mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
commit
b51d5aed5d
@ -1540,6 +1540,14 @@ pref("browser.tabs.remote.warmup.enabled", true);
|
||||
pref("browser.tabs.remote.warmup.enabled", false);
|
||||
#endif
|
||||
|
||||
// Caches tab layers to improve perceived performance
|
||||
// of tab switches.
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
pref("browser.tabs.remote.tabCacheSize", 5);
|
||||
#else
|
||||
pref("browser.tabs.remote.tabCacheSize", 0);
|
||||
#endif
|
||||
|
||||
pref("browser.tabs.remote.warmup.maxTabs", 3);
|
||||
pref("browser.tabs.remote.warmup.unloadDelayMs", 2000);
|
||||
|
||||
|
@ -195,6 +195,12 @@ We use a few tricks and optimizations to help improve the perceived performance
|
||||
|
||||
4. On platforms that support ``occlusionstatechange`` events (as of this writing, only macOS) and ``sizemodechange`` events (Windows, macOS and Linux), we stop rendering the layers for the currently selected tab when the window is minimized or fully occluded by another window.
|
||||
|
||||
5. Based on the browser.tabs.remote.tabCacheSize pref, we keep recently used tabs'
|
||||
layers around to speed up tab switches by avoiding the round trip to the content
|
||||
process. This uses a simple array (``_tabLayerCache``) inside tabbrowser.js, which
|
||||
we examine when determining if we want to unload a tab's layers or not. This is still
|
||||
experimental as of Nightly 62.
|
||||
|
||||
.. _async-tab-switcher.warming:
|
||||
|
||||
Warming
|
||||
|
@ -97,6 +97,8 @@ window._gBrowser = {
|
||||
|
||||
_contentWaitingCount: 0,
|
||||
|
||||
_tabLayerCache: [],
|
||||
|
||||
tabAnimationsInProgress: 0,
|
||||
|
||||
_XUL_NS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
||||
@ -2329,6 +2331,9 @@ window._gBrowser = {
|
||||
lastRelatedTab.owner = null;
|
||||
} else if (openerTab) {
|
||||
t.owner = openerTab;
|
||||
}
|
||||
// Always set related map if opener exists.
|
||||
if (openerTab) {
|
||||
this._lastRelatedTabMap.set(openerTab, t);
|
||||
}
|
||||
} else {
|
||||
@ -2336,8 +2341,11 @@ window._gBrowser = {
|
||||
aIndex = this.tabs.length;
|
||||
}
|
||||
}
|
||||
// Ensure position respectes tab pinned state.
|
||||
if (aPinned) {
|
||||
aIndex = Math.min(aIndex, this._numPinnedTabs);
|
||||
} else {
|
||||
aIndex = Math.max(aIndex, this._numPinnedTabs);
|
||||
}
|
||||
|
||||
// use .item() instead of [] because dragging to the end of the strip goes out of
|
||||
@ -2750,6 +2758,13 @@ window._gBrowser = {
|
||||
}
|
||||
}
|
||||
|
||||
// this._switcher would normally cover removing a tab from this
|
||||
// cache, but we may not have one at this time.
|
||||
let tabCacheIndex = this._tabLayerCache.indexOf(aTab);
|
||||
if (tabCacheIndex != -1) {
|
||||
this._tabLayerCache.splice(tabCacheIndex, 1);
|
||||
}
|
||||
|
||||
this._blurTab(aTab);
|
||||
|
||||
var closeWindow = false;
|
||||
|
@ -28,6 +28,7 @@ skip-if = !e10s # Pref and test only relevant for e10s.
|
||||
support-files = file_new_tab_page.html
|
||||
[browser_overflowScroll.js]
|
||||
[browser_pinnedTabs.js]
|
||||
[browser_pinnedTabs_clickOpen.js]
|
||||
[browser_pinnedTabs_closeByKeyboard.js]
|
||||
[browser_positional_attributes.js]
|
||||
[browser_preloadedBrowser_zoom.js]
|
||||
|
@ -0,0 +1,47 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
function index(tab) {
|
||||
return Array.indexOf(gBrowser.tabs, tab);
|
||||
}
|
||||
|
||||
async function testNewTabPosition(expectedPosition, modifiers = {}) {
|
||||
let opening = BrowserTestUtils.waitForNewTab(gBrowser, "http://mochi.test:8888/");
|
||||
BrowserTestUtils.synthesizeMouseAtCenter("#link", modifiers, gBrowser.selectedBrowser);
|
||||
let newtab = await opening;
|
||||
is(index(newtab), expectedPosition, "clicked tab is in correct position");
|
||||
return newtab;
|
||||
}
|
||||
|
||||
// Test that a tab opened from a pinned tab is not in the pinned region.
|
||||
add_task(async function test_pinned_content_click() {
|
||||
let testUri = "data:text/html;charset=utf-8,<a href=\"http://mochi.test:8888/\" target=\"_blank\" id=\"link\">link</a>";
|
||||
let tabs = [gBrowser.selectedTab, BrowserTestUtils.addTab(gBrowser, testUri), BrowserTestUtils.addTab(gBrowser)];
|
||||
gBrowser.pinTab(tabs[1]);
|
||||
gBrowser.pinTab(tabs[2]);
|
||||
|
||||
// First test new active tabs open at the start of non-pinned tabstrip.
|
||||
await BrowserTestUtils.switchTab(gBrowser, tabs[1]);
|
||||
let newtab1 = await testNewTabPosition(2);
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, tabs[1]);
|
||||
let newtab2 = await testNewTabPosition(2);
|
||||
|
||||
gBrowser.removeTab(newtab1);
|
||||
gBrowser.removeTab(newtab2);
|
||||
|
||||
// Second test new background tabs open in order.
|
||||
let modifiers = AppConstants.platform == "macosx" ? {metaKey: true} : {ctrlKey: true};
|
||||
await BrowserTestUtils.switchTab(gBrowser, tabs[1]);
|
||||
|
||||
newtab1 = await testNewTabPosition(2, modifiers);
|
||||
newtab2 = await testNewTabPosition(3, modifiers);
|
||||
|
||||
gBrowser.removeTab(tabs[1]);
|
||||
gBrowser.removeTab(tabs[2]);
|
||||
gBrowser.removeTab(newtab1);
|
||||
gBrowser.removeTab(newtab2);
|
||||
});
|
@ -110,6 +110,15 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
|
||||
});
|
||||
}
|
||||
|
||||
_getAdditionalDisplayItems(state) {
|
||||
let methodId = state.selectedPaymentCard;
|
||||
let modifier = paymentRequest.getModifierForPaymentMethod(state, methodId);
|
||||
if (modifier && modifier.additionalDisplayItems) {
|
||||
return modifier.additionalDisplayItems;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set some state from the privileged parent process.
|
||||
* Other elements that need to set state should use their own `this.requestStore.setState`
|
||||
@ -236,6 +245,10 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
|
||||
let paymentDetails = request.paymentDetails;
|
||||
this._hostNameEl.textContent = request.topLevelPrincipal.URI.displayHost;
|
||||
|
||||
let displayItems = request.paymentDetails.displayItems || [];
|
||||
let additionalItems = this._getAdditionalDisplayItems(state);
|
||||
this._viewAllButton.hidden = !displayItems.length && !additionalItems.length;
|
||||
|
||||
let shippingType = state.request.paymentOptions.shippingType || "shipping";
|
||||
this._shippingAddressPicker.dataset.addAddressTitle =
|
||||
this.dataset[shippingType + "AddressTitleAdd"];
|
||||
|
@ -89,6 +89,31 @@ add_task(async function test_initialState() {
|
||||
is(initialState.page.id, "payment-summary", "Check initial page");
|
||||
});
|
||||
|
||||
add_task(async function test_viewAllButtonVisibility() {
|
||||
await setup();
|
||||
|
||||
let button = el1._viewAllButton;
|
||||
ok(button.hidden, "Button is initially hidden when there are no items to show");
|
||||
|
||||
// Add a display item.
|
||||
let request = deepClone(el1.requestStore.getState().request);
|
||||
request.paymentDetails.displayItems = [
|
||||
{
|
||||
"label": "Triangle",
|
||||
"amount": {
|
||||
"currency": "CAD",
|
||||
"value": "3",
|
||||
},
|
||||
},
|
||||
];
|
||||
await el1.requestStore.setState({ request });
|
||||
await asyncElementRendered();
|
||||
|
||||
// Check if the "View all items" button is visible.
|
||||
ok(!button.hidden, "Button is visible");
|
||||
});
|
||||
|
||||
|
||||
add_task(async function test_viewAllButton() {
|
||||
await setup();
|
||||
|
||||
|
@ -20,6 +20,8 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingMax",
|
||||
"browser.tabs.remote.warmup.maxTabs");
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingUnloadDelayMs",
|
||||
"browser.tabs.remote.warmup.unloadDelayMs");
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gTabCacheSize",
|
||||
"browser.tabs.remote.tabCacheSize");
|
||||
|
||||
/**
|
||||
* The tab switcher is responsible for asynchronously switching
|
||||
@ -291,6 +293,10 @@ class AsyncTabSwitcher {
|
||||
this.window.isFullyOccluded;
|
||||
}
|
||||
|
||||
get tabLayerCache() {
|
||||
return this.tabbrowser._tabLayerCache;
|
||||
}
|
||||
|
||||
finish() {
|
||||
this.log("FINISH");
|
||||
|
||||
@ -508,6 +514,15 @@ class AsyncTabSwitcher {
|
||||
this.assert(this.tabbrowser._switcher);
|
||||
this.assert(this.tabbrowser._switcher === this);
|
||||
|
||||
for (let i = 0; i < this.tabLayerCache.length; i++) {
|
||||
let tab = this.tabLayerCache[i];
|
||||
if (!tab.linkedBrowser) {
|
||||
this.tabState.delete(tab);
|
||||
this.tabLayerCache.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
for (let [tab, ] of this.tabState) {
|
||||
if (!tab.linkedBrowser) {
|
||||
this.tabState.delete(tab);
|
||||
@ -566,6 +581,13 @@ class AsyncTabSwitcher {
|
||||
this.loadRequestedTab();
|
||||
}
|
||||
|
||||
let numBackgroundCached = 0;
|
||||
for (let tab of this.tabLayerCache) {
|
||||
if (tab !== this.requestedTab) {
|
||||
numBackgroundCached++;
|
||||
}
|
||||
}
|
||||
|
||||
// See how many tabs still have work to do.
|
||||
let numPending = 0;
|
||||
let numWarming = 0;
|
||||
@ -575,7 +597,9 @@ class AsyncTabSwitcher {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state == this.STATE_LOADED && tab !== this.requestedTab) {
|
||||
if (state == this.STATE_LOADED &&
|
||||
tab !== this.requestedTab &&
|
||||
!this.tabLayerCache.includes(tab)) {
|
||||
numPending++;
|
||||
|
||||
if (tab !== this.visibleTab) {
|
||||
@ -598,8 +622,10 @@ class AsyncTabSwitcher {
|
||||
|
||||
this.maybeFinishTabSwitch();
|
||||
|
||||
if (numWarming > gTabWarmingMax) {
|
||||
this.logState("Hit tabWarmingMax");
|
||||
if (numWarming > gTabWarmingMax || numBackgroundCached > 0) {
|
||||
if (numWarming > gTabWarmingMax) {
|
||||
this.logState("Hit tabWarmingMax");
|
||||
}
|
||||
if (this.unloadTimer) {
|
||||
this.clearTimer(this.unloadTimer);
|
||||
}
|
||||
@ -632,21 +658,34 @@ class AsyncTabSwitcher {
|
||||
this.warmingTabs = new WeakSet();
|
||||
let numPending = 0;
|
||||
|
||||
for (let tab of this.tabLayerCache) {
|
||||
if (tab !== this.requestedTab) {
|
||||
let browser = tab.linkedBrowser;
|
||||
browser.preserveLayers(true);
|
||||
browser.docShellIsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Unload any tabs that can be unloaded.
|
||||
for (let [tab, state] of this.tabState) {
|
||||
if (this.tabbrowser._printPreviewBrowsers.has(tab.linkedBrowser)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let isInLayerCache = this.tabLayerCache.includes(tab);
|
||||
|
||||
if (state == this.STATE_LOADED &&
|
||||
!this.maybeVisibleTabs.has(tab) &&
|
||||
tab !== this.lastVisibleTab &&
|
||||
tab !== this.loadingTab &&
|
||||
tab !== this.requestedTab) {
|
||||
tab !== this.requestedTab &&
|
||||
!isInLayerCache) {
|
||||
this.setTabState(tab, this.STATE_UNLOADING);
|
||||
}
|
||||
|
||||
if (state != this.STATE_UNLOADED && tab !== this.requestedTab) {
|
||||
if (state != this.STATE_UNLOADED &&
|
||||
tab !== this.requestedTab &&
|
||||
!isInLayerCache) {
|
||||
numPending++;
|
||||
}
|
||||
}
|
||||
@ -870,17 +909,49 @@ class AsyncTabSwitcher {
|
||||
this.queueUnload(gTabWarmingUnloadDelayMs);
|
||||
}
|
||||
|
||||
cleanUpTabAfterEviction(tab) {
|
||||
this.assert(tab !== this.requestedTab);
|
||||
let browser = tab.linkedBrowser;
|
||||
if (browser) {
|
||||
browser.preserveLayers(false);
|
||||
}
|
||||
this.setTabState(tab, this.STATE_UNLOADING);
|
||||
}
|
||||
|
||||
evictOldestTabFromCache() {
|
||||
let tab = this.tabLayerCache.shift();
|
||||
this.cleanUpTabAfterEviction(tab);
|
||||
}
|
||||
|
||||
maybePromoteTabInLayerCache(tab) {
|
||||
if (gTabCacheSize > 1 &&
|
||||
tab.linkedBrowser.isRemoteBrowser &&
|
||||
tab.linkedBrowser.currentURI.spec != "about:blank") {
|
||||
let tabIndex = this.tabLayerCache.indexOf(tab);
|
||||
|
||||
if (tabIndex != -1) {
|
||||
this.tabLayerCache.splice(tabIndex, 1);
|
||||
}
|
||||
|
||||
this.tabLayerCache.push(tab);
|
||||
|
||||
if (this.tabLayerCache.length > gTabCacheSize) {
|
||||
this.evictOldestTabFromCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the user asks to switch to a given tab.
|
||||
requestTab(tab) {
|
||||
if (tab === this.requestedTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tabState = this.getTabState(tab);
|
||||
if (gTabWarmingEnabled) {
|
||||
let warmingState = "disqualified";
|
||||
|
||||
if (this.canWarmTab(tab)) {
|
||||
let tabState = this.getTabState(tab);
|
||||
if (tabState == this.STATE_LOADING) {
|
||||
warmingState = "stillLoading";
|
||||
} else if (tabState == this.STATE_LOADED) {
|
||||
@ -906,6 +977,9 @@ class AsyncTabSwitcher {
|
||||
this.startTabSwitch();
|
||||
|
||||
this.requestedTab = tab;
|
||||
if (tabState == this.STATE_LOADED) {
|
||||
this.maybeVisibleTabs.clear();
|
||||
}
|
||||
|
||||
tab.linkedBrowser.setAttribute("primary", "true");
|
||||
if (this.lastPrimaryTab && this.lastPrimaryTab != tab) {
|
||||
@ -992,6 +1066,10 @@ class AsyncTabSwitcher {
|
||||
if (this.switchInProgress && this.requestedTab &&
|
||||
(this.getTabState(this.requestedTab) == this.STATE_LOADED ||
|
||||
this.requestedTab === this.blankTab)) {
|
||||
if (this.requestedTab !== this.blankTab) {
|
||||
this.maybePromoteTabInLayerCache(this.requestedTab);
|
||||
}
|
||||
|
||||
// After this point the tab has switched from the content thread's point of view.
|
||||
// The changes will be visible after the next refresh driver tick + composite.
|
||||
let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_TOTAL_E10S_MS", this.window);
|
||||
@ -1078,19 +1156,37 @@ class AsyncTabSwitcher {
|
||||
let tab = this.tabbrowser.tabs[i];
|
||||
let state = this.getTabState(tab);
|
||||
let isWarming = this.warmingTabs.has(tab);
|
||||
let isCached = this.tabLayerCache.includes(tab);
|
||||
let isClosing = tab.closing;
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
let isActive = linkedBrowser && linkedBrowser.docShellIsActive;
|
||||
let isRendered = linkedBrowser && linkedBrowser.renderLayers;
|
||||
|
||||
accum += i + ":";
|
||||
if (tab === this.lastVisibleTab) accum += "V";
|
||||
if (tab === this.loadingTab) accum += "L";
|
||||
if (tab === this.requestedTab) accum += "R";
|
||||
if (tab === this.blankTab) accum += "B";
|
||||
if (isWarming) accum += "(W)";
|
||||
|
||||
let extraStates = "";
|
||||
if (isWarming) extraStates += "W";
|
||||
if (isCached) extraStates += "C";
|
||||
if (isClosing) extraStates += "X";
|
||||
if (isActive) extraStates += "A";
|
||||
if (isRendered) extraStates += "R";
|
||||
if (extraStates != "") {
|
||||
accum += `(${extraStates})`;
|
||||
}
|
||||
|
||||
if (state == this.STATE_LOADED) accum += "(+)";
|
||||
if (state == this.STATE_LOADING) accum += "(+?)";
|
||||
if (state == this.STATE_UNLOADED) accum += "(-)";
|
||||
if (state == this.STATE_UNLOADING) accum += "(-?)";
|
||||
accum += " ";
|
||||
}
|
||||
|
||||
accum += "cached: " + this.tabLayerCache.length;
|
||||
|
||||
if (this._useDumpForLogging) {
|
||||
dump(accum + "\n");
|
||||
} else {
|
||||
|
@ -56,6 +56,8 @@ class ToolboxToolbar extends Component {
|
||||
disableAutohide: PropTypes.bool,
|
||||
// Function to select a tool based on its id.
|
||||
selectTool: PropTypes.func,
|
||||
// Function to turn the options panel on / off.
|
||||
toggleOptions: PropTypes.func.isRequired,
|
||||
// Function to turn the split console on / off.
|
||||
toggleSplitConsole: PropTypes.func,
|
||||
// Function to turn the disable pop-up autohide behavior on / off.
|
||||
@ -234,6 +236,8 @@ function renderSeparator() {
|
||||
* (Only defined for the browser toolbox.)
|
||||
* @param {Function} selectTool
|
||||
* Function to select a tool based on its id.
|
||||
* @param {Function} toggleOptions
|
||||
* Function to turn the options panel on / off.
|
||||
* @param {Function} toggleSplitConsole
|
||||
* Function to turn the split console on / off.
|
||||
* @param {Function} toggleNoAutohide
|
||||
@ -319,8 +323,10 @@ function renderToolboxControls(props) {
|
||||
* Are we disabling the behavior where pop-ups are automatically
|
||||
* closed when clicking outside them.
|
||||
* (Only defined for the browser toolbox.)
|
||||
* @param {Function} props.selectTool
|
||||
* @param {Function} selectTool
|
||||
* Function to select a tool based on its id.
|
||||
* @param {Function} toggleOptions
|
||||
* Function to turn the options panel on / off.
|
||||
* @param {Function} toggleSplitConsole
|
||||
* Function to turn the split console on / off.
|
||||
* @param {Function} toggleNoAutohide
|
||||
@ -339,7 +345,7 @@ function showMeatballMenu(
|
||||
currentHostType,
|
||||
isSplitConsoleActive,
|
||||
disableAutohide,
|
||||
selectTool,
|
||||
toggleOptions,
|
||||
toggleSplitConsole,
|
||||
toggleNoAutohide,
|
||||
L10N,
|
||||
@ -402,7 +408,7 @@ function showMeatballMenu(
|
||||
id: "toolbox-meatball-menu-settings",
|
||||
label: L10N.getStr("toolbox.meatballMenu.settings.label"),
|
||||
accelerator: L10N.getStr("toolbox.help.key"),
|
||||
click: () => selectTool("options"),
|
||||
click: () => toggleOptions(),
|
||||
}));
|
||||
|
||||
if (menu.items.length) {
|
||||
|
@ -91,6 +91,7 @@ skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keybo
|
||||
[browser_toolbox_options_disable_js.js]
|
||||
[browser_toolbox_options_enable_serviceworkers_testing.js]
|
||||
[browser_toolbox_options_frames_button.js]
|
||||
[browser_toolbox_options_panel_toggle.js]
|
||||
[browser_toolbox_raise.js]
|
||||
disabled=Bug 962258
|
||||
[browser_toolbox_races.js]
|
||||
|
@ -0,0 +1,57 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test whether options panel toggled by key event and "Settings" on the meatball menu.
|
||||
|
||||
const { Toolbox } = require("devtools/client/framework/toolbox");
|
||||
|
||||
add_task(async function() {
|
||||
const tab = await addTab("about:blank");
|
||||
const toolbox = await openToolboxForTab(tab, "webconsole", Toolbox.HostType.BOTTOM);
|
||||
|
||||
info("Check the option panel was selected after sending F1 key event");
|
||||
await sendOptionsKeyEvent(toolbox);
|
||||
is(toolbox.currentToolId, "options", "The options panel should be selected");
|
||||
|
||||
info("Check the last selected panel was selected after sending F1 key event");
|
||||
await sendOptionsKeyEvent(toolbox);
|
||||
is(toolbox.currentToolId, "webconsole", "The webconsole panel should be selected");
|
||||
|
||||
info("Check the option panel was selected after clicking 'Settings' menu");
|
||||
await clickSettingsMenu(toolbox);
|
||||
is(toolbox.currentToolId, "options", "The options panel should be selected");
|
||||
|
||||
info("Check the last selected panel was selected after clicking 'Settings' menu");
|
||||
await sendOptionsKeyEvent(toolbox);
|
||||
is(toolbox.currentToolId, "webconsole", "The webconsole panel should be selected");
|
||||
|
||||
info("Check the combination of key event and 'Settings' menu");
|
||||
await sendOptionsKeyEvent(toolbox);
|
||||
await clickSettingsMenu(toolbox);
|
||||
is(toolbox.currentToolId, "webconsole", "The webconsole panel should be selected");
|
||||
await clickSettingsMenu(toolbox);
|
||||
await sendOptionsKeyEvent(toolbox);
|
||||
is(toolbox.currentToolId, "webconsole", "The webconsole panel should be selected");
|
||||
});
|
||||
|
||||
async function sendOptionsKeyEvent(toolbox) {
|
||||
const onReady = toolbox.once("select");
|
||||
EventUtils.synthesizeKey("VK_F1", {}, toolbox.win);
|
||||
await onReady;
|
||||
}
|
||||
|
||||
async function clickSettingsMenu(toolbox) {
|
||||
const onPopupShown = () => {
|
||||
toolbox.doc.removeEventListener("popuphidden", onPopupShown);
|
||||
const menuItem = toolbox.doc.getElementById("toolbox-meatball-menu-settings");
|
||||
EventUtils.synthesizeMouseAtCenter(menuItem, {}, menuItem.ownerGlobal);
|
||||
};
|
||||
toolbox.doc.addEventListener("popupshown", onPopupShown);
|
||||
|
||||
const button = toolbox.doc.getElementById("toolbox-meatball-menu-button");
|
||||
EventUtils.synthesizeMouseAtCenter(button, {}, button.ownerGlobal);
|
||||
|
||||
await toolbox.once("select");
|
||||
}
|
@ -164,6 +164,7 @@ function Toolbox(target, selectedTool, hostType, contentWindow, frameId) {
|
||||
this.selectTool = this.selectTool.bind(this);
|
||||
this._pingTelemetrySelectTool = this._pingTelemetrySelectTool.bind(this);
|
||||
this.toggleSplitConsole = this.toggleSplitConsole.bind(this);
|
||||
this.toggleOptions = this.toggleOptions.bind(this);
|
||||
|
||||
this._target.on("close", this.destroy);
|
||||
|
||||
@ -840,17 +841,7 @@ Toolbox.prototype = {
|
||||
},
|
||||
|
||||
_buildOptions: function() {
|
||||
let selectOptions = event => {
|
||||
// Flip back to the last used panel if we are already
|
||||
// on the options panel.
|
||||
if (this.currentToolId === "options" &&
|
||||
gDevTools.getToolDefinition(this.lastUsedToolId)) {
|
||||
this.selectTool(this.lastUsedToolId, "toggle_settings_off");
|
||||
} else {
|
||||
this.selectTool("options", "toggle_settings_on");
|
||||
}
|
||||
};
|
||||
this.shortcuts.on(L10N.getStr("toolbox.help.key"), selectOptions);
|
||||
this.shortcuts.on(L10N.getStr("toolbox.help.key"), this.toggleOptions);
|
||||
},
|
||||
|
||||
_splitConsoleOnKeypress: function(e) {
|
||||
@ -1144,6 +1135,7 @@ Toolbox.prototype = {
|
||||
L10N,
|
||||
currentToolId: this.currentToolId,
|
||||
selectTool: this.selectTool,
|
||||
toggleOptions: this.toggleOptions,
|
||||
toggleSplitConsole: this.toggleSplitConsole,
|
||||
toggleNoAutohide: this.toggleNoAutohide,
|
||||
closeToolbox: this.destroy,
|
||||
@ -2047,6 +2039,21 @@ Toolbox.prototype = {
|
||||
return promise.resolve();
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the options panel.
|
||||
* If the option panel is already selected then select the last selected panel.
|
||||
*/
|
||||
toggleOptions: function() {
|
||||
// Flip back to the last used panel if we are already
|
||||
// on the options panel.
|
||||
if (this.currentToolId === "options" &&
|
||||
gDevTools.getToolDefinition(this.lastUsedToolId)) {
|
||||
this.selectTool(this.lastUsedToolId, "toggle_settings_off");
|
||||
} else {
|
||||
this.selectTool("options", "toggle_settings_on");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Tells the target tab to reload.
|
||||
*/
|
||||
|
@ -90,7 +90,7 @@ ProgressGraphHelper.prototype = {
|
||||
* @return {Number} duration
|
||||
*/
|
||||
getDuration: function() {
|
||||
return this.animation.effect.timing.duration;
|
||||
return this.animation.effect.getComputedTiming().duration;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -435,7 +435,7 @@ SummaryGraphHelper.prototype = {
|
||||
* @param {String} fill - "both", "forwards", "backwards" or "both"
|
||||
*/
|
||||
setFillMode: function(fill) {
|
||||
this.animation.effect.timing.fill = fill;
|
||||
this.animation.effect.updateTiming({ fill });
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -3,8 +3,10 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<!DOCTYPE html>
|
||||
<html dir=""
|
||||
id="devtools-webconsole"
|
||||
windowtype="devtools:webconsole"
|
||||
width="900" height="350">
|
||||
width="900" height="350"
|
||||
persist="screenX screenY width height sizemode">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/widgets.css"/>
|
||||
|
@ -253,7 +253,7 @@ var AnimationPlayerActor = protocol.ActorClassWithSpec(animationPlayerSpec, {
|
||||
* @return {String}
|
||||
*/
|
||||
getEasing: function() {
|
||||
return this.player.effect.timing.easing;
|
||||
return this.player.effect.getComputedTiming().easing;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -3500,71 +3500,6 @@ nsDocShell::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DOCSHELL_FOCUS
|
||||
static void
|
||||
PrintDocTree(nsIDocShellTreeItem* aParentNode, int aLevel)
|
||||
{
|
||||
for (int32_t i = 0; i < aLevel; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
int32_t childWebshellCount;
|
||||
aParentNode->GetChildCount(&childWebshellCount);
|
||||
nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode));
|
||||
int32_t type = aParentNode->ItemType();
|
||||
nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell();
|
||||
RefPtr<nsPresContext> presContext;
|
||||
parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
|
||||
nsIDocument* doc = presShell->GetDocument();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> domwin(doc->GetWindow());
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
nsViewManager* vm = presShell->GetViewManager();
|
||||
if (vm) {
|
||||
vm->GetWidget(getter_AddRefs(widget));
|
||||
}
|
||||
dom::Element* rootElement = doc->GetRootElement();
|
||||
|
||||
printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n",
|
||||
(void*)parentAsDocShell.get(),
|
||||
type == nsIDocShellTreeItem::typeChrome ? "Chr" : "Con",
|
||||
(void*)doc, (void*)domwin.get(),
|
||||
(void*)presContext->EventStateManager(), (void*)rootElement);
|
||||
|
||||
if (childWebshellCount > 0) {
|
||||
for (int32_t i = 0; i < childWebshellCount; i++) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> child;
|
||||
aParentNode->GetChildAt(i, getter_AddRefs(child));
|
||||
PrintDocTree(child, aLevel + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
PrintDocTree(nsIDocShellTreeItem* aParentNode)
|
||||
{
|
||||
NS_ASSERTION(aParentNode, "Pointer is null!");
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentItem;
|
||||
aParentNode->GetParent(getter_AddRefs(parentItem));
|
||||
while (parentItem) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> tmp;
|
||||
parentItem->GetParent(getter_AddRefs(tmp));
|
||||
if (!tmp) {
|
||||
break;
|
||||
}
|
||||
parentItem = tmp;
|
||||
}
|
||||
|
||||
if (!parentItem) {
|
||||
parentItem = aParentNode;
|
||||
}
|
||||
|
||||
PrintDocTree(parentItem, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
|
||||
{
|
||||
@ -3572,13 +3507,6 @@ nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DOCSHELL_FOCUS
|
||||
nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner));
|
||||
if (item) {
|
||||
PrintDocTree(item);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Don't automatically set the progress based on the tree owner for frames
|
||||
if (!IsFrame()) {
|
||||
nsCOMPtr<nsIWebProgress> webProgress =
|
||||
|
@ -88,7 +88,7 @@ namespace {
|
||||
// ---------------------------------------------------------------------------
|
||||
/* static */ already_AddRefed<Animation>
|
||||
Animation::Constructor(const GlobalObject& aGlobal,
|
||||
AnimationEffectReadOnly* aEffect,
|
||||
AnimationEffect* aEffect,
|
||||
const Optional<AnimationTimeline*>& aTimeline,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -125,7 +125,7 @@ Animation::SetId(const nsAString& aId)
|
||||
}
|
||||
|
||||
void
|
||||
Animation::SetEffect(AnimationEffectReadOnly* aEffect)
|
||||
Animation::SetEffect(AnimationEffect* aEffect)
|
||||
{
|
||||
SetEffectNoUpdate(aEffect);
|
||||
PostUpdate();
|
||||
@ -133,7 +133,7 @@ Animation::SetEffect(AnimationEffectReadOnly* aEffect)
|
||||
|
||||
// https://drafts.csswg.org/web-animations/#setting-the-target-effect
|
||||
void
|
||||
Animation::SetEffectNoUpdate(AnimationEffectReadOnly* aEffect)
|
||||
Animation::SetEffectNoUpdate(AnimationEffect* aEffect)
|
||||
{
|
||||
RefPtr<Animation> kungFuDeathGrip(this);
|
||||
|
||||
@ -159,7 +159,7 @@ Animation::SetEffectNoUpdate(AnimationEffectReadOnly* aEffect)
|
||||
}
|
||||
|
||||
// Break links with the old effect and then drop it.
|
||||
RefPtr<AnimationEffectReadOnly> oldEffect = mEffect;
|
||||
RefPtr<AnimationEffect> oldEffect = mEffect;
|
||||
mEffect = nullptr;
|
||||
oldEffect->SetAnimation(nullptr);
|
||||
|
||||
@ -169,7 +169,7 @@ Animation::SetEffectNoUpdate(AnimationEffectReadOnly* aEffect)
|
||||
|
||||
if (aEffect) {
|
||||
// Break links from the new effect to its previous animation, if any.
|
||||
RefPtr<AnimationEffectReadOnly> newEffect = aEffect;
|
||||
RefPtr<AnimationEffect> newEffect = aEffect;
|
||||
Animation* prevAnim = aEffect->GetAnimation();
|
||||
if (prevAnim) {
|
||||
prevAnim->SetEffect(nullptr);
|
||||
@ -703,7 +703,7 @@ Animation::Tick()
|
||||
}
|
||||
|
||||
// Update layers if we are newly finished.
|
||||
KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
KeyframeEffect* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
if (keyframeEffect &&
|
||||
!keyframeEffect->Properties().IsEmpty() &&
|
||||
!mFinishedAtLastComposeStyle &&
|
||||
@ -908,9 +908,9 @@ Animation::ShouldBeSynchronizedWithMainThread(
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyframeEffectReadOnly* keyframeEffect = mEffect
|
||||
? mEffect->AsKeyframeEffect()
|
||||
: nullptr;
|
||||
KeyframeEffect* keyframeEffect = mEffect
|
||||
? mEffect->AsKeyframeEffect()
|
||||
: nullptr;
|
||||
if (!keyframeEffect) {
|
||||
return false;
|
||||
}
|
||||
@ -1020,7 +1020,7 @@ Animation::WillComposeStyle()
|
||||
|
||||
MOZ_ASSERT(mEffect);
|
||||
|
||||
KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
KeyframeEffect* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
if (keyframeEffect) {
|
||||
keyframeEffect->WillComposeStyle();
|
||||
}
|
||||
@ -1085,7 +1085,7 @@ Animation::ComposeStyle(RawServoAnimationValueMap& aComposeResult,
|
||||
}
|
||||
}
|
||||
|
||||
KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
KeyframeEffect* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
if (keyframeEffect) {
|
||||
keyframeEffect->ComposeStyle(aComposeResult, aPropertiesToSkip);
|
||||
}
|
||||
@ -1410,7 +1410,7 @@ Animation::UpdateEffect()
|
||||
if (mEffect) {
|
||||
UpdateRelevance();
|
||||
|
||||
KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
KeyframeEffect* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
if (keyframeEffect) {
|
||||
keyframeEffect->NotifyAnimationTimingUpdated();
|
||||
}
|
||||
@ -1434,7 +1434,7 @@ Animation::PostUpdate()
|
||||
return;
|
||||
}
|
||||
|
||||
KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
KeyframeEffect* keyframeEffect = mEffect->AsKeyframeEffect();
|
||||
if (!keyframeEffect) {
|
||||
return;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
|
||||
#include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState
|
||||
#include "mozilla/dom/AnimationEffectReadOnly.h"
|
||||
#include "mozilla/dom/AnimationEffect.h"
|
||||
#include "mozilla/dom/AnimationTimeline.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
@ -96,13 +96,13 @@ public:
|
||||
// Animation interface methods
|
||||
static already_AddRefed<Animation>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
AnimationEffectReadOnly* aEffect,
|
||||
AnimationEffect* aEffect,
|
||||
const Optional<AnimationTimeline*>& aTimeline,
|
||||
ErrorResult& aRv);
|
||||
void GetId(nsAString& aResult) const { aResult = mId; }
|
||||
void SetId(const nsAString& aId);
|
||||
AnimationEffectReadOnly* GetEffect() const { return mEffect; }
|
||||
void SetEffect(AnimationEffectReadOnly* aEffect);
|
||||
AnimationEffect* GetEffect() const { return mEffect; }
|
||||
void SetEffect(AnimationEffect* aEffect);
|
||||
AnimationTimeline* GetTimeline() const { return mTimeline; }
|
||||
void SetTimeline(AnimationTimeline* aTimeline);
|
||||
Nullable<TimeDuration> GetStartTime() const { return mStartTime; }
|
||||
@ -155,7 +155,7 @@ public:
|
||||
|
||||
virtual void CancelFromStyle() { CancelNoUpdate(); }
|
||||
void SetTimelineNoUpdate(AnimationTimeline* aTimeline);
|
||||
void SetEffectNoUpdate(AnimationEffectReadOnly* aEffect);
|
||||
void SetEffectNoUpdate(AnimationEffect* aEffect);
|
||||
|
||||
virtual void Tick();
|
||||
bool NeedsTicks() const
|
||||
@ -363,7 +363,7 @@ public:
|
||||
/**
|
||||
* Updates various bits of state that we need to update as the result of
|
||||
* running ComposeStyle().
|
||||
* See the comment of KeyframeEffectReadOnly::WillComposeStyle for more detail.
|
||||
* See the comment of KeyframeEffect::WillComposeStyle for more detail.
|
||||
*/
|
||||
void WillComposeStyle();
|
||||
|
||||
@ -488,7 +488,7 @@ protected:
|
||||
nsIDocument* GetRenderedDocument() const;
|
||||
|
||||
RefPtr<AnimationTimeline> mTimeline;
|
||||
RefPtr<AnimationEffectReadOnly> mEffect;
|
||||
RefPtr<AnimationEffect> mEffect;
|
||||
// The beginning of the delay period.
|
||||
Nullable<TimeDuration> mStartTime; // Timeline timescale
|
||||
Nullable<TimeDuration> mHoldTime; // Animation timescale
|
||||
|
@ -4,51 +4,40 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/AnimationEffectReadOnly.h"
|
||||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h"
|
||||
#include "mozilla/dom/AnimationEffect.h"
|
||||
#include "mozilla/dom/AnimationEffectBinding.h"
|
||||
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/AnimationUtils.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(AnimationEffectReadOnly)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AnimationEffectReadOnly)
|
||||
if (tmp->mTiming) {
|
||||
tmp->mTiming->Unlink();
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument, mTiming, mAnimation)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(AnimationEffect)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AnimationEffect)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument, mAnimation)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationEffectReadOnly)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument, mTiming, mAnimation)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationEffect)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument, mAnimation)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AnimationEffectReadOnly)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AnimationEffect)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationEffectReadOnly)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationEffectReadOnly)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationEffect)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationEffect)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationEffectReadOnly)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationEffect)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
AnimationEffectReadOnly::AnimationEffectReadOnly(
|
||||
nsIDocument* aDocument, AnimationEffectTimingReadOnly* aTiming)
|
||||
: mDocument(aDocument)
|
||||
, mTiming(aTiming)
|
||||
{
|
||||
MOZ_ASSERT(aTiming);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/web-animations/#current
|
||||
bool
|
||||
AnimationEffectReadOnly::IsCurrent() const
|
||||
AnimationEffect::IsCurrent() const
|
||||
{
|
||||
if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
|
||||
return false;
|
||||
@ -61,39 +50,44 @@ AnimationEffectReadOnly::IsCurrent() const
|
||||
|
||||
// https://drafts.csswg.org/web-animations/#in-effect
|
||||
bool
|
||||
AnimationEffectReadOnly::IsInEffect() const
|
||||
AnimationEffect::IsInEffect() const
|
||||
{
|
||||
ComputedTiming computedTiming = GetComputedTiming();
|
||||
return !computedTiming.mProgress.IsNull();
|
||||
}
|
||||
|
||||
already_AddRefed<AnimationEffectTimingReadOnly>
|
||||
AnimationEffectReadOnly::Timing()
|
||||
{
|
||||
RefPtr<AnimationEffectTimingReadOnly> temp(mTiming);
|
||||
return temp.forget();
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectReadOnly::SetSpecifiedTiming(const TimingParams& aTiming)
|
||||
AnimationEffect::SetSpecifiedTiming(const TimingParams& aTiming)
|
||||
{
|
||||
if (mTiming->AsTimingParams() == aTiming) {
|
||||
if (mTiming == aTiming) {
|
||||
return;
|
||||
}
|
||||
mTiming->SetTimingParams(aTiming);
|
||||
|
||||
mTiming = aTiming;
|
||||
|
||||
if (mAnimation) {
|
||||
Maybe<nsAutoAnimationMutationBatch> mb;
|
||||
if (AsKeyframeEffect() && AsKeyframeEffect()->GetTarget()) {
|
||||
mb.emplace(AsKeyframeEffect()->GetTarget()->mElement->OwnerDoc());
|
||||
}
|
||||
|
||||
mAnimation->NotifyEffectTimingUpdated();
|
||||
|
||||
if (mAnimation->IsRelevant()) {
|
||||
nsNodeUtils::AnimationChanged(mAnimation);
|
||||
}
|
||||
|
||||
if (AsKeyframeEffect()) {
|
||||
AsKeyframeEffect()->RequestRestyle(EffectCompositor::RestyleType::Layer);
|
||||
}
|
||||
}
|
||||
// For keyframe effects, NotifyEffectTimingUpdated above will eventually cause
|
||||
// KeyframeEffectReadOnly::NotifyAnimationTimingUpdated to be called so it can
|
||||
// KeyframeEffect::NotifyAnimationTimingUpdated to be called so it can
|
||||
// update its registration with the target element as necessary.
|
||||
}
|
||||
|
||||
ComputedTiming
|
||||
AnimationEffectReadOnly::GetComputedTimingAt(
|
||||
AnimationEffect::GetComputedTimingAt(
|
||||
const Nullable<TimeDuration>& aLocalTime,
|
||||
const TimingParams& aTiming,
|
||||
double aPlaybackRate)
|
||||
@ -265,7 +259,7 @@ AnimationEffectReadOnly::GetComputedTimingAt(
|
||||
}
|
||||
|
||||
ComputedTiming
|
||||
AnimationEffectReadOnly::GetComputedTiming(const TimingParams* aTiming) const
|
||||
AnimationEffect::GetComputedTiming(const TimingParams* aTiming) const
|
||||
{
|
||||
double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1;
|
||||
return GetComputedTimingAt(GetLocalTime(),
|
||||
@ -273,68 +267,77 @@ AnimationEffectReadOnly::GetComputedTiming(const TimingParams* aTiming) const
|
||||
playbackRate);
|
||||
}
|
||||
|
||||
// Helper functions for generating a ComputedTimingProperties dictionary
|
||||
// Helper function for generating an (Computed)EffectTiming dictionary
|
||||
static void
|
||||
GetComputedTimingDictionary(const ComputedTiming& aComputedTiming,
|
||||
const Nullable<TimeDuration>& aLocalTime,
|
||||
const TimingParams& aTiming,
|
||||
ComputedTimingProperties& aRetVal)
|
||||
GetEffectTimingDictionary(const TimingParams& aTiming, EffectTiming& aRetVal)
|
||||
{
|
||||
// AnimationEffectTimingProperties
|
||||
aRetVal.mDelay = aTiming.Delay().ToMilliseconds();
|
||||
aRetVal.mEndDelay = aTiming.EndDelay().ToMilliseconds();
|
||||
aRetVal.mFill = aComputedTiming.mFill;
|
||||
aRetVal.mIterationStart = aComputedTiming.mIterationStart;
|
||||
aRetVal.mIterations = aComputedTiming.mIterations;
|
||||
aRetVal.mDuration.SetAsUnrestrictedDouble() =
|
||||
aComputedTiming.mDuration.ToMilliseconds();
|
||||
aRetVal.mFill = aTiming.Fill();
|
||||
aRetVal.mIterationStart = aTiming.IterationStart();
|
||||
aRetVal.mIterations = aTiming.Iterations();
|
||||
if (aTiming.Duration()) {
|
||||
aRetVal.mDuration.SetAsUnrestrictedDouble() =
|
||||
aTiming.Duration()->ToMilliseconds();
|
||||
}
|
||||
aRetVal.mDirection = aTiming.Direction();
|
||||
if (aTiming.TimingFunction()) {
|
||||
aRetVal.mEasing.Truncate();
|
||||
aTiming.TimingFunction()->AppendToString(aRetVal.mEasing);
|
||||
}
|
||||
}
|
||||
|
||||
// ComputedTimingProperties
|
||||
aRetVal.mActiveDuration = aComputedTiming.mActiveDuration.ToMilliseconds();
|
||||
aRetVal.mEndTime = aComputedTiming.mEndTime.ToMilliseconds();
|
||||
aRetVal.mLocalTime = AnimationUtils::TimeDurationToDouble(aLocalTime);
|
||||
aRetVal.mProgress = aComputedTiming.mProgress;
|
||||
void
|
||||
AnimationEffect::GetTiming(EffectTiming& aRetVal) const
|
||||
{
|
||||
GetEffectTimingDictionary(SpecifiedTiming(), aRetVal);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffect::GetComputedTimingAsDict(ComputedEffectTiming& aRetVal) const
|
||||
{
|
||||
// Specified timing
|
||||
GetEffectTimingDictionary(SpecifiedTiming(), aRetVal);
|
||||
|
||||
// Computed timing
|
||||
double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1;
|
||||
const Nullable<TimeDuration> currentTime = GetLocalTime();
|
||||
ComputedTiming computedTiming =
|
||||
GetComputedTimingAt(currentTime, SpecifiedTiming(), playbackRate);
|
||||
|
||||
aRetVal.mDuration.SetAsUnrestrictedDouble() =
|
||||
computedTiming.mDuration.ToMilliseconds();
|
||||
aRetVal.mFill = computedTiming.mFill;
|
||||
aRetVal.mActiveDuration = computedTiming.mActiveDuration.ToMilliseconds();
|
||||
aRetVal.mEndTime = computedTiming.mEndTime.ToMilliseconds();
|
||||
aRetVal.mLocalTime = AnimationUtils::TimeDurationToDouble(currentTime);
|
||||
aRetVal.mProgress = computedTiming.mProgress;
|
||||
|
||||
if (!aRetVal.mProgress.IsNull()) {
|
||||
// Convert the returned currentIteration into Infinity if we set
|
||||
// (uint64_t) aComputedTiming.mCurrentIteration to UINT64_MAX
|
||||
double iteration = aComputedTiming.mCurrentIteration == UINT64_MAX
|
||||
// (uint64_t) computedTiming.mCurrentIteration to UINT64_MAX
|
||||
double iteration = computedTiming.mCurrentIteration == UINT64_MAX
|
||||
? PositiveInfinity<double>()
|
||||
: static_cast<double>(aComputedTiming.mCurrentIteration);
|
||||
: static_cast<double>(computedTiming.mCurrentIteration);
|
||||
aRetVal.mCurrentIteration.SetValue(iteration);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectReadOnly::GetComputedTimingAsDict(
|
||||
ComputedTimingProperties& aRetVal) const
|
||||
AnimationEffect::UpdateTiming(const OptionalEffectTiming& aTiming,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1;
|
||||
const Nullable<TimeDuration> currentTime = GetLocalTime();
|
||||
GetComputedTimingDictionary(GetComputedTimingAt(currentTime,
|
||||
SpecifiedTiming(),
|
||||
playbackRate),
|
||||
currentTime,
|
||||
SpecifiedTiming(),
|
||||
aRetVal);
|
||||
}
|
||||
|
||||
AnimationEffectReadOnly::~AnimationEffectReadOnly()
|
||||
{
|
||||
// mTiming is cycle collected, so we have to do null check first even though
|
||||
// mTiming shouldn't be null during the lifetime of KeyframeEffect.
|
||||
if (mTiming) {
|
||||
mTiming->Unlink();
|
||||
TimingParams timing =
|
||||
TimingParams::MergeOptionalEffectTiming(mTiming, aTiming, mDocument, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetSpecifiedTiming(timing);
|
||||
}
|
||||
|
||||
Nullable<TimeDuration>
|
||||
AnimationEffectReadOnly::GetLocalTime() const
|
||||
AnimationEffect::GetLocalTime() const
|
||||
{
|
||||
// Since the *animation* start time is currently always zero, the local
|
||||
// time is equal to the parent time.
|
@ -4,11 +4,10 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_AnimationEffectReadOnly_h
|
||||
#define mozilla_dom_AnimationEffectReadOnly_h
|
||||
#ifndef mozilla_dom_AnimationEffect_h
|
||||
#define mozilla_dom_AnimationEffect_h
|
||||
|
||||
#include "mozilla/ComputedTiming.h"
|
||||
#include "mozilla/dom/AnimationEffectTimingReadOnly.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
@ -25,21 +24,23 @@ struct ElementPropertyTransition;
|
||||
namespace dom {
|
||||
|
||||
class Animation;
|
||||
class AnimationEffectTimingReadOnly;
|
||||
class KeyframeEffectReadOnly;
|
||||
struct ComputedTimingProperties;
|
||||
class KeyframeEffect;
|
||||
struct ComputedEffectTiming;
|
||||
|
||||
class AnimationEffectReadOnly : public nsISupports,
|
||||
public nsWrapperCache
|
||||
class AnimationEffect : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationEffectReadOnly)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationEffect)
|
||||
|
||||
AnimationEffectReadOnly(nsIDocument* aDocument,
|
||||
AnimationEffectTimingReadOnly* aTiming);
|
||||
AnimationEffect(nsIDocument* aDocument, const TimingParams& aTiming)
|
||||
: mDocument(aDocument)
|
||||
, mTiming(aTiming)
|
||||
{
|
||||
}
|
||||
|
||||
virtual KeyframeEffectReadOnly* AsKeyframeEffect() { return nullptr; }
|
||||
virtual KeyframeEffect* AsKeyframeEffect() { return nullptr; }
|
||||
|
||||
virtual ElementPropertyTransition* AsTransition() { return nullptr; }
|
||||
virtual const ElementPropertyTransition* AsTransition() const
|
||||
@ -56,11 +57,12 @@ public:
|
||||
return SpecifiedTiming().ActiveDuration() != TimeDuration::Forever();
|
||||
}
|
||||
|
||||
already_AddRefed<AnimationEffectTimingReadOnly> Timing();
|
||||
const TimingParams& SpecifiedTiming() const
|
||||
{
|
||||
return mTiming->AsTimingParams();
|
||||
}
|
||||
// AnimationEffect interface
|
||||
void GetTiming(EffectTiming& aRetVal) const;
|
||||
void GetComputedTimingAsDict(ComputedEffectTiming& aRetVal) const;
|
||||
void UpdateTiming(const OptionalEffectTiming& aTiming, ErrorResult& aRv);
|
||||
|
||||
const TimingParams& SpecifiedTiming() const { return mTiming; }
|
||||
void SetSpecifiedTiming(const TimingParams& aTiming);
|
||||
|
||||
// This function takes as input the timing parameters of an animation and
|
||||
@ -80,7 +82,6 @@ public:
|
||||
// Shortcut that gets the computed timing using the current local time as
|
||||
// calculated from the timeline time.
|
||||
ComputedTiming GetComputedTiming(const TimingParams* aTiming = nullptr) const;
|
||||
void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const;
|
||||
|
||||
virtual void SetAnimation(Animation* aAnimation) = 0;
|
||||
Animation* GetAnimation() const { return mAnimation; };
|
||||
@ -94,17 +95,17 @@ public:
|
||||
virtual bool AffectsGeometry() const = 0;
|
||||
|
||||
protected:
|
||||
virtual ~AnimationEffectReadOnly();
|
||||
virtual ~AnimationEffect() = default;
|
||||
|
||||
Nullable<TimeDuration> GetLocalTime() const;
|
||||
|
||||
protected:
|
||||
RefPtr<nsIDocument> mDocument;
|
||||
RefPtr<AnimationEffectTimingReadOnly> mTiming;
|
||||
RefPtr<Animation> mAnimation;
|
||||
TimingParams mTiming;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_AnimationEffectReadOnly_h
|
||||
#endif // mozilla_dom_AnimationEffect_h
|
@ -1,152 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/AnimationEffectTiming.h"
|
||||
|
||||
#include "mozilla/dom/AnimatableBinding.h"
|
||||
#include "mozilla/dom/AnimationEffectTimingBinding.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/TimingParams.h"
|
||||
#include "nsAString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
JSObject*
|
||||
AnimationEffectTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return AnimationEffectTimingBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
static inline void
|
||||
PostSpecifiedTimingUpdated(KeyframeEffect* aEffect)
|
||||
{
|
||||
if (aEffect) {
|
||||
aEffect->NotifySpecifiedTimingUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTiming::SetDelay(double aDelay)
|
||||
{
|
||||
TimeDuration delay = TimeDuration::FromMilliseconds(aDelay);
|
||||
if (mTiming.Delay() == delay) {
|
||||
return;
|
||||
}
|
||||
mTiming.SetDelay(delay);
|
||||
|
||||
PostSpecifiedTimingUpdated(mEffect);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTiming::SetEndDelay(double aEndDelay)
|
||||
{
|
||||
TimeDuration endDelay = TimeDuration::FromMilliseconds(aEndDelay);
|
||||
if (mTiming.EndDelay() == endDelay) {
|
||||
return;
|
||||
}
|
||||
mTiming.SetEndDelay(endDelay);
|
||||
|
||||
PostSpecifiedTimingUpdated(mEffect);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTiming::SetFill(const FillMode& aFill)
|
||||
{
|
||||
if (mTiming.Fill() == aFill) {
|
||||
return;
|
||||
}
|
||||
mTiming.SetFill(aFill);
|
||||
|
||||
PostSpecifiedTimingUpdated(mEffect);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTiming::SetIterationStart(double aIterationStart,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (mTiming.IterationStart() == aIterationStart) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimingParams::ValidateIterationStart(aIterationStart, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTiming.SetIterationStart(aIterationStart);
|
||||
|
||||
PostSpecifiedTimingUpdated(mEffect);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTiming::SetIterations(double aIterations, ErrorResult& aRv)
|
||||
{
|
||||
if (mTiming.Iterations() == aIterations) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimingParams::ValidateIterations(aIterations, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTiming.SetIterations(aIterations);
|
||||
|
||||
PostSpecifiedTimingUpdated(mEffect);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTiming::SetDuration(const UnrestrictedDoubleOrString& aDuration,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
Maybe<StickyTimeDuration> newDuration =
|
||||
TimingParams::ParseDuration(aDuration, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTiming.Duration() == newDuration) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTiming.SetDuration(Move(newDuration));
|
||||
|
||||
PostSpecifiedTimingUpdated(mEffect);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTiming::SetDirection(const PlaybackDirection& aDirection)
|
||||
{
|
||||
if (mTiming.Direction() == aDirection) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTiming.SetDirection(aDirection);
|
||||
|
||||
PostSpecifiedTimingUpdated(mEffect);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTiming::SetEasing(const nsAString& aEasing, ErrorResult& aRv)
|
||||
{
|
||||
Maybe<ComputedTimingFunction> newFunction =
|
||||
TimingParams::ParseEasing(aEasing, mDocument, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTiming.TimingFunction() == newFunction) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTiming.SetTimingFunction(Move(newFunction));
|
||||
|
||||
PostSpecifiedTimingUpdated(mEffect);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -1,49 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_AnimationEffectTiming_h
|
||||
#define mozilla_dom_AnimationEffectTiming_h
|
||||
|
||||
#include "mozilla/dom/AnimationEffectTimingReadOnly.h"
|
||||
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
|
||||
#include "nsStringFwd.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class KeyframeEffect;
|
||||
|
||||
class AnimationEffectTiming : public AnimationEffectTimingReadOnly
|
||||
{
|
||||
public:
|
||||
AnimationEffectTiming(nsIDocument* aDocument,
|
||||
const TimingParams& aTiming,
|
||||
KeyframeEffect* aEffect)
|
||||
: AnimationEffectTimingReadOnly(aDocument, aTiming)
|
||||
, mEffect(aEffect) { }
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void Unlink() override { mEffect = nullptr; }
|
||||
|
||||
void SetDelay(double aDelay);
|
||||
void SetEndDelay(double aEndDelay);
|
||||
void SetFill(const FillMode& aFill);
|
||||
void SetIterationStart(double aIterationStart, ErrorResult& aRv);
|
||||
void SetIterations(double aIterations, ErrorResult& aRv);
|
||||
void SetDuration(const UnrestrictedDoubleOrString& aDuration,
|
||||
ErrorResult& aRv);
|
||||
void SetDirection(const PlaybackDirection& aDirection);
|
||||
void SetEasing(const nsAString& aEasing, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
KeyframeEffect* MOZ_NON_OWNING_REF mEffect;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_AnimationEffectTiming_h
|
@ -1,51 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/AnimationEffectTimingReadOnly.h"
|
||||
|
||||
#include "mozilla/AnimationUtils.h"
|
||||
#include "mozilla/dom/AnimatableBinding.h"
|
||||
#include "mozilla/dom/AnimationEffectTimingReadOnlyBinding.h"
|
||||
#include "mozilla/dom/CSSPseudoElement.h"
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationEffectTimingReadOnly, mDocument)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AnimationEffectTimingReadOnly, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnimationEffectTimingReadOnly, Release)
|
||||
|
||||
JSObject*
|
||||
AnimationEffectTimingReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return AnimationEffectTimingReadOnlyBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTimingReadOnly::GetDuration(
|
||||
OwningUnrestrictedDoubleOrString& aRetVal) const
|
||||
{
|
||||
if (mTiming.Duration()) {
|
||||
aRetVal.SetAsUnrestrictedDouble() = mTiming.Duration()->ToMilliseconds();
|
||||
} else {
|
||||
aRetVal.SetAsString().AssignLiteral("auto");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnimationEffectTimingReadOnly::GetEasing(nsString& aRetVal) const
|
||||
{
|
||||
if (mTiming.TimingFunction()) {
|
||||
mTiming.TimingFunction()->AppendToString(aRetVal);
|
||||
} else {
|
||||
aRetVal.AssignLiteral("linear");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -1,63 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_AnimationEffectTimingReadOnly_h
|
||||
#define mozilla_dom_AnimationEffectTimingReadOnly_h
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/TimingParams.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class AnimationEffectTimingReadOnly : public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
AnimationEffectTimingReadOnly() = default;
|
||||
AnimationEffectTimingReadOnly(nsIDocument* aDocument,
|
||||
const TimingParams& aTiming)
|
||||
: mDocument(aDocument)
|
||||
, mTiming(aTiming) { }
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnimationEffectTimingReadOnly)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AnimationEffectTimingReadOnly)
|
||||
|
||||
protected:
|
||||
virtual ~AnimationEffectTimingReadOnly() = default;
|
||||
|
||||
public:
|
||||
nsISupports* GetParentObject() const { return mDocument; }
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
double Delay() const { return mTiming.Delay().ToMilliseconds(); }
|
||||
double EndDelay() const { return mTiming.EndDelay().ToMilliseconds(); }
|
||||
FillMode Fill() const { return mTiming.Fill(); }
|
||||
double IterationStart() const { return mTiming.IterationStart(); }
|
||||
double Iterations() const { return mTiming.Iterations(); }
|
||||
void GetDuration(OwningUnrestrictedDoubleOrString& aRetVal) const;
|
||||
PlaybackDirection Direction() const { return mTiming.Direction(); }
|
||||
void GetEasing(nsString& aRetVal) const;
|
||||
|
||||
const TimingParams& AsTimingParams() const { return mTiming; }
|
||||
void SetTimingParams(const TimingParams& aTiming) { mTiming = aTiming; }
|
||||
|
||||
virtual void Unlink() { }
|
||||
|
||||
protected:
|
||||
RefPtr<nsIDocument> mDocument;
|
||||
TimingParams mTiming;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_AnimationEffectTimingReadOnly_h
|
@ -14,7 +14,7 @@
|
||||
#include "nsString.h"
|
||||
#include "xpcpublic.h" // For xpc::NativeGlobal
|
||||
#include "mozilla/EffectSet.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -78,7 +78,7 @@ AnimationUtils::IsOffscreenThrottlingEnabled()
|
||||
AnimationUtils::EffectSetContainsAnimatedScale(EffectSet& aEffects,
|
||||
const nsIFrame* aFrame)
|
||||
{
|
||||
for (const dom::KeyframeEffectReadOnly* effect : aEffects) {
|
||||
for (const dom::KeyframeEffect* effect : aEffects) {
|
||||
if (effect->ContainsAnimatedScale(aFrame)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "mozilla/StickyTimeDuration.h"
|
||||
#include "mozilla/ComputedTimingFunction.h"
|
||||
|
||||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // FillMode
|
||||
#include "mozilla/dom/AnimationEffectBinding.h" // FillMode
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/AnimationComparator.h"
|
||||
#include "mozilla/AnimationPerformanceWarning.h"
|
||||
#include "mozilla/AnimationTarget.h"
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
using mozilla::dom::Animation;
|
||||
using mozilla::dom::Element;
|
||||
using mozilla::dom::KeyframeEffectReadOnly;
|
||||
using mozilla::dom::KeyframeEffect;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -81,7 +81,7 @@ enum class MatchForCompositor {
|
||||
}
|
||||
|
||||
static MatchForCompositor
|
||||
IsMatchForCompositor(const KeyframeEffectReadOnly& aEffect,
|
||||
IsMatchForCompositor(const KeyframeEffect& aEffect,
|
||||
nsCSSPropertyID aProperty,
|
||||
const nsIFrame* aFrame)
|
||||
{
|
||||
@ -197,7 +197,7 @@ FindAnimationsForCompositor(const nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
bool foundRunningAnimations = false;
|
||||
for (KeyframeEffectReadOnly* effect : *effects) {
|
||||
for (KeyframeEffect* effect : *effects) {
|
||||
MatchForCompositor matchResult =
|
||||
IsMatchForCompositor(*effect, aProperty, aFrame);
|
||||
|
||||
@ -395,7 +395,7 @@ EffectCompositor::UpdateEffectProperties(const ComputedStyle* aStyle,
|
||||
// result.
|
||||
effectSet->MarkCascadeNeedsUpdate();
|
||||
|
||||
for (KeyframeEffectReadOnly* effect : *effectSet) {
|
||||
for (KeyframeEffect* effect : *effectSet) {
|
||||
effect->UpdateProperties(aStyle);
|
||||
}
|
||||
}
|
||||
@ -404,14 +404,12 @@ EffectCompositor::UpdateEffectProperties(const ComputedStyle* aStyle,
|
||||
namespace {
|
||||
class EffectCompositeOrderComparator {
|
||||
public:
|
||||
bool Equals(const KeyframeEffectReadOnly* a,
|
||||
const KeyframeEffectReadOnly* b) const
|
||||
bool Equals(const KeyframeEffect* a, const KeyframeEffect* b) const
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
bool LessThan(const KeyframeEffectReadOnly* a,
|
||||
const KeyframeEffectReadOnly* b) const
|
||||
bool LessThan(const KeyframeEffect* a, const KeyframeEffect* b) const
|
||||
{
|
||||
MOZ_ASSERT(a->GetAnimation() && b->GetAnimation());
|
||||
MOZ_ASSERT(
|
||||
@ -444,8 +442,8 @@ EffectCompositor::GetServoAnimationRule(
|
||||
}
|
||||
|
||||
// Get a list of effects sorted by composite order.
|
||||
nsTArray<KeyframeEffectReadOnly*> sortedEffectList(effectSet->Count());
|
||||
for (KeyframeEffectReadOnly* effect : *effectSet) {
|
||||
nsTArray<KeyframeEffect*> sortedEffectList(effectSet->Count());
|
||||
for (KeyframeEffect* effect : *effectSet) {
|
||||
sortedEffectList.AppendElement(effect);
|
||||
}
|
||||
sortedEffectList.Sort(EffectCompositeOrderComparator());
|
||||
@ -457,7 +455,7 @@ EffectCompositor::GetServoAnimationRule(
|
||||
aCascadeLevel == CascadeLevel::Animations
|
||||
? effectSet->PropertiesForAnimationsLevel().Inverse()
|
||||
: effectSet->PropertiesForAnimationsLevel();
|
||||
for (KeyframeEffectReadOnly* effect : sortedEffectList) {
|
||||
for (KeyframeEffect* effect : sortedEffectList) {
|
||||
effect->GetAnimation()->ComposeStyle(*aAnimationValues, propertiesToSkip);
|
||||
}
|
||||
|
||||
@ -533,7 +531,7 @@ EffectCompositor::ClearIsRunningOnCompositor(const nsIFrame *aFrame,
|
||||
return;
|
||||
}
|
||||
|
||||
for (KeyframeEffectReadOnly* effect : *effects) {
|
||||
for (KeyframeEffect* effect : *effects) {
|
||||
effect->SetIsRunningOnCompositor(aProperty, false);
|
||||
}
|
||||
}
|
||||
@ -607,7 +605,7 @@ EffectCompositor::GetOverriddenProperties(EffectSet& aEffectSet,
|
||||
AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack;
|
||||
{
|
||||
nsCSSPropertyIDSet propertiesToTrackAsSet;
|
||||
for (KeyframeEffectReadOnly* effect : aEffectSet) {
|
||||
for (KeyframeEffect* effect : aEffectSet) {
|
||||
for (const AnimationProperty& property : effect->Properties()) {
|
||||
if (nsCSSProps::PropHasFlags(property.mProperty,
|
||||
CSSPropFlags::CanAnimateOnCompositor) &&
|
||||
@ -647,8 +645,8 @@ EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
|
||||
}
|
||||
|
||||
// Get a list of effects sorted by composite order.
|
||||
nsTArray<KeyframeEffectReadOnly*> sortedEffectList(aEffectSet.Count());
|
||||
for (KeyframeEffectReadOnly* effect : aEffectSet) {
|
||||
nsTArray<KeyframeEffect*> sortedEffectList(aEffectSet.Count());
|
||||
for (KeyframeEffect* effect : aEffectSet) {
|
||||
sortedEffectList.AppendElement(effect);
|
||||
}
|
||||
sortedEffectList.Sort(EffectCompositeOrderComparator());
|
||||
@ -695,7 +693,7 @@ EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
|
||||
|
||||
nsCSSPropertyIDSet propertiesForTransitionsLevel;
|
||||
|
||||
for (const KeyframeEffectReadOnly* effect : sortedEffectList) {
|
||||
for (const KeyframeEffect* effect : sortedEffectList) {
|
||||
MOZ_ASSERT(effect->GetAnimation(),
|
||||
"Effects on a target element should have an Animation");
|
||||
CascadeLevel cascadeLevel = effect->GetAnimation()->CascadeLevel();
|
||||
@ -766,7 +764,7 @@ EffectCompositor::SetPerformanceWarning(
|
||||
return;
|
||||
}
|
||||
|
||||
for (KeyframeEffectReadOnly* effect : *effects) {
|
||||
for (KeyframeEffect* effect : *effects) {
|
||||
effect->SetPerformanceWarning(aProperty, aWarning);
|
||||
}
|
||||
}
|
||||
@ -901,7 +899,7 @@ EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags,
|
||||
continue;
|
||||
}
|
||||
|
||||
for (KeyframeEffectReadOnly* effect : *effects) {
|
||||
for (KeyframeEffect* effect : *effects) {
|
||||
effect->GetAnimation()->WillComposeStyle();
|
||||
}
|
||||
|
||||
@ -977,7 +975,7 @@ EffectCompositor::PreTraverse(dom::Element* aElement,
|
||||
if (effects) {
|
||||
MaybeUpdateCascadeResults(aElement, aPseudoType);
|
||||
|
||||
for (KeyframeEffectReadOnly* effect : *effects) {
|
||||
for (KeyframeEffect* effect : *effects) {
|
||||
effect->GetAnimation()->WillComposeStyle();
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ EffectSet::GetEffectSetPropertyAtom(CSSPseudoElementType aPseudoType)
|
||||
}
|
||||
|
||||
void
|
||||
EffectSet::AddEffect(dom::KeyframeEffectReadOnly& aEffect)
|
||||
EffectSet::AddEffect(dom::KeyframeEffect& aEffect)
|
||||
{
|
||||
if (mEffects.Contains(&aEffect)) {
|
||||
return;
|
||||
@ -160,7 +160,7 @@ EffectSet::AddEffect(dom::KeyframeEffectReadOnly& aEffect)
|
||||
}
|
||||
|
||||
void
|
||||
EffectSet::RemoveEffect(dom::KeyframeEffectReadOnly& aEffect)
|
||||
EffectSet::RemoveEffect(dom::KeyframeEffect& aEffect)
|
||||
{
|
||||
if (!mEffects.Contains(&aEffect)) {
|
||||
return;
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "mozilla/EffectCompositor.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "nsHashKeys.h" // For nsPtrHashKey
|
||||
#include "nsTHashtable.h" // For nsTHashtable
|
||||
|
||||
@ -66,8 +66,8 @@ public:
|
||||
static void DestroyEffectSet(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
void AddEffect(dom::KeyframeEffectReadOnly& aEffect);
|
||||
void RemoveEffect(dom::KeyframeEffectReadOnly& aEffect);
|
||||
void AddEffect(dom::KeyframeEffect& aEffect);
|
||||
void RemoveEffect(dom::KeyframeEffect& aEffect);
|
||||
|
||||
void SetMayHaveOpacityAnimation() { mMayHaveOpacityAnim = true; }
|
||||
bool MayHaveOpacityAnimation() const { return mMayHaveOpacityAnim; }
|
||||
@ -75,7 +75,7 @@ public:
|
||||
bool MayHaveTransformAnimation() const { return mMayHaveTransformAnim; }
|
||||
|
||||
private:
|
||||
typedef nsTHashtable<nsRefPtrHashKey<dom::KeyframeEffectReadOnly>>
|
||||
typedef nsTHashtable<nsRefPtrHashKey<dom::KeyframeEffect>>
|
||||
OwningEffectSet;
|
||||
|
||||
public:
|
||||
@ -136,7 +136,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
dom::KeyframeEffectReadOnly* operator* ()
|
||||
dom::KeyframeEffect* operator*()
|
||||
{
|
||||
MOZ_ASSERT(!Done());
|
||||
return mHashIterator.Get()->GetKey();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,30 +7,112 @@
|
||||
#ifndef mozilla_dom_KeyframeEffect_h
|
||||
#define mozilla_dom_KeyframeEffect_h
|
||||
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
#include "nsCSSPropertyIDSet.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/AnimationPerformanceWarning.h"
|
||||
#include "mozilla/AnimationPropertySegment.h"
|
||||
#include "mozilla/AnimationTarget.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ComputedTimingFunction.h"
|
||||
#include "mozilla/EffectCompositor.h"
|
||||
#include "mozilla/Keyframe.h"
|
||||
#include "mozilla/KeyframeEffectParams.h"
|
||||
// RawServoDeclarationBlock and associated RefPtrTraits
|
||||
#include "mozilla/ServoBindingTypes.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "mozilla/dom/AnimationEffect.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/AnimationTarget.h" // For (Non)OwningAnimationTarget
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIFrame;
|
||||
class nsIPresShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AnimValuesStyleRule;
|
||||
enum class CSSPseudoElementType : uint8_t;
|
||||
class ErrorResult;
|
||||
struct KeyframeEffectParams;
|
||||
struct AnimationRule;
|
||||
struct TimingParams;
|
||||
class EffectSet;
|
||||
class ComputedStyle;
|
||||
|
||||
namespace dom {
|
||||
class ElementOrCSSPseudoElement;
|
||||
class GlobalObject;
|
||||
class OwningElementOrCSSPseudoElement;
|
||||
class UnrestrictedDoubleOrKeyframeAnimationOptions;
|
||||
class UnrestrictedDoubleOrKeyframeEffectOptions;
|
||||
enum class IterationCompositeOperation : uint8_t;
|
||||
enum class CompositeOperation : uint8_t;
|
||||
struct AnimationPropertyDetails;
|
||||
}
|
||||
|
||||
struct AnimationProperty
|
||||
{
|
||||
nsCSSPropertyID mProperty = eCSSProperty_UNKNOWN;
|
||||
|
||||
// If true, the propery is currently being animated on the compositor.
|
||||
//
|
||||
// Note that when the owning Animation requests a non-throttled restyle, in
|
||||
// between calling RequestRestyle on its EffectCompositor and when the
|
||||
// restyle is performed, this member may temporarily become false even if
|
||||
// the animation remains on the layer after the restyle.
|
||||
//
|
||||
// **NOTE**: This member is not included when comparing AnimationProperty
|
||||
// objects for equality.
|
||||
bool mIsRunningOnCompositor = false;
|
||||
|
||||
Maybe<AnimationPerformanceWarning> mPerformanceWarning;
|
||||
|
||||
InfallibleTArray<AnimationPropertySegment> mSegments;
|
||||
|
||||
// The copy constructor/assignment doesn't copy mIsRunningOnCompositor and
|
||||
// mPerformanceWarning.
|
||||
AnimationProperty() = default;
|
||||
AnimationProperty(const AnimationProperty& aOther)
|
||||
: mProperty(aOther.mProperty), mSegments(aOther.mSegments) { }
|
||||
AnimationProperty& operator=(const AnimationProperty& aOther)
|
||||
{
|
||||
mProperty = aOther.mProperty;
|
||||
mSegments = aOther.mSegments;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// NOTE: This operator does *not* compare the mIsRunningOnCompositor member.
|
||||
// This is because AnimationProperty objects are compared when recreating
|
||||
// CSS animations to determine if mutation observer change records need to
|
||||
// be created or not. However, at the point when these objects are compared
|
||||
// the mIsRunningOnCompositor will not have been set on the new objects so
|
||||
// we ignore this member to avoid generating spurious change records.
|
||||
bool operator==(const AnimationProperty& aOther) const
|
||||
{
|
||||
return mProperty == aOther.mProperty &&
|
||||
mSegments == aOther.mSegments;
|
||||
}
|
||||
bool operator!=(const AnimationProperty& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
struct ElementPropertyTransition;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class ElementOrCSSPseudoElement;
|
||||
class GlobalObject;
|
||||
class UnrestrictedDoubleOrKeyframeAnimationOptions;
|
||||
class UnrestrictedDoubleOrKeyframeEffectOptions;
|
||||
class Animation;
|
||||
|
||||
class KeyframeEffect : public KeyframeEffectReadOnly
|
||||
class KeyframeEffect : public AnimationEffect
|
||||
{
|
||||
public:
|
||||
KeyframeEffect(nsIDocument* aDocument,
|
||||
@ -38,9 +120,16 @@ public:
|
||||
const TimingParams& aTiming,
|
||||
const KeyframeEffectParams& aOptions);
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffect,
|
||||
AnimationEffect)
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
KeyframeEffect* AsKeyframeEffect() override { return this; }
|
||||
|
||||
// KeyframeEffect interface
|
||||
static already_AddRefed<KeyframeEffect>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const Nullable<ElementOrCSSPseudoElement>& aTarget,
|
||||
@ -50,7 +139,7 @@ public:
|
||||
|
||||
static already_AddRefed<KeyframeEffect>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
KeyframeEffectReadOnly& aSource,
|
||||
KeyframeEffect& aSource,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Variant of Constructor that accepts a KeyframeAnimationOptions object
|
||||
@ -63,8 +152,15 @@ public:
|
||||
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void NotifySpecifiedTimingUpdated();
|
||||
|
||||
void GetTarget(Nullable<OwningElementOrCSSPseudoElement>& aRv) const;
|
||||
Maybe<NonOwningAnimationTarget> GetTarget() const
|
||||
{
|
||||
Maybe<NonOwningAnimationTarget> result;
|
||||
if (mTarget) {
|
||||
result.emplace(*mTarget);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// This method calls GetTargetComputedStyle which is not safe to use when
|
||||
// we are in the middle of updating style. If we need to use this when
|
||||
// updating style, we should pass the ComputedStyle into this method and use
|
||||
@ -72,14 +168,295 @@ public:
|
||||
// GetComputedStyle.
|
||||
void SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget);
|
||||
|
||||
IterationCompositeOperation IterationComposite(CallerType aCallerType)
|
||||
{
|
||||
return KeyframeEffectReadOnly::IterationComposite();
|
||||
}
|
||||
void GetKeyframes(JSContext*& aCx,
|
||||
nsTArray<JSObject*>& aResult,
|
||||
ErrorResult& aRv);
|
||||
void GetProperties(nsTArray<AnimationPropertyDetails>& aProperties,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
// aCallerType is not used in the getter so we supply a default value so that
|
||||
// internal users don't need to specify this value.
|
||||
IterationCompositeOperation IterationComposite(
|
||||
CallerType aCallerType = CallerType::System) const;
|
||||
void SetIterationComposite(
|
||||
const IterationCompositeOperation& aIterationComposite,
|
||||
CallerType aCallerType);
|
||||
|
||||
CompositeOperation Composite() const;
|
||||
void SetComposite(const CompositeOperation& aComposite);
|
||||
|
||||
void NotifySpecifiedTimingUpdated();
|
||||
void NotifyAnimationTimingUpdated();
|
||||
void RequestRestyle(EffectCompositor::RestyleType aRestyleType);
|
||||
void SetAnimation(Animation* aAnimation) override;
|
||||
void SetKeyframes(JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
|
||||
ErrorResult& aRv);
|
||||
void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
|
||||
const ComputedStyle* aStyle);
|
||||
|
||||
// Returns true if the effect includes |aProperty| regardless of whether the
|
||||
// property is overridden by !important rule.
|
||||
bool HasAnimationOfProperty(nsCSSPropertyID aProperty) const;
|
||||
|
||||
// GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
|
||||
// to a given CSS property if the effect includes the property and the
|
||||
// property is not overridden by !important rules.
|
||||
// Also EffectiveAnimationOfProperty returns true under the same condition.
|
||||
//
|
||||
// NOTE: We don't currently check for !important rules for properties that
|
||||
// can't run on the compositor.
|
||||
bool HasEffectiveAnimationOfProperty(nsCSSPropertyID aProperty) const
|
||||
{
|
||||
return GetEffectiveAnimationOfProperty(aProperty) != nullptr;
|
||||
}
|
||||
const AnimationProperty* GetEffectiveAnimationOfProperty(
|
||||
nsCSSPropertyID aProperty) const;
|
||||
|
||||
const InfallibleTArray<AnimationProperty>& Properties() const
|
||||
{
|
||||
return mProperties;
|
||||
}
|
||||
|
||||
// Update |mProperties| by recalculating from |mKeyframes| using
|
||||
// |aComputedStyle| to resolve specified values.
|
||||
void UpdateProperties(const ComputedStyle* aComputedValues);
|
||||
|
||||
// Update various bits of state related to running ComposeStyle().
|
||||
// We need to update this outside ComposeStyle() because we should avoid
|
||||
// mutating any state in ComposeStyle() since it might be called during
|
||||
// parallel traversal.
|
||||
void WillComposeStyle();
|
||||
|
||||
// Updates |aComposeResult| with the animation values produced by this
|
||||
// AnimationEffect for the current time except any properties contained
|
||||
// in |aPropertiesToSkip|.
|
||||
void ComposeStyle(RawServoAnimationValueMap& aComposeResult,
|
||||
const nsCSSPropertyIDSet& aPropertiesToSkip);
|
||||
|
||||
|
||||
// Returns true if at least one property is being animated on compositor.
|
||||
bool IsRunningOnCompositor() const;
|
||||
void SetIsRunningOnCompositor(nsCSSPropertyID aProperty, bool aIsRunning);
|
||||
void ResetIsRunningOnCompositor();
|
||||
|
||||
// Returns true if this effect, applied to |aFrame|, contains properties
|
||||
// that mean we shouldn't run transform compositor animations on this element.
|
||||
//
|
||||
// For example, if we have an animation of geometric properties like 'left'
|
||||
// and 'top' on an element, we force all 'transform' animations running at
|
||||
// the same time on the same element to run on the main thread.
|
||||
//
|
||||
// When returning true, |aPerformanceWarning| stores the reason why
|
||||
// we shouldn't run the transform animations.
|
||||
bool ShouldBlockAsyncTransformAnimations(
|
||||
const nsIFrame* aFrame, AnimationPerformanceWarning::Type& aPerformanceWarning) const;
|
||||
bool HasGeometricProperties() const;
|
||||
bool AffectsGeometry() const override
|
||||
{
|
||||
return GetTarget() && HasGeometricProperties();
|
||||
}
|
||||
|
||||
nsIDocument* GetRenderedDocument() const;
|
||||
nsIPresShell* GetPresShell() const;
|
||||
|
||||
// Associates a warning with the animated property on the specified frame
|
||||
// indicating why, for example, the property could not be animated on the
|
||||
// compositor. |aParams| and |aParamsLength| are optional parameters which
|
||||
// will be used to generate a localized message for devtools.
|
||||
void SetPerformanceWarning(
|
||||
nsCSSPropertyID aProperty,
|
||||
const AnimationPerformanceWarning& aWarning);
|
||||
|
||||
// Cumulative change hint on each segment for each property.
|
||||
// This is used for deciding the animation is paint-only.
|
||||
void CalculateCumulativeChangeHint(const ComputedStyle* aStyle);
|
||||
|
||||
// Returns true if all of animation properties' change hints
|
||||
// can ignore painting if the animation is not visible.
|
||||
// See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
|
||||
// in detail which change hint can be ignored.
|
||||
bool CanIgnoreIfNotVisible() const;
|
||||
|
||||
// Returns true if the effect is current state and has scale animation.
|
||||
// |aFrame| is used for calculation of scale values.
|
||||
bool ContainsAnimatedScale(const nsIFrame* aFrame) const;
|
||||
|
||||
AnimationValue BaseStyle(nsCSSPropertyID aProperty) const
|
||||
{
|
||||
AnimationValue result;
|
||||
bool hasProperty = false;
|
||||
// We cannot use getters_AddRefs on RawServoAnimationValue because it is
|
||||
// an incomplete type, so Get() doesn't work. Instead, use GetWeak, and
|
||||
// then assign the raw pointer to a RefPtr.
|
||||
result.mServo = mBaseStyleValuesForServo.GetWeak(aProperty, &hasProperty);
|
||||
MOZ_ASSERT(hasProperty || result.IsNull());
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool HasComputedTimingChanged(
|
||||
const ComputedTiming& aComputedTiming,
|
||||
IterationCompositeOperation aIterationComposite,
|
||||
const Nullable<double>& aProgressOnLastCompose,
|
||||
uint64_t aCurrentIterationOnLastCompose);
|
||||
|
||||
protected:
|
||||
~KeyframeEffect() override = default;
|
||||
|
||||
static Maybe<OwningAnimationTarget>
|
||||
ConvertTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget);
|
||||
|
||||
template<class KeyframeEffectType, class OptionsType>
|
||||
static already_AddRefed<KeyframeEffectType>
|
||||
ConstructKeyframeEffect(const GlobalObject& aGlobal,
|
||||
const Nullable<ElementOrCSSPseudoElement>& aTarget,
|
||||
JS::Handle<JSObject*> aKeyframes,
|
||||
const OptionsType& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
template<class KeyframeEffectType>
|
||||
static already_AddRefed<KeyframeEffectType>
|
||||
ConstructKeyframeEffect(const GlobalObject& aGlobal,
|
||||
KeyframeEffect& aSource,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Build properties by recalculating from |mKeyframes| using |aComputedStyle|
|
||||
// to resolve specified values. This function also applies paced spacing if
|
||||
// needed.
|
||||
nsTArray<AnimationProperty> BuildProperties(const ComputedStyle* aStyle);
|
||||
|
||||
// This effect is registered with its target element so long as:
|
||||
//
|
||||
// (a) It has a target element, and
|
||||
// (b) It is "relevant" (i.e. yet to finish but not idle, or finished but
|
||||
// filling forwards)
|
||||
//
|
||||
// As a result, we need to make sure this gets called whenever anything
|
||||
// changes with regards to this effects's timing including changes to the
|
||||
// owning Animation's timing.
|
||||
void UpdateTargetRegistration();
|
||||
|
||||
// Remove the current effect target from its EffectSet.
|
||||
void UnregisterTarget();
|
||||
|
||||
// Update the associated frame state bits so that, if necessary, a stacking
|
||||
// context will be created and the effect sent to the compositor. We
|
||||
// typically need to do this when the properties referenced by the keyframe
|
||||
// have changed, or when the target frame might have changed.
|
||||
void MaybeUpdateFrameForCompositor();
|
||||
|
||||
// Looks up the ComputedStyle associated with the target element, if any.
|
||||
// We need to be careful to *not* call this when we are updating the style
|
||||
// context. That's because calling GetComputedStyle when we are in the process
|
||||
// of building a ComputedStyle may trigger various forms of infinite
|
||||
// recursion.
|
||||
already_AddRefed<ComputedStyle> GetTargetComputedStyle();
|
||||
|
||||
// A wrapper for marking cascade update according to the current
|
||||
// target and its effectSet.
|
||||
void MarkCascadeNeedsUpdate();
|
||||
|
||||
void EnsureBaseStyles(const ComputedStyle* aComputedValues,
|
||||
const nsTArray<AnimationProperty>& aProperties);
|
||||
|
||||
// Stylo version of the above function that also first checks for an additive
|
||||
// value in |aProperty|'s list of segments.
|
||||
void EnsureBaseStyle(const AnimationProperty& aProperty,
|
||||
nsPresContext* aPresContext,
|
||||
const ComputedStyle* aComputedValues,
|
||||
RefPtr<ComputedStyle>& aBaseComputedValues);
|
||||
|
||||
Maybe<OwningAnimationTarget> mTarget;
|
||||
|
||||
KeyframeEffectParams mEffectOptions;
|
||||
|
||||
// The specified keyframes.
|
||||
nsTArray<Keyframe> mKeyframes;
|
||||
|
||||
// A set of per-property value arrays, derived from |mKeyframes|.
|
||||
nsTArray<AnimationProperty> mProperties;
|
||||
|
||||
// The computed progress last time we composed the style rule. This is
|
||||
// used to detect when the progress is not changing (e.g. due to a step
|
||||
// timing function) so we can avoid unnecessary style updates.
|
||||
Nullable<double> mProgressOnLastCompose;
|
||||
|
||||
// The purpose of this value is the same as mProgressOnLastCompose but
|
||||
// this is used to detect when the current iteration is not changing
|
||||
// in the case when iterationComposite is accumulate.
|
||||
uint64_t mCurrentIterationOnLastCompose = 0;
|
||||
|
||||
// We need to track when we go to or from being "in effect" since
|
||||
// we need to re-evaluate the cascade of animations when that changes.
|
||||
bool mInEffectOnLastAnimationTimingUpdate;
|
||||
|
||||
// The non-animated values for properties in this effect that contain at
|
||||
// least one animation value that is composited with the underlying value
|
||||
// (i.e. it uses the additive or accumulate composite mode).
|
||||
nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>
|
||||
mBaseStyleValuesForServo;
|
||||
|
||||
// True if this effect is in the EffectSet for its target element. This is
|
||||
// used as an optimization to avoid unnecessary hashmap lookups on the
|
||||
// EffectSet.
|
||||
bool mInEffectSet = false;
|
||||
|
||||
private:
|
||||
nsChangeHint mCumulativeChangeHint;
|
||||
|
||||
void ComposeStyleRule(RawServoAnimationValueMap& aAnimationValues,
|
||||
const AnimationProperty& aProperty,
|
||||
const AnimationPropertySegment& aSegment,
|
||||
const ComputedTiming& aComputedTiming);
|
||||
|
||||
|
||||
already_AddRefed<ComputedStyle> CreateComputedStyleForAnimationValue(
|
||||
nsCSSPropertyID aProperty,
|
||||
const AnimationValue& aValue,
|
||||
nsPresContext* aPresContext,
|
||||
const ComputedStyle* aBaseComputedStyle);
|
||||
|
||||
// Return the primary frame for the target (pseudo-)element.
|
||||
nsIFrame* GetPrimaryFrame() const;
|
||||
// Returns the frame which is used for styling.
|
||||
nsIFrame* GetStyleFrame() const;
|
||||
|
||||
bool CanThrottle() const;
|
||||
bool CanThrottleTransformChanges(const nsIFrame& aFrame) const;
|
||||
bool CanThrottleTransformChangesInScrollable(nsIFrame& aFrame) const;
|
||||
|
||||
// Returns true if the computedTiming has changed since the last
|
||||
// composition.
|
||||
bool HasComputedTimingChanged() const;
|
||||
|
||||
// Returns true unless Gecko limitations prevent performing transform
|
||||
// animations for |aFrame|. When returning true, the reason for the
|
||||
// limitation is stored in |aOutPerformanceWarning|.
|
||||
static bool CanAnimateTransformOnCompositor(
|
||||
const nsIFrame* aFrame,
|
||||
AnimationPerformanceWarning::Type& aPerformanceWarning);
|
||||
static bool IsGeometricProperty(const nsCSSPropertyID aProperty);
|
||||
|
||||
static const TimeDuration OverflowRegionRefreshInterval();
|
||||
|
||||
void UpdateEffectSet(mozilla::EffectSet* aEffectSet = nullptr) const;
|
||||
|
||||
// Returns true if this effect has transform and the transform might affect
|
||||
// the overflow region.
|
||||
// This function is used for updating scroll bars or notifying intersection
|
||||
// observers reflected by the transform.
|
||||
bool HasTransformThatMightAffectOverflow() const
|
||||
{
|
||||
return mCumulativeChangeHint & (nsChangeHint_UpdatePostTransformOverflow |
|
||||
nsChangeHint_AddOrRemoveTransform |
|
||||
nsChangeHint_UpdateTransformLayer);
|
||||
}
|
||||
|
||||
// Returns true if this effect causes visibility change.
|
||||
// (i.e. 'visibility: hidden' -> 'visibility: visible' and vice versa.)
|
||||
bool HasVisibilityChange() const
|
||||
{
|
||||
return mCumulativeChangeHint & nsChangeHint_VisibilityChange;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,443 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_KeyframeEffectReadOnly_h
|
||||
#define mozilla_dom_KeyframeEffectReadOnly_h
|
||||
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
#include "nsCSSPropertyIDSet.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/AnimationPerformanceWarning.h"
|
||||
#include "mozilla/AnimationPropertySegment.h"
|
||||
#include "mozilla/AnimationTarget.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ComputedTimingFunction.h"
|
||||
#include "mozilla/EffectCompositor.h"
|
||||
#include "mozilla/Keyframe.h"
|
||||
#include "mozilla/KeyframeEffectParams.h"
|
||||
// RawServoDeclarationBlock and associated RefPtrTraits
|
||||
#include "mozilla/ServoBindingTypes.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "mozilla/dom/AnimationEffectReadOnly.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIFrame;
|
||||
class nsIPresShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AnimValuesStyleRule;
|
||||
enum class CSSPseudoElementType : uint8_t;
|
||||
class ErrorResult;
|
||||
struct AnimationRule;
|
||||
struct TimingParams;
|
||||
class EffectSet;
|
||||
class ComputedStyle;
|
||||
|
||||
namespace dom {
|
||||
class ElementOrCSSPseudoElement;
|
||||
class GlobalObject;
|
||||
class OwningElementOrCSSPseudoElement;
|
||||
class UnrestrictedDoubleOrKeyframeAnimationOptions;
|
||||
class UnrestrictedDoubleOrKeyframeEffectOptions;
|
||||
enum class IterationCompositeOperation : uint8_t;
|
||||
enum class CompositeOperation : uint8_t;
|
||||
struct AnimationPropertyDetails;
|
||||
}
|
||||
|
||||
struct AnimationProperty
|
||||
{
|
||||
nsCSSPropertyID mProperty = eCSSProperty_UNKNOWN;
|
||||
|
||||
// If true, the propery is currently being animated on the compositor.
|
||||
//
|
||||
// Note that when the owning Animation requests a non-throttled restyle, in
|
||||
// between calling RequestRestyle on its EffectCompositor and when the
|
||||
// restyle is performed, this member may temporarily become false even if
|
||||
// the animation remains on the layer after the restyle.
|
||||
//
|
||||
// **NOTE**: This member is not included when comparing AnimationProperty
|
||||
// objects for equality.
|
||||
bool mIsRunningOnCompositor = false;
|
||||
|
||||
Maybe<AnimationPerformanceWarning> mPerformanceWarning;
|
||||
|
||||
InfallibleTArray<AnimationPropertySegment> mSegments;
|
||||
|
||||
// The copy constructor/assignment doesn't copy mIsRunningOnCompositor and
|
||||
// mPerformanceWarning.
|
||||
AnimationProperty() = default;
|
||||
AnimationProperty(const AnimationProperty& aOther)
|
||||
: mProperty(aOther.mProperty), mSegments(aOther.mSegments) { }
|
||||
AnimationProperty& operator=(const AnimationProperty& aOther)
|
||||
{
|
||||
mProperty = aOther.mProperty;
|
||||
mSegments = aOther.mSegments;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// NOTE: This operator does *not* compare the mIsRunningOnCompositor member.
|
||||
// This is because AnimationProperty objects are compared when recreating
|
||||
// CSS animations to determine if mutation observer change records need to
|
||||
// be created or not. However, at the point when these objects are compared
|
||||
// the mIsRunningOnCompositor will not have been set on the new objects so
|
||||
// we ignore this member to avoid generating spurious change records.
|
||||
bool operator==(const AnimationProperty& aOther) const
|
||||
{
|
||||
return mProperty == aOther.mProperty &&
|
||||
mSegments == aOther.mSegments;
|
||||
}
|
||||
bool operator!=(const AnimationProperty& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
struct ElementPropertyTransition;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Animation;
|
||||
|
||||
class KeyframeEffectReadOnly : public AnimationEffectReadOnly
|
||||
{
|
||||
public:
|
||||
KeyframeEffectReadOnly(nsIDocument* aDocument,
|
||||
const Maybe<OwningAnimationTarget>& aTarget,
|
||||
const TimingParams& aTiming,
|
||||
const KeyframeEffectParams& aOptions);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadOnly,
|
||||
AnimationEffectReadOnly)
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
KeyframeEffectReadOnly* AsKeyframeEffect() override { return this; }
|
||||
|
||||
// KeyframeEffectReadOnly interface
|
||||
static already_AddRefed<KeyframeEffectReadOnly>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const Nullable<ElementOrCSSPseudoElement>& aTarget,
|
||||
JS::Handle<JSObject*> aKeyframes,
|
||||
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<KeyframeEffectReadOnly>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
KeyframeEffectReadOnly& aSource,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void GetTarget(Nullable<OwningElementOrCSSPseudoElement>& aRv) const;
|
||||
Maybe<NonOwningAnimationTarget> GetTarget() const
|
||||
{
|
||||
Maybe<NonOwningAnimationTarget> result;
|
||||
if (mTarget) {
|
||||
result.emplace(*mTarget);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void GetKeyframes(JSContext*& aCx,
|
||||
nsTArray<JSObject*>& aResult,
|
||||
ErrorResult& aRv);
|
||||
void GetProperties(nsTArray<AnimationPropertyDetails>& aProperties,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
IterationCompositeOperation IterationComposite() const;
|
||||
CompositeOperation Composite() const;
|
||||
void NotifyAnimationTimingUpdated();
|
||||
void RequestRestyle(EffectCompositor::RestyleType aRestyleType);
|
||||
void SetAnimation(Animation* aAnimation) override;
|
||||
void SetKeyframes(JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
|
||||
ErrorResult& aRv);
|
||||
void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
|
||||
const ComputedStyle* aStyle);
|
||||
|
||||
// Returns true if the effect includes |aProperty| regardless of whether the
|
||||
// property is overridden by !important rule.
|
||||
bool HasAnimationOfProperty(nsCSSPropertyID aProperty) const;
|
||||
|
||||
// GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
|
||||
// to a given CSS property if the effect includes the property and the
|
||||
// property is not overridden by !important rules.
|
||||
// Also EffectiveAnimationOfProperty returns true under the same condition.
|
||||
//
|
||||
// NOTE: We don't currently check for !important rules for properties that
|
||||
// can't run on the compositor.
|
||||
bool HasEffectiveAnimationOfProperty(nsCSSPropertyID aProperty) const
|
||||
{
|
||||
return GetEffectiveAnimationOfProperty(aProperty) != nullptr;
|
||||
}
|
||||
const AnimationProperty* GetEffectiveAnimationOfProperty(
|
||||
nsCSSPropertyID aProperty) const;
|
||||
|
||||
const InfallibleTArray<AnimationProperty>& Properties() const
|
||||
{
|
||||
return mProperties;
|
||||
}
|
||||
|
||||
// Update |mProperties| by recalculating from |mKeyframes| using
|
||||
// |aComputedStyle| to resolve specified values.
|
||||
void UpdateProperties(const ComputedStyle* aComputedValues);
|
||||
|
||||
// Update various bits of state related to running ComposeStyle().
|
||||
// We need to update this outside ComposeStyle() because we should avoid
|
||||
// mutating any state in ComposeStyle() since it might be called during
|
||||
// parallel traversal.
|
||||
void WillComposeStyle();
|
||||
|
||||
// Updates |aComposeResult| with the animation values produced by this
|
||||
// AnimationEffect for the current time except any properties contained
|
||||
// in |aPropertiesToSkip|.
|
||||
void ComposeStyle(RawServoAnimationValueMap& aComposeResult,
|
||||
const nsCSSPropertyIDSet& aPropertiesToSkip);
|
||||
|
||||
|
||||
// Returns true if at least one property is being animated on compositor.
|
||||
bool IsRunningOnCompositor() const;
|
||||
void SetIsRunningOnCompositor(nsCSSPropertyID aProperty, bool aIsRunning);
|
||||
void ResetIsRunningOnCompositor();
|
||||
|
||||
// Returns true if this effect, applied to |aFrame|, contains properties
|
||||
// that mean we shouldn't run transform compositor animations on this element.
|
||||
//
|
||||
// For example, if we have an animation of geometric properties like 'left'
|
||||
// and 'top' on an element, we force all 'transform' animations running at
|
||||
// the same time on the same element to run on the main thread.
|
||||
//
|
||||
// When returning true, |aPerformanceWarning| stores the reason why
|
||||
// we shouldn't run the transform animations.
|
||||
bool ShouldBlockAsyncTransformAnimations(
|
||||
const nsIFrame* aFrame, AnimationPerformanceWarning::Type& aPerformanceWarning) const;
|
||||
bool HasGeometricProperties() const;
|
||||
bool AffectsGeometry() const override
|
||||
{
|
||||
return GetTarget() && HasGeometricProperties();
|
||||
}
|
||||
|
||||
nsIDocument* GetRenderedDocument() const;
|
||||
nsIPresShell* GetPresShell() const;
|
||||
|
||||
// Associates a warning with the animated property on the specified frame
|
||||
// indicating why, for example, the property could not be animated on the
|
||||
// compositor. |aParams| and |aParamsLength| are optional parameters which
|
||||
// will be used to generate a localized message for devtools.
|
||||
void SetPerformanceWarning(
|
||||
nsCSSPropertyID aProperty,
|
||||
const AnimationPerformanceWarning& aWarning);
|
||||
|
||||
// Cumulative change hint on each segment for each property.
|
||||
// This is used for deciding the animation is paint-only.
|
||||
void CalculateCumulativeChangeHint(const ComputedStyle* aStyle);
|
||||
|
||||
// Returns true if all of animation properties' change hints
|
||||
// can ignore painting if the animation is not visible.
|
||||
// See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
|
||||
// in detail which change hint can be ignored.
|
||||
bool CanIgnoreIfNotVisible() const;
|
||||
|
||||
// Returns true if the effect is current state and has scale animation.
|
||||
// |aFrame| is used for calculation of scale values.
|
||||
bool ContainsAnimatedScale(const nsIFrame* aFrame) const;
|
||||
|
||||
AnimationValue BaseStyle(nsCSSPropertyID aProperty) const
|
||||
{
|
||||
AnimationValue result;
|
||||
bool hasProperty = false;
|
||||
// We cannot use getters_AddRefs on RawServoAnimationValue because it is
|
||||
// an incomplete type, so Get() doesn't work. Instead, use GetWeak, and
|
||||
// then assign the raw pointer to a RefPtr.
|
||||
result.mServo = mBaseStyleValuesForServo.GetWeak(aProperty, &hasProperty);
|
||||
MOZ_ASSERT(hasProperty || result.IsNull());
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool HasComputedTimingChanged(
|
||||
const ComputedTiming& aComputedTiming,
|
||||
IterationCompositeOperation aIterationComposite,
|
||||
const Nullable<double>& aProgressOnLastCompose,
|
||||
uint64_t aCurrentIterationOnLastCompose);
|
||||
|
||||
protected:
|
||||
KeyframeEffectReadOnly(nsIDocument* aDocument,
|
||||
const Maybe<OwningAnimationTarget>& aTarget,
|
||||
AnimationEffectTimingReadOnly* aTiming,
|
||||
const KeyframeEffectParams& aOptions);
|
||||
|
||||
~KeyframeEffectReadOnly() override = default;
|
||||
|
||||
static Maybe<OwningAnimationTarget>
|
||||
ConvertTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget);
|
||||
|
||||
template<class KeyframeEffectType, class OptionsType>
|
||||
static already_AddRefed<KeyframeEffectType>
|
||||
ConstructKeyframeEffect(const GlobalObject& aGlobal,
|
||||
const Nullable<ElementOrCSSPseudoElement>& aTarget,
|
||||
JS::Handle<JSObject*> aKeyframes,
|
||||
const OptionsType& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
template<class KeyframeEffectType>
|
||||
static already_AddRefed<KeyframeEffectType>
|
||||
ConstructKeyframeEffect(const GlobalObject& aGlobal,
|
||||
KeyframeEffectReadOnly& aSource,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Build properties by recalculating from |mKeyframes| using |aComputedStyle|
|
||||
// to resolve specified values. This function also applies paced spacing if
|
||||
// needed.
|
||||
nsTArray<AnimationProperty> BuildProperties(const ComputedStyle* aStyle);
|
||||
|
||||
// This effect is registered with its target element so long as:
|
||||
//
|
||||
// (a) It has a target element, and
|
||||
// (b) It is "relevant" (i.e. yet to finish but not idle, or finished but
|
||||
// filling forwards)
|
||||
//
|
||||
// As a result, we need to make sure this gets called whenever anything
|
||||
// changes with regards to this effects's timing including changes to the
|
||||
// owning Animation's timing.
|
||||
void UpdateTargetRegistration();
|
||||
|
||||
// Remove the current effect target from its EffectSet.
|
||||
void UnregisterTarget();
|
||||
|
||||
// Update the associated frame state bits so that, if necessary, a stacking
|
||||
// context will be created and the effect sent to the compositor. We
|
||||
// typically need to do this when the properties referenced by the keyframe
|
||||
// have changed, or when the target frame might have changed.
|
||||
void MaybeUpdateFrameForCompositor();
|
||||
|
||||
// Looks up the ComputedStyle associated with the target element, if any.
|
||||
// We need to be careful to *not* call this when we are updating the style
|
||||
// context. That's because calling GetComputedStyle when we are in the process
|
||||
// of building a ComputedStyle may trigger various forms of infinite
|
||||
// recursion.
|
||||
already_AddRefed<ComputedStyle> GetTargetComputedStyle();
|
||||
|
||||
// A wrapper for marking cascade update according to the current
|
||||
// target and its effectSet.
|
||||
void MarkCascadeNeedsUpdate();
|
||||
|
||||
void EnsureBaseStyles(const ComputedStyle* aComputedValues,
|
||||
const nsTArray<AnimationProperty>& aProperties);
|
||||
|
||||
// Stylo version of the above function that also first checks for an additive
|
||||
// value in |aProperty|'s list of segments.
|
||||
void EnsureBaseStyle(const AnimationProperty& aProperty,
|
||||
nsPresContext* aPresContext,
|
||||
const ComputedStyle* aComputedValues,
|
||||
RefPtr<ComputedStyle>& aBaseComputedValues);
|
||||
|
||||
Maybe<OwningAnimationTarget> mTarget;
|
||||
|
||||
KeyframeEffectParams mEffectOptions;
|
||||
|
||||
// The specified keyframes.
|
||||
nsTArray<Keyframe> mKeyframes;
|
||||
|
||||
// A set of per-property value arrays, derived from |mKeyframes|.
|
||||
nsTArray<AnimationProperty> mProperties;
|
||||
|
||||
// The computed progress last time we composed the style rule. This is
|
||||
// used to detect when the progress is not changing (e.g. due to a step
|
||||
// timing function) so we can avoid unnecessary style updates.
|
||||
Nullable<double> mProgressOnLastCompose;
|
||||
|
||||
// The purpose of this value is the same as mProgressOnLastCompose but
|
||||
// this is used to detect when the current iteration is not changing
|
||||
// in the case when iterationComposite is accumulate.
|
||||
uint64_t mCurrentIterationOnLastCompose = 0;
|
||||
|
||||
// We need to track when we go to or from being "in effect" since
|
||||
// we need to re-evaluate the cascade of animations when that changes.
|
||||
bool mInEffectOnLastAnimationTimingUpdate;
|
||||
|
||||
// The non-animated values for properties in this effect that contain at
|
||||
// least one animation value that is composited with the underlying value
|
||||
// (i.e. it uses the additive or accumulate composite mode).
|
||||
nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>
|
||||
mBaseStyleValuesForServo;
|
||||
|
||||
// True if this effect is in the EffectSet for its target element. This is
|
||||
// used as an optimization to avoid unnecessary hashmap lookups on the
|
||||
// EffectSet.
|
||||
bool mInEffectSet = false;
|
||||
|
||||
private:
|
||||
nsChangeHint mCumulativeChangeHint;
|
||||
|
||||
void ComposeStyleRule(RawServoAnimationValueMap& aAnimationValues,
|
||||
const AnimationProperty& aProperty,
|
||||
const AnimationPropertySegment& aSegment,
|
||||
const ComputedTiming& aComputedTiming);
|
||||
|
||||
|
||||
already_AddRefed<ComputedStyle> CreateComputedStyleForAnimationValue(
|
||||
nsCSSPropertyID aProperty,
|
||||
const AnimationValue& aValue,
|
||||
nsPresContext* aPresContext,
|
||||
const ComputedStyle* aBaseComputedStyle);
|
||||
|
||||
// Return the primary frame for the target (pseudo-)element.
|
||||
nsIFrame* GetPrimaryFrame() const;
|
||||
// Returns the frame which is used for styling.
|
||||
nsIFrame* GetStyleFrame() const;
|
||||
|
||||
bool CanThrottle() const;
|
||||
bool CanThrottleTransformChanges(const nsIFrame& aFrame) const;
|
||||
bool CanThrottleTransformChangesInScrollable(nsIFrame& aFrame) const;
|
||||
|
||||
// Returns true if the computedTiming has changed since the last
|
||||
// composition.
|
||||
bool HasComputedTimingChanged() const;
|
||||
|
||||
// Returns true unless Gecko limitations prevent performing transform
|
||||
// animations for |aFrame|. When returning true, the reason for the
|
||||
// limitation is stored in |aOutPerformanceWarning|.
|
||||
static bool CanAnimateTransformOnCompositor(
|
||||
const nsIFrame* aFrame,
|
||||
AnimationPerformanceWarning::Type& aPerformanceWarning);
|
||||
static bool IsGeometricProperty(const nsCSSPropertyID aProperty);
|
||||
|
||||
static const TimeDuration OverflowRegionRefreshInterval();
|
||||
|
||||
void UpdateEffectSet(mozilla::EffectSet* aEffectSet = nullptr) const;
|
||||
|
||||
// Returns true if this effect has transform and the transform might affect
|
||||
// the overflow region.
|
||||
// This function is used for updating scroll bars or notifying intersection
|
||||
// observers reflected by the transform.
|
||||
bool HasTransformThatMightAffectOverflow() const
|
||||
{
|
||||
return mCumulativeChangeHint & (nsChangeHint_UpdatePostTransformOverflow |
|
||||
nsChangeHint_AddOrRemoveTransform |
|
||||
nsChangeHint_UpdateTransformLayer);
|
||||
}
|
||||
|
||||
// Returns true if this effect causes visibility change.
|
||||
// (i.e. 'visibility: hidden' -> 'visibility: visible' and vice versa.)
|
||||
bool HasVisibilityChange() const
|
||||
{
|
||||
return mCumulativeChangeHint & nsChangeHint_VisibilityChange;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_KeyframeEffectReadOnly_h
|
@ -18,7 +18,7 @@
|
||||
#include "mozilla/dom/BaseKeyframeTypesBinding.h" // For FastBaseKeyframe etc.
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h" // For PropertyValuesPair etc.
|
||||
#include "mozilla/dom/KeyframeEffect.h" // For PropertyValuesPair etc.
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "jsapi.h" // For ForOfIterator etc.
|
||||
#include "nsClassHashtable.h"
|
||||
|
@ -16,11 +16,11 @@
|
||||
namespace mozilla {
|
||||
|
||||
template <class OptionsType>
|
||||
static const dom::AnimationEffectTimingProperties&
|
||||
static const dom::EffectTiming&
|
||||
GetTimingProperties(const OptionsType& aOptions);
|
||||
|
||||
template <>
|
||||
/* static */ const dom::AnimationEffectTimingProperties&
|
||||
/* static */ const dom::EffectTiming&
|
||||
GetTimingProperties(
|
||||
const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions)
|
||||
{
|
||||
@ -29,7 +29,7 @@ GetTimingProperties(
|
||||
}
|
||||
|
||||
template <>
|
||||
/* static */ const dom::AnimationEffectTimingProperties&
|
||||
/* static */ const dom::EffectTiming&
|
||||
GetTimingProperties(
|
||||
const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions)
|
||||
{
|
||||
@ -44,6 +44,7 @@ TimingParams::FromOptionsType(const OptionsType& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
TimingParams result;
|
||||
|
||||
if (aOptions.IsUnrestrictedDouble()) {
|
||||
double durationInMs = aOptions.GetAsUnrestrictedDouble();
|
||||
if (durationInMs >= 0) {
|
||||
@ -53,39 +54,11 @@ TimingParams::FromOptionsType(const OptionsType& aOptions,
|
||||
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
|
||||
return result;
|
||||
}
|
||||
result.Update();
|
||||
} else {
|
||||
const dom::AnimationEffectTimingProperties& timing =
|
||||
GetTimingProperties(aOptions);
|
||||
|
||||
Maybe<StickyTimeDuration> duration =
|
||||
TimingParams::ParseDuration(timing.mDuration, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
TimingParams::ValidateIterationStart(timing.mIterationStart, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
TimingParams::ValidateIterations(timing.mIterations, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
Maybe<ComputedTimingFunction> easing =
|
||||
TimingParams::ParseEasing(timing.mEasing, aDocument, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.mDuration = duration;
|
||||
result.mDelay = TimeDuration::FromMilliseconds(timing.mDelay);
|
||||
result.mEndDelay = TimeDuration::FromMilliseconds(timing.mEndDelay);
|
||||
result.mIterations = timing.mIterations;
|
||||
result.mIterationStart = timing.mIterationStart;
|
||||
result.mDirection = timing.mDirection;
|
||||
result.mFill = timing.mFill;
|
||||
result.mFunction = easing;
|
||||
const dom::EffectTiming& timing = GetTimingProperties(aOptions);
|
||||
result = FromEffectTiming(timing, aDocument, aRv);
|
||||
}
|
||||
result.Update();
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -108,6 +81,126 @@ TimingParams::FromOptionsUnion(
|
||||
return FromOptionsType(aOptions, aDocument, aRv);
|
||||
}
|
||||
|
||||
/* static */ TimingParams
|
||||
TimingParams::FromEffectTiming(const dom::EffectTiming& aEffectTiming,
|
||||
nsIDocument* aDocument,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
TimingParams result;
|
||||
|
||||
Maybe<StickyTimeDuration> duration =
|
||||
TimingParams::ParseDuration(aEffectTiming.mDuration, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
TimingParams::ValidateIterationStart(aEffectTiming.mIterationStart, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
TimingParams::ValidateIterations(aEffectTiming.mIterations, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
Maybe<ComputedTimingFunction> easing =
|
||||
TimingParams::ParseEasing(aEffectTiming.mEasing, aDocument, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.mDuration = duration;
|
||||
result.mDelay = TimeDuration::FromMilliseconds(aEffectTiming.mDelay);
|
||||
result.mEndDelay = TimeDuration::FromMilliseconds(aEffectTiming.mEndDelay);
|
||||
result.mIterations = aEffectTiming.mIterations;
|
||||
result.mIterationStart = aEffectTiming.mIterationStart;
|
||||
result.mDirection = aEffectTiming.mDirection;
|
||||
result.mFill = aEffectTiming.mFill;
|
||||
result.mFunction = easing;
|
||||
|
||||
result.Update();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */ TimingParams
|
||||
TimingParams::MergeOptionalEffectTiming(
|
||||
const TimingParams& aSource,
|
||||
const dom::OptionalEffectTiming& aEffectTiming,
|
||||
nsIDocument* aDocument,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!aRv.Failed(), "Initially return value should be ok");
|
||||
|
||||
TimingParams result = aSource;
|
||||
|
||||
// Check for errors first
|
||||
|
||||
Maybe<StickyTimeDuration> duration;
|
||||
if (aEffectTiming.mDuration.WasPassed()) {
|
||||
duration =
|
||||
TimingParams::ParseDuration(aEffectTiming.mDuration.Value(), aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (aEffectTiming.mIterationStart.WasPassed()) {
|
||||
TimingParams::ValidateIterationStart(aEffectTiming.mIterationStart.Value(),
|
||||
aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (aEffectTiming.mIterations.WasPassed()) {
|
||||
TimingParams::ValidateIterations(aEffectTiming.mIterations.Value(), aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<ComputedTimingFunction> easing;
|
||||
if (aEffectTiming.mEasing.WasPassed()) {
|
||||
easing =
|
||||
TimingParams::ParseEasing(aEffectTiming.mEasing.Value(), aDocument, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Assign values
|
||||
|
||||
if (aEffectTiming.mDuration.WasPassed()) {
|
||||
result.mDuration = duration;
|
||||
}
|
||||
if (aEffectTiming.mDelay.WasPassed()) {
|
||||
result.mDelay =
|
||||
TimeDuration::FromMilliseconds(aEffectTiming.mDelay.Value());
|
||||
}
|
||||
if (aEffectTiming.mEndDelay.WasPassed()) {
|
||||
result.mEndDelay =
|
||||
TimeDuration::FromMilliseconds(aEffectTiming.mEndDelay.Value());
|
||||
}
|
||||
if (aEffectTiming.mIterations.WasPassed()) {
|
||||
result.mIterations = aEffectTiming.mIterations.Value();
|
||||
}
|
||||
if (aEffectTiming.mIterationStart.WasPassed()) {
|
||||
result.mIterationStart = aEffectTiming.mIterationStart.Value();
|
||||
}
|
||||
if (aEffectTiming.mDirection.WasPassed()) {
|
||||
result.mDirection = aEffectTiming.mDirection.Value();
|
||||
}
|
||||
if (aEffectTiming.mFill.WasPassed()) {
|
||||
result.mFill = aEffectTiming.mFill.Value();
|
||||
}
|
||||
if (aEffectTiming.mEasing.WasPassed()) {
|
||||
result.mFunction = easing;
|
||||
}
|
||||
|
||||
result.Update();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */ Maybe<ComputedTimingFunction>
|
||||
TimingParams::ParseEasing(const nsAString& aEasing,
|
||||
nsIDocument* aDocument,
|
||||
@ -136,6 +229,7 @@ TimingParams::operator==(const TimingParams& aOther) const
|
||||
// from other timing parameters.
|
||||
return mDuration == aOther.mDuration &&
|
||||
mDelay == aOther.mDelay &&
|
||||
mEndDelay == aOther.mEndDelay &&
|
||||
mIterations == aOther.mIterations &&
|
||||
mIterationStart == aOther.mIterationStart &&
|
||||
mDirection == aOther.mDirection &&
|
||||
|
@ -15,8 +15,8 @@
|
||||
#include "mozilla/StickyTimeDuration.h"
|
||||
#include "mozilla/TimeStamp.h" // for TimeDuration
|
||||
|
||||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for FillMode
|
||||
// and PlaybackDirection
|
||||
#include "mozilla/dom/AnimationEffectBinding.h" // for FillMode
|
||||
// and PlaybackDirection
|
||||
|
||||
class nsIDocument;
|
||||
|
||||
@ -75,6 +75,21 @@ struct TimingParams
|
||||
static TimingParams FromOptionsUnion(
|
||||
const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
nsIDocument* aDocument, ErrorResult& aRv);
|
||||
static TimingParams FromEffectTiming(
|
||||
const dom::EffectTiming& aEffectTiming,
|
||||
nsIDocument* aDocument,
|
||||
ErrorResult& aRv);
|
||||
// Returns a copy of |aSource| where each timing property in |aSource| that
|
||||
// is also specified in |aEffectTiming| is replaced with the value from
|
||||
// |aEffectTiming|.
|
||||
//
|
||||
// If any of the values in |aEffectTiming| are invalid, |aRv.Failed()| will be
|
||||
// true and an unmodified copy of |aSource| will be returned.
|
||||
static TimingParams MergeOptionalEffectTiming(
|
||||
const TimingParams& aSource,
|
||||
const dom::OptionalEffectTiming& aEffectTiming,
|
||||
nsIDocument* aDocument,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Range-checks and validates an UnrestrictedDoubleOrString or
|
||||
// OwningUnrestrictedDoubleOrString object and converts to a
|
||||
|
@ -12,14 +12,11 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'Animation.h',
|
||||
'AnimationEffectReadOnly.h',
|
||||
'AnimationEffectTiming.h',
|
||||
'AnimationEffectTimingReadOnly.h',
|
||||
'AnimationEffect.h',
|
||||
'AnimationTimeline.h',
|
||||
'CSSPseudoElement.h',
|
||||
'DocumentTimeline.h',
|
||||
'KeyframeEffect.h',
|
||||
'KeyframeEffectReadOnly.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
@ -43,9 +40,7 @@ EXPORTS.mozilla += [
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'Animation.cpp',
|
||||
'AnimationEffectReadOnly.cpp',
|
||||
'AnimationEffectTiming.cpp',
|
||||
'AnimationEffectTimingReadOnly.cpp',
|
||||
'AnimationEffect.cpp',
|
||||
'AnimationEventDispatcher.cpp',
|
||||
'AnimationPerformanceWarning.cpp',
|
||||
'AnimationTimeline.cpp',
|
||||
@ -56,7 +51,6 @@ UNIFIED_SOURCES += [
|
||||
'EffectCompositor.cpp',
|
||||
'EffectSet.cpp',
|
||||
'KeyframeEffect.cpp',
|
||||
'KeyframeEffectReadOnly.cpp',
|
||||
'KeyframeUtils.cpp',
|
||||
'PendingAnimationTracker.cpp',
|
||||
'TimingParams.cpp',
|
||||
|
@ -6,7 +6,7 @@
|
||||
Element.prototype.animate = function() {
|
||||
throw 'Called animate() as defined in content document';
|
||||
}
|
||||
for (let name of ["KeyframeEffect", "KeyframeEffectReadOnly", "Animation"]) {
|
||||
for (let name of ["KeyframeEffect", "Animation"]) {
|
||||
this[name] = function() {
|
||||
throw `Called overridden ${name} constructor`;
|
||||
};
|
||||
|
@ -106,32 +106,34 @@ function runTest() {
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation is added");
|
||||
|
||||
anim.effect.timing.duration = 100 * MS_PER_SEC;
|
||||
anim.effect.updateTiming({ duration: 100 * MS_PER_SEC });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [anim], removed: [] }],
|
||||
"records after duration is changed");
|
||||
|
||||
anim.effect.timing.duration = 100 * MS_PER_SEC;
|
||||
anim.effect.updateTiming({ duration: 100 * MS_PER_SEC });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "records after assigning same value");
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
anim.currentTime = anim.effect.getComputedTiming().duration * 2;
|
||||
anim.finish();
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [], removed: [anim] }],
|
||||
"records after animation end");
|
||||
|
||||
anim.effect.timing.duration = anim.effect.timing.duration * 3;
|
||||
anim.effect.updateTiming({
|
||||
duration: anim.effect.getComputedTiming().duration * 3
|
||||
});
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation restarted");
|
||||
|
||||
anim.effect.timing.duration = "auto";
|
||||
anim.effect.updateTiming({ duration: 'auto' });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [], removed: [anim] }],
|
||||
"records after duration set \"auto\"");
|
||||
|
||||
anim.effect.timing.duration = "auto";
|
||||
anim.effect.updateTiming({ duration: 'auto' });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "records after assigning same value \"auto\"");
|
||||
}, "change_duration_and_currenttime");
|
||||
@ -149,12 +151,12 @@ function runTest() {
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation is added");
|
||||
|
||||
anim.effect.timing.endDelay = 10 * MS_PER_SEC;
|
||||
anim.effect.updateTiming({ endDelay: 10 * MS_PER_SEC });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [anim], removed: [] }],
|
||||
"records after endDelay is changed");
|
||||
|
||||
anim.effect.timing.endDelay = 10 * MS_PER_SEC;
|
||||
anim.effect.updateTiming({ endDelay: 10 * MS_PER_SEC });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "records after assigning same value");
|
||||
|
||||
@ -163,7 +165,7 @@ function runTest() {
|
||||
[{ added: [], changed: [], removed: [anim] }],
|
||||
"records after currentTime during endDelay");
|
||||
|
||||
anim.effect.timing.endDelay = -110 * MS_PER_SEC;
|
||||
anim.effect.updateTiming({ endDelay: -110 * MS_PER_SEC });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "records after assigning negative value");
|
||||
}, "change_enddelay_and_currenttime");
|
||||
@ -195,21 +197,21 @@ function runTest() {
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation is added");
|
||||
|
||||
anim.effect.timing.iterations = 2;
|
||||
anim.effect.updateTiming({ iterations: 2 });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [anim], removed: [] }],
|
||||
"records after iterations is changed");
|
||||
|
||||
anim.effect.timing.iterations = 2;
|
||||
anim.effect.updateTiming({ iterations: 2 });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "records after assigning same value");
|
||||
|
||||
anim.effect.timing.iterations = 0;
|
||||
anim.effect.updateTiming({ iterations: 0 });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [], removed: [anim] }],
|
||||
"records after animation end");
|
||||
|
||||
anim.effect.timing.iterations = Infinity;
|
||||
anim.effect.updateTiming({ iterations: Infinity });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation restarted");
|
||||
@ -228,21 +230,21 @@ function runTest() {
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation is added");
|
||||
|
||||
anim.effect.timing.delay = 100;
|
||||
anim.effect.updateTiming({ delay: 100 });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [anim], removed: [] }],
|
||||
"records after delay is changed");
|
||||
|
||||
anim.effect.timing.delay = 100;
|
||||
anim.effect.updateTiming({ delay: 100 });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "records after assigning same value");
|
||||
|
||||
anim.effect.timing.delay = -100 * MS_PER_SEC;
|
||||
anim.effect.updateTiming({ delay: -100 * MS_PER_SEC });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [], removed: [anim] }],
|
||||
"records after animation end");
|
||||
|
||||
anim.effect.timing.delay = 0;
|
||||
anim.effect.updateTiming({ delay: 0 });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation restarted");
|
||||
@ -263,12 +265,12 @@ function runTest() {
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation is added");
|
||||
|
||||
anim.effect.timing.easing = "steps(2, end)";
|
||||
anim.effect.updateTiming({ easing: "steps(2, end)" });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [anim], removed: [] }],
|
||||
"records after easing is changed");
|
||||
|
||||
anim.effect.timing.easing = "steps(2, end)";
|
||||
anim.effect.updateTiming({ easing: "steps(2, end)" });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "records after assigning same value");
|
||||
}, "change_easing");
|
||||
@ -293,9 +295,9 @@ function runTest() {
|
||||
aOptions.subtree ? div.parentNode : div,
|
||||
aOptions.subtree);
|
||||
|
||||
var effect = new KeyframeEffectReadOnly(null,
|
||||
{ opacity: [ 0, 1 ] },
|
||||
{ duration: 100 * MS_PER_SEC });
|
||||
var effect = new KeyframeEffect(null,
|
||||
{ opacity: [ 0, 1 ] },
|
||||
{ duration: 100 * MS_PER_SEC });
|
||||
var anim = new Animation(effect, document.timeline);
|
||||
anim.play();
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
@ -1525,32 +1527,34 @@ function runTest() {
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation is added");
|
||||
|
||||
anim.effect.timing.duration = 100 * MS_PER_SEC;
|
||||
anim.effect.updateTiming({ duration: 100 * MS_PER_SEC });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [anim], removed: [] }],
|
||||
"records after duration is changed");
|
||||
|
||||
anim.effect.timing.duration = 100 * MS_PER_SEC;
|
||||
anim.effect.updateTiming({ duration: 100 * MS_PER_SEC });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "records after assigning same value");
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
anim.currentTime = anim.effect.getComputedTiming().duration * 2;
|
||||
anim.finish();
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [], removed: [anim] }],
|
||||
"records after animation end");
|
||||
|
||||
anim.effect.timing.duration = anim.effect.timing.duration * 3;
|
||||
anim.effect.updateTiming({
|
||||
duration: anim.effect.getComputedTiming().duration * 3
|
||||
});
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [anim], changed: [], removed: [] }],
|
||||
"records after animation restarted");
|
||||
|
||||
anim.effect.timing.duration = "auto";
|
||||
anim.effect.updateTiming({ duration: "auto" });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[{ added: [], changed: [], removed: [anim] }],
|
||||
"records after duration set \"auto\"");
|
||||
|
||||
anim.effect.timing.duration = "auto";
|
||||
anim.effect.updateTiming({ duration: "auto" });
|
||||
assert_equals_records(observer.takeRecords(),
|
||||
[], "records after assigning same value \"auto\"");
|
||||
}, "change_duration_and_currenttime_on_pseudo_elements");
|
||||
|
@ -2,7 +2,7 @@
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>Bug 1254419 - Test the values returned by
|
||||
KeyframeEffectReadOnly.getProperties()</title>
|
||||
KeyframeEffect.getProperties()</title>
|
||||
<script type="application/javascript" src="../testharness.js"></script>
|
||||
<script type="application/javascript" src="../testharnessreport.js"></script>
|
||||
<script type="application/javascript" src="../testcommon.js"></script>
|
||||
|
@ -320,13 +320,13 @@ promise_test(async t => {
|
||||
'Animation reports that it is running on the compositor');
|
||||
|
||||
animation.currentTime = 150 * MS_PER_SEC;
|
||||
animation.effect.timing.duration = 100 * MS_PER_SEC;
|
||||
animation.effect.updateTiming({ duration: 100 * MS_PER_SEC });
|
||||
|
||||
assert_animation_is_not_running_on_compositor(animation,
|
||||
'Animation reports that it is NOT running on the compositor'
|
||||
+ ' when the animation is set a shorter duration than current time');
|
||||
}, 'animation is immediately removed from compositor' +
|
||||
'when timing.duration is made shorter than the current time');
|
||||
'when the duration is made shorter than the current time');
|
||||
|
||||
promise_test(async t => {
|
||||
var animation = addDivAndAnimate(t,
|
||||
@ -344,14 +344,14 @@ promise_test(async t => {
|
||||
'Animation reports that it is NOT running on the compositor'
|
||||
+ ' when finished');
|
||||
|
||||
animation.effect.timing.duration = 1000 * MS_PER_SEC;
|
||||
animation.effect.updateTiming({ duration: 1000 * MS_PER_SEC });
|
||||
await waitForFrame();
|
||||
|
||||
assert_animation_is_running_on_compositor(animation,
|
||||
'Animation reports that it is running on the compositor'
|
||||
+ ' when restarted');
|
||||
}, 'animation is added to compositor' +
|
||||
' when timing.duration is made longer than the current time');
|
||||
' when the duration is made longer than the current time');
|
||||
|
||||
promise_test(async t => {
|
||||
var animation = addDivAndAnimate(t,
|
||||
@ -363,7 +363,7 @@ promise_test(async t => {
|
||||
assert_animation_is_running_on_compositor(animation,
|
||||
'Animation reports that it is running on the compositor');
|
||||
|
||||
animation.effect.timing.endDelay = 100 * MS_PER_SEC;
|
||||
animation.effect.updateTiming({ endDelay: 100 * MS_PER_SEC });
|
||||
|
||||
assert_animation_is_running_on_compositor(animation,
|
||||
'Animation reports that it is running on the compositor'
|
||||
@ -388,7 +388,7 @@ promise_test(async t => {
|
||||
assert_animation_is_running_on_compositor(animation,
|
||||
'Animation reports that it is running on the compositor');
|
||||
|
||||
animation.effect.timing.endDelay = -200 * MS_PER_SEC;
|
||||
animation.effect.updateTiming({ endDelay: -200 * MS_PER_SEC });
|
||||
await waitForFrame();
|
||||
|
||||
assert_animation_is_not_running_on_compositor(animation,
|
||||
@ -407,7 +407,7 @@ promise_test(async t => {
|
||||
assert_animation_is_running_on_compositor(animation,
|
||||
'Animation reports that it is running on the compositor');
|
||||
|
||||
animation.effect.timing.endDelay = -100 * MS_PER_SEC;
|
||||
animation.effect.updateTiming({ endDelay: -100 * MS_PER_SEC });
|
||||
await waitForFrame();
|
||||
|
||||
assert_animation_is_running_on_compositor(animation,
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script>
|
||||
var target = document.getElementById("target");
|
||||
var effect =
|
||||
new KeyframeEffectReadOnly(
|
||||
new KeyframeEffect(
|
||||
target,
|
||||
{ opacity: [0, 1] },
|
||||
{
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script>
|
||||
var target = document.getElementById("target");
|
||||
var effect =
|
||||
new KeyframeEffectReadOnly(
|
||||
new KeyframeEffect(
|
||||
target,
|
||||
{ opacity: [0, 1] },
|
||||
{
|
||||
|
@ -9,7 +9,7 @@
|
||||
<script>
|
||||
var target = document.getElementById("target");
|
||||
var effect =
|
||||
new KeyframeEffectReadOnly(
|
||||
new KeyframeEffect(
|
||||
target,
|
||||
{ color: ["red", "blue"] },
|
||||
{
|
||||
|
@ -9,7 +9,7 @@
|
||||
<script>
|
||||
var target = document.getElementById("target");
|
||||
var effect =
|
||||
new KeyframeEffectReadOnly(
|
||||
new KeyframeEffect(
|
||||
target,
|
||||
{ color: ["red", "blue"] },
|
||||
{
|
||||
|
@ -18,7 +18,7 @@
|
||||
<script>
|
||||
var target = document.getElementById("target");
|
||||
var effect =
|
||||
new KeyframeEffectReadOnly(
|
||||
new KeyframeEffect(
|
||||
target,
|
||||
{ opacity: [0, 1], easing: "step-end" },
|
||||
{
|
||||
|
@ -18,7 +18,7 @@
|
||||
<script>
|
||||
var target = document.getElementById("target");
|
||||
var effect =
|
||||
new KeyframeEffectReadOnly(
|
||||
new KeyframeEffect(
|
||||
target,
|
||||
{ opacity: [0, 1], easing: "step-end" },
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
</body>
|
||||
<script>
|
||||
var div = document.createElement('div');
|
||||
var effect = new KeyframeEffectReadOnly(div, { opacity: [0, 1] });
|
||||
var effect = new KeyframeEffect(div, { opacity: [0, 1] });
|
||||
requestAnimationFrame(() => {
|
||||
document.body.appendChild(div);
|
||||
document.documentElement.classList.remove("reftest-wait");
|
||||
|
@ -23,7 +23,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
{ duration: 1000, iterations: Infinity });
|
||||
requestAnimationFrame(() => {
|
||||
// Tweak animation to cause animation dirty bit to be set
|
||||
animation.effect.timing.duration = 2000;
|
||||
animation.effect.updateTiming({ duration: 2000 });
|
||||
ancestor.style.display = "none";
|
||||
getComputedStyle(ancestor).display;
|
||||
document.documentElement.className = '';
|
||||
|
@ -274,7 +274,7 @@ promise_test(function(t) {
|
||||
|
||||
test(function(t) {
|
||||
var div = addDiv(t);
|
||||
var effect = new KeyframeEffectReadOnly(div, {left: ["0px", "100px"]});
|
||||
var effect = new KeyframeEffect(div, {left: ["0px", "100px"]});
|
||||
|
||||
assert_equals(effect.getComputedTiming().localTime, null,
|
||||
'localTime for orphaned effect');
|
||||
@ -555,7 +555,7 @@ test(function(t) {
|
||||
|
||||
test(function(t) {
|
||||
var div = addDiv(t);
|
||||
var effect = new KeyframeEffectReadOnly(div, {left: ["0px", "100px"]});
|
||||
var effect = new KeyframeEffect(div, {left: ["0px", "100px"]});
|
||||
|
||||
assert_equals(effect.getComputedTiming().currentIteration, null,
|
||||
'currentIteration for orphaned effect');
|
||||
|
@ -39,9 +39,9 @@ test(function(t) {
|
||||
addStyle(t, { '.after::after': 'animation: anim 10s;' });
|
||||
var div = addDiv(t, { class: 'after' });
|
||||
var pseudoTarget = document.getAnimations()[0].effect.target;
|
||||
var effect = new KeyframeEffectReadOnly(pseudoTarget,
|
||||
{ background: ["blue", "red"] },
|
||||
3 * MS_PER_SEC);
|
||||
var effect = new KeyframeEffect(pseudoTarget,
|
||||
{ background: ["blue", "red"] },
|
||||
3 * MS_PER_SEC);
|
||||
var newAnim = new Animation(effect, document.timeline);
|
||||
newAnim.play();
|
||||
var anims = document.getAnimations();
|
||||
@ -52,7 +52,7 @@ test(function(t) {
|
||||
assert_equals(newAnim.effect.target, pseudoTarget,
|
||||
'The effect.target of the scripted-generated animation is ' +
|
||||
'the same as the one from the argument of ' +
|
||||
'KeyframeEffectReadOnly constructor');
|
||||
'KeyframeEffect constructor');
|
||||
assert_equals(anims[0].effect.target, newAnim.effect.target,
|
||||
'Both animations return the same target object');
|
||||
}, 'effect.target from the script-generated animation should return the same ' +
|
||||
|
@ -215,7 +215,7 @@ test(function(t) {
|
||||
assert_equals(getKeyframes(div).length, 0,
|
||||
"number of frames when @keyframes only has frames with " +
|
||||
"non-animatable properties");
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns no frames for various kinds'
|
||||
}, 'KeyframeEffect.getKeyframes() returns no frames for various kinds'
|
||||
+ ' of empty enimations');
|
||||
|
||||
test(function(t) {
|
||||
@ -236,7 +236,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for a simple'
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for a simple'
|
||||
+ ' animation');
|
||||
|
||||
test(function(t) {
|
||||
@ -253,7 +253,7 @@ test(function(t) {
|
||||
"value for 'easing' on ComputedKeyframe #" + i);
|
||||
}
|
||||
});
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns frames with expected easing'
|
||||
}, 'KeyframeEffect.getKeyframes() returns frames with expected easing'
|
||||
+ ' values, when the easing comes from animation-timing-function on the'
|
||||
+ ' element');
|
||||
|
||||
@ -270,7 +270,7 @@ test(function(t) {
|
||||
"value of 'easing' on ComputedKeyframe #1");
|
||||
assert_equals(frames[2].easing, "steps(1)",
|
||||
"value of 'easing' on ComputedKeyframe #2");
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns frames with expected easing'
|
||||
}, 'KeyframeEffect.getKeyframes() returns frames with expected easing'
|
||||
+ ' values, when the easing is specified on each keyframe');
|
||||
|
||||
test(function(t) {
|
||||
@ -286,7 +286,7 @@ test(function(t) {
|
||||
"value of 'easing' on ComputedKeyframe #1");
|
||||
assert_equals(frames[2].easing, "steps(1, start)",
|
||||
"value of 'easing' on ComputedKeyframe #2");
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns frames with expected easing'
|
||||
}, 'KeyframeEffect.getKeyframes() returns frames with expected easing'
|
||||
+ ' values, when the easing is specified on some keyframes');
|
||||
|
||||
test(function(t) {
|
||||
@ -309,7 +309,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for a simple'
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for a simple'
|
||||
+ ' animation that specifies a single shorthand property');
|
||||
|
||||
test(function(t) {
|
||||
@ -331,7 +331,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for an ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for an ' +
|
||||
'animation with a 0% keyframe and no 100% keyframe');
|
||||
|
||||
test(function(t) {
|
||||
@ -353,7 +353,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for an ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for an ' +
|
||||
'animation with a 100% keyframe and no 0% keyframe');
|
||||
|
||||
test(function(t) {
|
||||
@ -377,7 +377,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for an ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for an ' +
|
||||
'animation with no 0% or 100% keyframe but with a 50% keyframe');
|
||||
|
||||
test(function(t) {
|
||||
@ -399,7 +399,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for an ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for an ' +
|
||||
'animation with a partially complete 100% keyframe (because the ' +
|
||||
'!important rule is ignored)');
|
||||
|
||||
@ -425,7 +425,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for an ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for an ' +
|
||||
'animation with different properties on different keyframes, all ' +
|
||||
'with the same easing function');
|
||||
|
||||
@ -451,7 +451,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for an ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for an ' +
|
||||
'animation with different properties on different keyframes, with ' +
|
||||
'a different easing function on each');
|
||||
|
||||
@ -473,7 +473,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for an ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for an ' +
|
||||
'animation with multiple keyframes for the same time, and all with ' +
|
||||
'the same easing function');
|
||||
|
||||
@ -498,7 +498,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for an ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for an ' +
|
||||
'animation with multiple keyframes for the same time and with ' +
|
||||
'different easing functions');
|
||||
|
||||
@ -522,7 +522,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for an ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for an ' +
|
||||
'animation with multiple keyframes for the same time and with ' +
|
||||
'different but equivalent easing functions');
|
||||
|
||||
@ -552,7 +552,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for ' +
|
||||
'overlapping keyframes');
|
||||
|
||||
// Gecko-specific test case: We are specifically concerned here that the
|
||||
@ -576,7 +576,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected values for ' +
|
||||
'animations with filter properties and missing keyframes');
|
||||
|
||||
test(function(t) {
|
||||
@ -597,7 +597,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected values for ' +
|
||||
'animation with drop-shadow of filter property');
|
||||
|
||||
// Gecko-specific test case: We are specifically concerned here that the
|
||||
@ -627,7 +627,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected values for ' +
|
||||
'animations with text-shadow properties and missing keyframes');
|
||||
|
||||
// Gecko-specific test case: We are specifically concerned here that the
|
||||
@ -663,7 +663,7 @@ test(function(t) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i
|
||||
+ " after updating current style");
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected values for ' +
|
||||
'animations with background-size properties and missing keyframes');
|
||||
|
||||
test(function(t) {
|
||||
@ -683,7 +683,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected values for ' +
|
||||
'animations with CSS variables as keyframe values');
|
||||
|
||||
test(function(t) {
|
||||
@ -709,7 +709,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected values for ' +
|
||||
'animations with CSS variables as keyframe values in a shorthand property');
|
||||
|
||||
test(function(t) {
|
||||
@ -729,7 +729,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected values for ' +
|
||||
'animations with a CSS variable which is overriden by the value in keyframe');
|
||||
|
||||
test(function(t) {
|
||||
@ -749,7 +749,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected values for ' +
|
||||
'animations with only custom property in a keyframe');
|
||||
|
||||
</script>
|
||||
|
@ -45,9 +45,9 @@ test(function(t) {
|
||||
|
||||
// Create additional animation on the pseudo-element from script
|
||||
var pseudoTarget = document.getAnimations()[0].effect.target;
|
||||
var effect = new KeyframeEffectReadOnly(pseudoTarget,
|
||||
{ background: ["blue", "red"] },
|
||||
3 * MS_PER_SEC);
|
||||
var effect = new KeyframeEffect(pseudoTarget,
|
||||
{ background: ["blue", "red"] },
|
||||
3 * MS_PER_SEC);
|
||||
var newAnimation = new Animation(effect, document.timeline);
|
||||
newAnimation.id = 'scripted-anim';
|
||||
newAnimation.play();
|
||||
|
@ -43,9 +43,9 @@ test(function(t) {
|
||||
flushComputedStyle(div);
|
||||
div.classList.add('change');
|
||||
var pseudoTarget = document.getAnimations()[0].effect.target;
|
||||
var effect = new KeyframeEffectReadOnly(pseudoTarget,
|
||||
{ background: ["blue", "red"] },
|
||||
3000);
|
||||
var effect = new KeyframeEffect(pseudoTarget,
|
||||
{ background: ["blue", "red"] },
|
||||
3000);
|
||||
var newAnim = new Animation(effect, document.timeline);
|
||||
newAnim.play();
|
||||
|
||||
@ -57,7 +57,7 @@ test(function(t) {
|
||||
assert_equals(newAnim.effect.target, pseudoTarget,
|
||||
'The effect.target of the scripted-generated animation is ' +
|
||||
'the same as the one from the argument of ' +
|
||||
'KeyframeEffectReadOnly constructor');
|
||||
'KeyframeEffect constructor');
|
||||
assert_equals(anims[0].effect.target, newAnim.effect.target,
|
||||
'Both the transition and the scripted-generated animation ' +
|
||||
'return the same target object');
|
||||
|
@ -350,8 +350,8 @@ promise_test(t => {
|
||||
setupTransition(t, 'margin-left 100s 100s');
|
||||
|
||||
return watcher.wait_for('transitionrun').then(evt => {
|
||||
// We can't set the end delay via generated effect timing.
|
||||
// Because CSS-Transition use the AnimationEffectTimingReadOnly.
|
||||
// We can't set the end delay via generated effect timing
|
||||
// because mutating CSS transitions is not specced yet.
|
||||
transition.effect = new KeyframeEffect(div,
|
||||
{ marginleft: [ '0px', '100px' ]},
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
|
@ -48,7 +48,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for a simple'
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for a simple'
|
||||
+ ' transition');
|
||||
|
||||
test(function(t) {
|
||||
@ -73,7 +73,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for a simple'
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for a simple'
|
||||
+ ' transition with a non-default easing function');
|
||||
|
||||
test(function(t) {
|
||||
@ -96,7 +96,7 @@ test(function(t) {
|
||||
for (var i = 0; i < frames.length; i++) {
|
||||
assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
|
||||
}
|
||||
}, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for a'
|
||||
}, 'KeyframeEffect.getKeyframes() returns expected frames for a'
|
||||
+ ' transition with a CSS variable endpoint');
|
||||
|
||||
</script>
|
||||
|
@ -1149,11 +1149,11 @@ waitForAllPaints(() => {
|
||||
ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
|
||||
|
||||
// Extend the duration.
|
||||
animation.effect.timing.duration = 800 * MS_PER_SEC;
|
||||
animation.effect.updateTiming({ duration: 800 * MS_PER_SEC });
|
||||
var markers = await observeStyling(5);
|
||||
is(markers.length, 1,
|
||||
'Animations running on the compositor should update style ' +
|
||||
'when timing.duration is made longer than the current time');
|
||||
'when duration is made longer than the current time');
|
||||
|
||||
await ensureElementRemoval(div);
|
||||
});
|
||||
|
@ -25,23 +25,23 @@ test(function(t) {
|
||||
var div = addDiv(t);
|
||||
var anim = div.animate({ }, 100 * MS_PER_SEC);
|
||||
|
||||
anim.effect.timing.easing = 'cubic-bezier(0, 1e+39, 0, 0)';
|
||||
assert_equals(anim.effect.timing.easing,
|
||||
anim.effect.updateTiming({ easing: 'cubic-bezier(0, 1e+39, 0, 0)' });
|
||||
assert_equals(anim.effect.getComputedTiming().easing,
|
||||
'cubic-bezier(0, ' + max_float + ', 0, 0)',
|
||||
'y1 control point for effect easing is out of upper boundary');
|
||||
|
||||
anim.effect.timing.easing = 'cubic-bezier(0, 0, 0, 1e+39)';
|
||||
assert_equals(anim.effect.timing.easing,
|
||||
anim.effect.updateTiming({ easing: 'cubic-bezier(0, 0, 0, 1e+39)' });
|
||||
assert_equals(anim.effect.getComputedTiming().easing,
|
||||
'cubic-bezier(0, 0, 0, ' + max_float + ')',
|
||||
'y2 control point for effect easing is out of upper boundary');
|
||||
|
||||
anim.effect.timing.easing = 'cubic-bezier(0, -1e+39, 0, 0)';
|
||||
assert_equals(anim.effect.timing.easing,
|
||||
anim.effect.updateTiming({ easing: 'cubic-bezier(0, -1e+39, 0, 0)' });
|
||||
assert_equals(anim.effect.getComputedTiming().easing,
|
||||
'cubic-bezier(0, ' + -max_float + ', 0, 0)',
|
||||
'y1 control point for effect easing is out of lower boundary');
|
||||
|
||||
anim.effect.timing.easing = 'cubic-bezier(0, 0, 0, -1e+39)';
|
||||
assert_equals(anim.effect.timing.easing,
|
||||
anim.effect.updateTiming({ easing: 'cubic-bezier(0, 0, 0, -1e+39)' });
|
||||
assert_equals(anim.effect.getComputedTiming().easing,
|
||||
'cubic-bezier(0, 0, 0, ' + -max_float + ')',
|
||||
'y2 control point for effect easing is out of lower boundary');
|
||||
|
||||
@ -144,7 +144,7 @@ test(function(t) {
|
||||
|
||||
anim.pause();
|
||||
// The positive steepest function on both edges.
|
||||
anim.effect.timing.easing = 'cubic-bezier(0, 1e+39, 0, 1e+39)';
|
||||
anim.effect.updateTiming({ easing: 'cubic-bezier(0, 1e+39, 0, 1e+39)' });
|
||||
assert_equals(anim.effect.getComputedTiming().progress, 0.0,
|
||||
'progress on lower edge for the highest value of y1 and y2 control points');
|
||||
|
||||
@ -153,7 +153,7 @@ test(function(t) {
|
||||
'progress on upper edge for the highest value of y1 and y2 control points');
|
||||
|
||||
// The negative steepest function on both edges.
|
||||
anim.effect.timing.easing = 'cubic-bezier(0, -1e+39, 0, -1e+39)';
|
||||
anim.effect.updateTiming({ easing: 'cubic-bezier(0, -1e+39, 0, -1e+39)' });
|
||||
anim.currentTime = 0;
|
||||
assert_equals(anim.effect.getComputedTiming().progress, 0.0,
|
||||
'progress on lower edge for the lowest value of y1 and y2 control points');
|
||||
|
@ -18,7 +18,7 @@ test(function(t) {
|
||||
|
||||
const contentScript = function() {
|
||||
try {
|
||||
document.getAnimations()[0].effect.timing.easing = "linear";
|
||||
document.getAnimations()[0].effect.updateTiming({ easing: 'linear' });
|
||||
assert_true(true, 'Setting easing should not throw in sandbox');
|
||||
} catch (e) {
|
||||
assert_unreached('Setting easing threw ' + e);
|
||||
|
@ -16,9 +16,9 @@
|
||||
test(function(t) {
|
||||
var target = addDiv(t);
|
||||
var anim = new Animation();
|
||||
anim.effect = new KeyframeEffectReadOnly(target,
|
||||
{ marginLeft: [ '0px', '100px' ] },
|
||||
100 * MS_PER_SEC);
|
||||
anim.effect = new KeyframeEffect(target,
|
||||
{ marginLeft: [ '0px', '100px' ] },
|
||||
100 * MS_PER_SEC);
|
||||
anim.currentTime = 50 * MS_PER_SEC;
|
||||
assert_equals(getComputedStyle(target).marginLeft, '50px');
|
||||
}, 'After setting target effect on an animation with null effect, the ' +
|
||||
|
@ -213,8 +213,10 @@ promise_test(t => {
|
||||
|
||||
return waitForPaintsFlushed();
|
||||
}).then(() => {
|
||||
lowerAnimation.effect.timing.duration = 0;
|
||||
lowerAnimation.effect.timing.fill = 'forwards';
|
||||
lowerAnimation.effect.updateTiming({
|
||||
duration: 0,
|
||||
fill: 'forwards',
|
||||
});
|
||||
return waitForPaintsFlushed();
|
||||
}).then(() => {
|
||||
SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
|
||||
|
@ -136,8 +136,8 @@
|
||||
#include "mozilla/dom/CSSPseudoElement.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/ElementBinding.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/dom/MouseEventBinding.h"
|
||||
#include "mozilla/dom/WindowBinding.h"
|
||||
#include "mozilla/dom/VRDisplay.h"
|
||||
@ -3776,7 +3776,7 @@ Element::GetAnimationsUnsorted(Element* aElement,
|
||||
return;
|
||||
}
|
||||
|
||||
for (KeyframeEffectReadOnly* effect : *effects) {
|
||||
for (KeyframeEffect* effect : *effects) {
|
||||
MOZ_ASSERT(effect && effect->GetAnimation(),
|
||||
"Only effects associated with an animation should be "
|
||||
"added to an element's effect set");
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
@ -380,13 +380,12 @@ void
|
||||
nsAnimationReceiver::RecordAnimationMutation(Animation* aAnimation,
|
||||
AnimationMutation aMutationType)
|
||||
{
|
||||
mozilla::dom::AnimationEffectReadOnly* effect = aAnimation->GetEffect();
|
||||
mozilla::dom::AnimationEffect* effect = aAnimation->GetEffect();
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::dom::KeyframeEffectReadOnly* keyframeEffect =
|
||||
effect->AsKeyframeEffect();
|
||||
mozilla::dom::KeyframeEffect* keyframeEffect = effect->AsKeyframeEffect();
|
||||
if (!keyframeEffect) {
|
||||
return;
|
||||
}
|
||||
|
@ -9967,10 +9967,13 @@ nsIDocument::CaretPositionFromPoint(float aX, float aY)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// GetContentOffsetsFromPoint requires frame-relative coordinates, so we need
|
||||
// to adjust to frame-relative coordinates before we can perform this call.
|
||||
// It should also not take into account the padding of the frame.
|
||||
nsPoint adjustedPoint = pt - ptFrame->GetOffsetTo(rootFrame);
|
||||
// We require frame-relative coordinates for GetContentOffsetsFromPoint.
|
||||
nsPoint aOffset;
|
||||
nsCOMPtr<nsIWidget> widget = nsContentUtils::GetWidget(ps, &aOffset);
|
||||
LayoutDeviceIntPoint refPoint =
|
||||
nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), aOffset, GetPresContext());
|
||||
nsPoint adjustedPoint =
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(widget, refPoint, ptFrame);
|
||||
|
||||
nsFrame::ContentOffsets offsets =
|
||||
ptFrame->GetContentOffsetsFromPoint(adjustedPoint);
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/dom/HTMLImageElement.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
#include "nsDOMMutationObserver.h"
|
||||
@ -235,7 +235,7 @@ nsNodeUtils::ContentRemoved(nsINode* aContainer,
|
||||
Maybe<NonOwningAnimationTarget>
|
||||
nsNodeUtils::GetTargetForAnimation(const Animation* aAnimation)
|
||||
{
|
||||
AnimationEffectReadOnly* effect = aAnimation->GetEffect();
|
||||
AnimationEffect* effect = aAnimation->GetEffect();
|
||||
if (!effect || !effect->AsKeyframeEffect()) {
|
||||
return Nothing();
|
||||
}
|
||||
|
@ -105,6 +105,12 @@
|
||||
Math.round(test6Rect.top + (test6Rect.height / 2)),
|
||||
5, "test6");
|
||||
|
||||
// Check the first and last characters of the transformed div.
|
||||
var test7Element = document.getElementById('test7');
|
||||
var test7Rect = test7Element.getBoundingClientRect();
|
||||
checkOffsetsFromPoint(Math.round(test7Rect.left + 1), Math.round(test7Rect.top + 1), 0, 'test7');
|
||||
checkOffsetsFromPoint(Math.round(test7Rect.right - 1), Math.round(test7Rect.top + 1), 13, 'test7');
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
@ -116,6 +122,8 @@
|
||||
<span id="test2" style="color: blue;">abc, abc, abc</span><br>
|
||||
<textarea id="test3">abc</textarea><input id="test4" value="abcdef"><br><br>
|
||||
<marquee>marquee</marquee>
|
||||
<!-- Translate test7 while staying within confines of the test viewport -->
|
||||
<div id="test7" style="transform: translate(140px, -20px); display: inline-block;">abc, abc, abc</div>
|
||||
</div>
|
||||
<input id="test5" value="The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly down, so suddenly that Alice had not a moment to think about stopping herself before she found herself falling down a very deep well. Either the well was very deep, or she fell very slowly, for she had plenty of time as she went down to look about her and to wonder what was going to happen next. First, she tried to look down and make out what she was coming to, but it was too dark to see anything; then she looked at the sides of the well, and noticed that they were filled with cupboards and book-shelves; here and there she saw maps and pictures hung upon pegs. She took down a jar from one of the shelves as she passed; it was labelled `ORANGE MARMALADE', but to her great disappointment it was empty: she did not like to drop the jar for fear of killing somebody, so managed to put it into one of the cupboards as she fell past it." type="text">
|
||||
<input id="test6" type="number" style="width:150px; height:57px;" value="31415"><br>
|
||||
|
@ -58,7 +58,7 @@ DOMInterfaces = {
|
||||
'concrete': False
|
||||
},
|
||||
|
||||
'AnimationEffectReadOnly': {
|
||||
'AnimationEffect': {
|
||||
'concrete': False
|
||||
},
|
||||
|
||||
|
@ -103,8 +103,6 @@ namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
|
||||
//#define DEBUG_DOCSHELL_FOCUS
|
||||
|
||||
static const LayoutDeviceIntPoint kInvalidRefPoint = LayoutDeviceIntPoint(-1,-1);
|
||||
|
||||
static uint32_t gMouseOrKeyboardEventCounter = 0;
|
||||
@ -122,66 +120,6 @@ RoundDown(double aDouble)
|
||||
static_cast<int32_t>(ceil(aDouble));
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DOCSHELL_FOCUS
|
||||
static void
|
||||
PrintDocTree(nsIDocShellTreeItem* aParentItem, int aLevel)
|
||||
{
|
||||
for (int32_t i=0;i<aLevel;i++) printf(" ");
|
||||
|
||||
int32_t childWebshellCount;
|
||||
aParentItem->GetChildCount(&childWebshellCount);
|
||||
nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentItem));
|
||||
int32_t type = aParentItem->ItemType();
|
||||
nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell();
|
||||
RefPtr<nsPresContext> presContext;
|
||||
parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
|
||||
nsCOMPtr<nsIContentViewer> cv;
|
||||
parentAsDocShell->GetContentViewer(getter_AddRefs(cv));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
if (cv)
|
||||
cv->GetDOMDocument(getter_AddRefs(domDoc));
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
|
||||
nsCOMPtr<nsIDOMWindow> domwin = doc ? doc->GetWindow() : nullptr;
|
||||
nsIURI* uri = doc ? doc->GetDocumentURI() : nullptr;
|
||||
|
||||
printf("DS %p Type %s Cnt %d Doc %p DW %p EM %p%c",
|
||||
static_cast<void*>(parentAsDocShell.get()),
|
||||
type==nsIDocShellTreeItem::typeChrome?"Chrome":"Content",
|
||||
childWebshellCount, static_cast<void*>(doc.get()),
|
||||
static_cast<void*>(domwin.get()),
|
||||
static_cast<void*>(presContext ? presContext->EventStateManager() : nullptr),
|
||||
uri ? ' ' : '\n');
|
||||
if (uri) {
|
||||
nsAutoCString spec;
|
||||
uri->GetSpec(spec);
|
||||
printf("\"%s\"\n", spec.get());
|
||||
}
|
||||
|
||||
if (childWebshellCount > 0) {
|
||||
for (int32_t i = 0; i < childWebshellCount; i++) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> child;
|
||||
aParentItem->GetChildAt(i, getter_AddRefs(child));
|
||||
PrintDocTree(child, aLevel + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
PrintDocTreeAll(nsIDocShellTreeItem* aItem)
|
||||
{
|
||||
nsCOMPtr<nsIDocShellTreeItem> item = aItem;
|
||||
for(;;) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> parent;
|
||||
item->GetParent(getter_AddRefs(parent));
|
||||
if (!parent)
|
||||
break;
|
||||
item = parent;
|
||||
}
|
||||
|
||||
PrintDocTree(item, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************/
|
||||
/* mozilla::UITimerCallback */
|
||||
/******************************************************************/
|
||||
|
@ -14,6 +14,10 @@ const kMaxPaints = 10;
|
||||
add_task(async function() {
|
||||
let result, tabSwitchedPromise;
|
||||
|
||||
// We want to make sure that we will paint in cases where we need to. The
|
||||
// tab layer cache just gets in the way of measuring that.
|
||||
await SpecialPowers.pushPrefEnv({set: [["browser.tabs.remote.tabCacheSize", 0]]});
|
||||
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||
|
||||
let testTab = gBrowser.selectedTab;
|
||||
|
@ -1,5 +1,33 @@
|
||||
var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||
|
||||
function waitForPluginVisibility(browser, shouldBeVisible, errorMessage) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
let lastTransactionId = windowUtils.lastTransactionId;
|
||||
let listener = async (event) => {
|
||||
let visibility = await ContentTask.spawn(browser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
|
||||
if (visibility == shouldBeVisible) {
|
||||
window.removeEventListener("MozAfterPaint", listener);
|
||||
resolve();
|
||||
} else if (event && event.transactionId > lastTransactionId) {
|
||||
// We want to allow for one failed check since we call listener
|
||||
// directly, but if we get a MozAfterPaint notification and we
|
||||
// still don't have the correct visibility, that's likely a
|
||||
// problem.
|
||||
reject(new Error("MozAfterPaint had a mismatched plugin visibility"));
|
||||
}
|
||||
};
|
||||
window.addEventListener("MozAfterPaint", listener);
|
||||
listener(null);
|
||||
});
|
||||
}
|
||||
|
||||
// tests that we get plugin updates when we flip between tabs that
|
||||
// have the same plugin in the same position in the page.
|
||||
|
||||
@ -29,76 +57,44 @@ add_task(async function() {
|
||||
// plugin tab 2 should be selected
|
||||
is(gBrowser.selectedTab == pluginTab2, true, "plugin2 is selected");
|
||||
|
||||
result = await ContentTask.spawn(pluginTab1.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin1 is hidden");
|
||||
await waitForPluginVisibility(pluginTab1.linkedBrowser,
|
||||
false, "plugin1 should be hidden");
|
||||
|
||||
result = await ContentTask.spawn(pluginTab2.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, true, "plugin2 is visible");
|
||||
await waitForPluginVisibility(pluginTab2.linkedBrowser,
|
||||
true, "plugin2 should be visible");
|
||||
|
||||
// select plugin1 tab
|
||||
tabSwitchedPromise = waitTabSwitched();
|
||||
gBrowser.selectedTab = pluginTab1;
|
||||
await tabSwitchedPromise;
|
||||
|
||||
result = await ContentTask.spawn(pluginTab1.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, true, "plugin1 is visible");
|
||||
await waitForPluginVisibility(pluginTab1.linkedBrowser,
|
||||
true, "plugin1 should be visible");
|
||||
|
||||
result = await ContentTask.spawn(pluginTab2.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin2 is hidden");
|
||||
await waitForPluginVisibility(pluginTab2.linkedBrowser,
|
||||
false, "plugin2 should be hidden");
|
||||
|
||||
// select plugin2 tab
|
||||
tabSwitchedPromise = waitTabSwitched();
|
||||
gBrowser.selectedTab = pluginTab2;
|
||||
await tabSwitchedPromise;
|
||||
|
||||
result = await ContentTask.spawn(pluginTab1.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin1 is hidden");
|
||||
await waitForPluginVisibility(pluginTab1.linkedBrowser,
|
||||
false, "plugin1 should be hidden");
|
||||
|
||||
result = await ContentTask.spawn(pluginTab2.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, true, "plugin2 is visible");
|
||||
await waitForPluginVisibility(pluginTab2.linkedBrowser,
|
||||
true, "plugin2 should be visible");
|
||||
|
||||
// select test tab
|
||||
tabSwitchedPromise = waitTabSwitched();
|
||||
gBrowser.selectedTab = testTab;
|
||||
await tabSwitchedPromise;
|
||||
|
||||
result = await ContentTask.spawn(pluginTab1.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin1 is hidden");
|
||||
await waitForPluginVisibility(pluginTab1.linkedBrowser,
|
||||
false, "plugin1 should be hidden");
|
||||
|
||||
result = await ContentTask.spawn(pluginTab2.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin2 is hidden");
|
||||
await waitForPluginVisibility(pluginTab2.linkedBrowser,
|
||||
false, "plugin2 should be hidden");
|
||||
|
||||
gBrowser.removeTab(pluginTab1);
|
||||
gBrowser.removeTab(pluginTab2);
|
||||
|
@ -125,11 +125,7 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "Animation", insecureContext: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AnimationEffectReadOnly", insecureContext: true, release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AnimationEffectTiming", insecureContext: true, release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AnimationEffectTimingReadOnly", insecureContext: true, release: false},
|
||||
{name: "AnimationEffect", insecureContext: true, release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AnimationEvent", insecureContext: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -614,8 +610,6 @@ var interfaceNamesInGlobalScope =
|
||||
{name: "KeyEvent", insecureContext: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "KeyboardEvent", insecureContext: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "KeyframeEffectReadOnly", insecureContext: true, release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "KeyframeEffect", insecureContext: true, release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -13,12 +13,12 @@
|
||||
enum AnimationPlayState { "idle", "running", "paused", "finished" };
|
||||
|
||||
[Func="nsDocument::IsElementAnimateEnabled",
|
||||
Constructor (optional AnimationEffectReadOnly? effect = null,
|
||||
Constructor (optional AnimationEffect? effect = null,
|
||||
optional AnimationTimeline? timeline)]
|
||||
interface Animation : EventTarget {
|
||||
attribute DOMString id;
|
||||
[Func="nsDocument::IsWebAnimationsEnabled", Pure]
|
||||
attribute AnimationEffectReadOnly? effect;
|
||||
attribute AnimationEffect? effect;
|
||||
[Func="nsDocument::IsWebAnimationsEnabled"]
|
||||
attribute AnimationTimeline? timeline;
|
||||
[BinaryName="startTimeAsDouble"]
|
||||
|
@ -25,7 +25,7 @@ enum PlaybackDirection {
|
||||
"alternate-reverse"
|
||||
};
|
||||
|
||||
dictionary AnimationEffectTimingProperties {
|
||||
dictionary EffectTiming {
|
||||
double delay = 0.0;
|
||||
double endDelay = 0.0;
|
||||
FillMode fill = "auto";
|
||||
@ -36,7 +36,18 @@ dictionary AnimationEffectTimingProperties {
|
||||
DOMString easing = "linear";
|
||||
};
|
||||
|
||||
dictionary ComputedTimingProperties : AnimationEffectTimingProperties {
|
||||
dictionary OptionalEffectTiming {
|
||||
double delay;
|
||||
double endDelay;
|
||||
FillMode fill;
|
||||
double iterationStart;
|
||||
unrestricted double iterations;
|
||||
(unrestricted double or DOMString) duration;
|
||||
PlaybackDirection direction;
|
||||
DOMString easing;
|
||||
};
|
||||
|
||||
dictionary ComputedEffectTiming : EffectTiming {
|
||||
unrestricted double endTime = 0.0;
|
||||
unrestricted double activeDuration = 0.0;
|
||||
double? localTime = null;
|
||||
@ -45,9 +56,10 @@ dictionary ComputedTimingProperties : AnimationEffectTimingProperties {
|
||||
};
|
||||
|
||||
[Func="nsDocument::IsWebAnimationsEnabled"]
|
||||
interface AnimationEffectReadOnly {
|
||||
[Cached, Constant]
|
||||
readonly attribute AnimationEffectTimingReadOnly timing;
|
||||
interface AnimationEffect {
|
||||
EffectTiming getTiming();
|
||||
[BinaryName="getComputedTimingAsDict"]
|
||||
ComputedTimingProperties getComputedTiming();
|
||||
ComputedEffectTiming getComputedTiming();
|
||||
[Throws]
|
||||
void updateTiming(optional OptionalEffectTiming timing);
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://drafts.csswg.org/web-animations/#animationeffecttiming
|
||||
*
|
||||
* Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Func="nsDocument::IsWebAnimationsEnabled"]
|
||||
interface AnimationEffectTiming : AnimationEffectTimingReadOnly {
|
||||
inherit attribute double delay;
|
||||
inherit attribute double endDelay;
|
||||
inherit attribute FillMode fill;
|
||||
[SetterThrows]
|
||||
inherit attribute double iterationStart;
|
||||
[SetterThrows]
|
||||
inherit attribute unrestricted double iterations;
|
||||
[SetterThrows]
|
||||
inherit attribute (unrestricted double or DOMString) duration;
|
||||
inherit attribute PlaybackDirection direction;
|
||||
[SetterThrows]
|
||||
inherit attribute DOMString easing;
|
||||
};
|
@ -1,23 +0,0 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://drafts.csswg.org/web-animations/#animationeffecttimingreadonly
|
||||
*
|
||||
* Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Func="nsDocument::IsWebAnimationsEnabled"]
|
||||
interface AnimationEffectTimingReadOnly {
|
||||
readonly attribute double delay;
|
||||
readonly attribute double endDelay;
|
||||
readonly attribute FillMode fill;
|
||||
readonly attribute double iterationStart;
|
||||
readonly attribute unrestricted double iterations;
|
||||
readonly attribute (unrestricted double or DOMString) duration;
|
||||
readonly attribute PlaybackDirection direction;
|
||||
readonly attribute DOMString easing;
|
||||
};
|
@ -16,8 +16,8 @@
|
||||
enum CompositeOperation { "replace", "add", "accumulate" };
|
||||
|
||||
// The following dictionary types are not referred to by other .webidl files,
|
||||
// but we use it for manual JS->IDL and IDL->JS conversions in
|
||||
// KeyframeEffectReadOnly's implementation.
|
||||
// but we use it for manual JS->IDL and IDL->JS conversions in KeyframeEffect's
|
||||
// implementation.
|
||||
|
||||
dictionary BasePropertyIndexedKeyframe {
|
||||
(double? or sequence<double?>) offset = [];
|
||||
|
@ -15,27 +15,26 @@ enum IterationCompositeOperation {
|
||||
"accumulate"
|
||||
};
|
||||
|
||||
dictionary KeyframeEffectOptions : AnimationEffectTimingProperties {
|
||||
dictionary KeyframeEffectOptions : EffectTiming {
|
||||
IterationCompositeOperation iterationComposite = "replace";
|
||||
CompositeOperation composite = "replace";
|
||||
};
|
||||
|
||||
// KeyframeEffectReadOnly should run in the caller's compartment to do custom
|
||||
// KeyframeEffect should run in the caller's compartment to do custom
|
||||
// processing on the `keyframes` object.
|
||||
[Func="nsDocument::IsWebAnimationsEnabled",
|
||||
RunConstructorInCallerCompartment,
|
||||
Constructor ((Element or CSSPseudoElement)? target,
|
||||
object? keyframes,
|
||||
optional (unrestricted double or KeyframeEffectOptions) options),
|
||||
Constructor (KeyframeEffectReadOnly source)]
|
||||
interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
|
||||
readonly attribute (Element or CSSPseudoElement)? target;
|
||||
readonly attribute IterationCompositeOperation iterationComposite;
|
||||
readonly attribute CompositeOperation composite;
|
||||
|
||||
// We use object instead of ComputedKeyframe so that we can put the
|
||||
// property-value pairs on the object.
|
||||
[Throws] sequence<object> getKeyframes();
|
||||
Constructor (KeyframeEffect source)]
|
||||
interface KeyframeEffect : AnimationEffect {
|
||||
attribute (Element or CSSPseudoElement)? target;
|
||||
[NeedsCallerType]
|
||||
attribute IterationCompositeOperation iterationComposite;
|
||||
attribute CompositeOperation composite;
|
||||
[Throws] sequence<object> getKeyframes ();
|
||||
[Throws] void setKeyframes (object? keyframes);
|
||||
};
|
||||
|
||||
// Non-standard extensions
|
||||
@ -53,23 +52,6 @@ dictionary AnimationPropertyDetails {
|
||||
required sequence<AnimationPropertyValueDetails> values;
|
||||
};
|
||||
|
||||
partial interface KeyframeEffectReadOnly {
|
||||
partial interface KeyframeEffect {
|
||||
[ChromeOnly, Throws] sequence<AnimationPropertyDetails> getProperties();
|
||||
};
|
||||
|
||||
// KeyframeEffect should run in the caller's compartment to do custom
|
||||
// processing on the `keyframes` object.
|
||||
[Func="nsDocument::IsWebAnimationsEnabled",
|
||||
RunConstructorInCallerCompartment,
|
||||
Constructor ((Element or CSSPseudoElement)? target,
|
||||
object? keyframes,
|
||||
optional (unrestricted double or KeyframeEffectOptions) options),
|
||||
Constructor (KeyframeEffectReadOnly source)]
|
||||
interface KeyframeEffect : KeyframeEffectReadOnly {
|
||||
inherit attribute (Element or CSSPseudoElement)? target;
|
||||
[NeedsCallerType]
|
||||
inherit attribute IterationCompositeOperation iterationComposite;
|
||||
inherit attribute CompositeOperation composite;
|
||||
[Throws]
|
||||
void setKeyframes (object? keyframes);
|
||||
};
|
||||
|
@ -364,9 +364,7 @@ WEBIDL_FILES = [
|
||||
'AnalyserNode.webidl',
|
||||
'Animatable.webidl',
|
||||
'Animation.webidl',
|
||||
'AnimationEffectReadOnly.webidl',
|
||||
'AnimationEffectTiming.webidl',
|
||||
'AnimationEffectTimingReadOnly.webidl',
|
||||
'AnimationEffect.webidl',
|
||||
'AnimationEvent.webidl',
|
||||
'AnimationTimeline.webidl',
|
||||
'AnonymousContent.webidl',
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
#include "AnimationHelper.h"
|
||||
#include "mozilla/ComputedTimingFunction.h" // for ComputedTimingFunction
|
||||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for dom::FillMode
|
||||
#include "mozilla/dom/AnimationEffectBinding.h" // for dom::FillMode
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h" // for dom::IterationComposite
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h" // for dom::KeyFrameEffectReadOnly
|
||||
#include "mozilla/dom/KeyframeEffect.h" // for dom::KeyFrameEffectReadOnly
|
||||
#include "mozilla/dom/Nullable.h" // for dom::Nullable
|
||||
#include "mozilla/layers/CompositorThread.h" // for CompositorThreadHolder
|
||||
#include "mozilla/layers/LayerAnimationUtils.h" // for TimingFunctionToComputedTimingFunction
|
||||
@ -233,7 +233,7 @@ AnimationHelper::SampleAnimationForEachNode(
|
||||
.MultDouble(animation.playbackRate());
|
||||
|
||||
ComputedTiming computedTiming =
|
||||
dom::AnimationEffectReadOnly::GetComputedTimingAt(
|
||||
dom::AnimationEffect::GetComputedTimingAt(
|
||||
dom::Nullable<TimeDuration>(elapsedDuration), animData.mTiming,
|
||||
animation.playbackRate());
|
||||
|
||||
@ -254,7 +254,7 @@ AnimationHelper::SampleAnimationForEachNode(
|
||||
// FIXME Bug 1455476: We should do this optimizations for the case where
|
||||
// the layer has multiple animations.
|
||||
if (iEnd == 1 &&
|
||||
!dom::KeyframeEffectReadOnly::HasComputedTimingChanged(
|
||||
!dom::KeyframeEffect::HasComputedTimingChanged(
|
||||
computedTiming,
|
||||
iterCompositeOperation,
|
||||
animData.mProgressOnLastCompose,
|
||||
|
@ -204,6 +204,7 @@ nsDeviceContext::nsDeviceContext()
|
||||
mAppUnitsPerDevPixel(-1), mAppUnitsPerDevPixelAtUnitFullZoom(-1),
|
||||
mAppUnitsPerPhysicalInch(-1),
|
||||
mFullZoom(1.0f), mPrintingScale(1.0f),
|
||||
mPrintingTranslate(gfxPoint(0, 0)),
|
||||
mIsCurrentlyPrintingDoc(false)
|
||||
#ifdef DEBUG
|
||||
, mIsInitialized(false)
|
||||
@ -276,6 +277,7 @@ nsDeviceContext::SetDPI(double* aScale)
|
||||
if (mDeviceContextSpec) {
|
||||
dpi = mDeviceContextSpec->GetDPI();
|
||||
mPrintingScale = mDeviceContextSpec->GetPrintingScale();
|
||||
mPrintingTranslate = mDeviceContextSpec->GetPrintingTranslate();
|
||||
mAppUnitsPerDevPixelAtUnitFullZoom =
|
||||
NS_lround((AppUnitsPerCSSPixel() * 96) / dpi);
|
||||
} else {
|
||||
@ -414,6 +416,7 @@ nsDeviceContext::CreateRenderingContextCommon(bool aWantReferenceContext)
|
||||
MOZ_ASSERT(pContext); // already checked draw target above
|
||||
|
||||
gfxMatrix transform;
|
||||
transform.PreTranslate(mPrintingTranslate);
|
||||
if (mPrintTarget->RotateNeededForLandscape()) {
|
||||
// Rotate page 90 degrees to draw landscape page on portrait paper
|
||||
IntSize size = mPrintTarget->GetSize();
|
||||
|
@ -305,6 +305,7 @@ private:
|
||||
int32_t mAppUnitsPerPhysicalInch;
|
||||
float mFullZoom;
|
||||
float mPrintingScale;
|
||||
gfxPoint mPrintingTranslate;
|
||||
|
||||
RefPtr<nsFontCache> mFontCache;
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
|
@ -26,14 +26,16 @@ PrintTargetWindows::PrintTargetWindows(cairo_surface_t* aCairoSurface,
|
||||
/* static */ already_AddRefed<PrintTargetWindows>
|
||||
PrintTargetWindows::CreateOrNull(HDC aDC)
|
||||
{
|
||||
// Figure out the cairo surface size - Windows we need to use the printable
|
||||
// area of the page. Note: we only scale the printing using the LOGPIXELSY,
|
||||
// Figure out the paper size, the actual surface size will be the printable
|
||||
// area which is likely smaller, but the size here is later used to create the
|
||||
// draw target where the full page size is needed.
|
||||
// Note: we only scale the printing using the LOGPIXELSY,
|
||||
// so we use that when calculating the surface width as well as the height.
|
||||
int32_t heightDPI = ::GetDeviceCaps(aDC, LOGPIXELSY);
|
||||
float width =
|
||||
(::GetDeviceCaps(aDC, HORZRES) * POINTS_PER_INCH_FLOAT) / heightDPI;
|
||||
(::GetDeviceCaps(aDC, PHYSICALWIDTH) * POINTS_PER_INCH_FLOAT) / heightDPI;
|
||||
float height =
|
||||
(::GetDeviceCaps(aDC, VERTRES) * POINTS_PER_INCH_FLOAT) / heightDPI;
|
||||
(::GetDeviceCaps(aDC, PHYSICALHEIGHT) * POINTS_PER_INCH_FLOAT) / heightDPI;
|
||||
IntSize size = IntSize::Truncate(width, height);
|
||||
|
||||
if (!Factory::CheckSurfaceSize(size)) {
|
||||
|
@ -2506,8 +2506,16 @@ void
|
||||
gfxPlatform::InitWebRenderConfig()
|
||||
{
|
||||
bool prefEnabled = WebRenderPrefEnabled();
|
||||
bool envvarEnabled = WebRenderEnvvarEnabled();
|
||||
|
||||
ScopedGfxFeatureReporter reporter("WR", prefEnabled);
|
||||
// On Nightly:
|
||||
// WR? WR+ => means WR was enabled via gfx.webrender.all.qualified
|
||||
// WR! WR+ => means WR was enabled via gfx.webrender.{all,enabled} or envvar
|
||||
// On Beta/Release:
|
||||
// WR? WR+ => means WR was enabled via gfx.webrender.all.qualified on qualified hardware
|
||||
// WR! WR+ => means WR was enabled via envvar, possibly on unqualified hardware.
|
||||
// In all cases WR- means WR was not enabled, for one of many possible reasons.
|
||||
ScopedGfxFeatureReporter reporter("WR", prefEnabled || envvarEnabled);
|
||||
if (!XRE_IsParentProcess()) {
|
||||
// The parent process runs through all the real decision-making code
|
||||
// later in this function. For other processes we still want to report
|
||||
@ -2525,10 +2533,19 @@ gfxPlatform::InitWebRenderConfig()
|
||||
"WebRender is an opt-in feature",
|
||||
NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
|
||||
|
||||
if (prefEnabled) {
|
||||
featureWebRender.UserEnable("Force enabled by pref");
|
||||
} else if (WebRenderEnvvarEnabled()) {
|
||||
// envvar works everywhere; we need this for testing in CI. Sadly this allows
|
||||
// beta/release to enable it on unqualified hardware, but at least this is
|
||||
// harder for the average person than flipping a pref.
|
||||
if (envvarEnabled) {
|
||||
featureWebRender.UserEnable("Force enabled by envvar");
|
||||
|
||||
// gfx.webrender.enabled and gfx.webrender.all only work on nightly
|
||||
#ifdef NIGHTLY_BUILD
|
||||
} else if (prefEnabled) {
|
||||
featureWebRender.UserEnable("Force enabled by pref");
|
||||
#endif
|
||||
|
||||
// gfx.webrender.all.qualified works on all channels
|
||||
} else if (gfxPrefs::WebRenderAllQualified()) {
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
nsCString discardFailureId;
|
||||
|
@ -594,6 +594,7 @@ VRControllerOpenVR::ShutdownVibrateHapticThread()
|
||||
|
||||
VRSystemManagerOpenVR::VRSystemManagerOpenVR()
|
||||
: mVRSystem(nullptr)
|
||||
, mRuntimeCheckFailed(false)
|
||||
, mIsWindowsMR(false)
|
||||
{
|
||||
}
|
||||
@ -607,10 +608,6 @@ VRSystemManagerOpenVR::Create()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!::vr::VR_IsRuntimeInstalled()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<VRSystemManagerOpenVR> manager = new VRSystemManagerOpenVR();
|
||||
return manager.forget();
|
||||
}
|
||||
@ -659,33 +656,51 @@ VRSystemManagerOpenVR::NotifyVSync()
|
||||
void
|
||||
VRSystemManagerOpenVR::Enumerate()
|
||||
{
|
||||
if (mOpenVRHMD == nullptr && ::vr::VR_IsHmdPresent()) {
|
||||
::vr::HmdError err;
|
||||
|
||||
::vr::VR_Init(&err, ::vr::EVRApplicationType::VRApplication_Scene);
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
::vr::IVRSystem *system = (::vr::IVRSystem *)::vr::VR_GetGenericInterface(::vr::IVRSystem_Version, &err);
|
||||
if (err || !system) {
|
||||
::vr::VR_Shutdown();
|
||||
return;
|
||||
}
|
||||
::vr::IVRChaperone *chaperone = (::vr::IVRChaperone *)::vr::VR_GetGenericInterface(::vr::IVRChaperone_Version, &err);
|
||||
if (err || !chaperone) {
|
||||
::vr::VR_Shutdown();
|
||||
return;
|
||||
}
|
||||
::vr::IVRCompositor *compositor = (::vr::IVRCompositor*)::vr::VR_GetGenericInterface(::vr::IVRCompositor_Version, &err);
|
||||
if (err || !compositor) {
|
||||
::vr::VR_Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
mVRSystem = system;
|
||||
mOpenVRHMD = new VRDisplayOpenVR(system, chaperone, compositor);
|
||||
if (mOpenVRHMD) {
|
||||
// Already enumerated, nothing more to do
|
||||
return;
|
||||
}
|
||||
if (mRuntimeCheckFailed) {
|
||||
// We have already checked for a runtime and
|
||||
// know that its not installed.
|
||||
return;
|
||||
}
|
||||
if (!::vr::VR_IsRuntimeInstalled()) {
|
||||
// Runtime is not installed, remember so we don't
|
||||
// continue to scan for the files
|
||||
mRuntimeCheckFailed = true;
|
||||
return;
|
||||
}
|
||||
if (!::vr::VR_IsHmdPresent()) {
|
||||
// Avoid initializing if no headset is connected
|
||||
return;
|
||||
}
|
||||
|
||||
::vr::HmdError err;
|
||||
|
||||
::vr::VR_Init(&err, ::vr::EVRApplicationType::VRApplication_Scene);
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
::vr::IVRSystem *system = (::vr::IVRSystem *)::vr::VR_GetGenericInterface(::vr::IVRSystem_Version, &err);
|
||||
if (err || !system) {
|
||||
::vr::VR_Shutdown();
|
||||
return;
|
||||
}
|
||||
::vr::IVRChaperone *chaperone = (::vr::IVRChaperone *)::vr::VR_GetGenericInterface(::vr::IVRChaperone_Version, &err);
|
||||
if (err || !chaperone) {
|
||||
::vr::VR_Shutdown();
|
||||
return;
|
||||
}
|
||||
::vr::IVRCompositor *compositor = (::vr::IVRCompositor*)::vr::VR_GetGenericInterface(::vr::IVRCompositor_Version, &err);
|
||||
if (err || !compositor) {
|
||||
::vr::VR_Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
mVRSystem = system;
|
||||
mOpenVRHMD = new VRDisplayOpenVR(system, chaperone, compositor);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -170,6 +170,7 @@ private:
|
||||
RefPtr<impl::VRDisplayOpenVR> mOpenVRHMD;
|
||||
nsTArray<RefPtr<impl::VRControllerOpenVR>> mOpenVRController;
|
||||
::vr::IVRSystem *mVRSystem;
|
||||
bool mRuntimeCheckFailed;
|
||||
bool mIsWindowsMR;
|
||||
};
|
||||
|
||||
|
@ -134,16 +134,10 @@ private:
|
||||
|
||||
|
||||
TransactionBuilder::TransactionBuilder()
|
||||
: mUseSceneBuilderThread(gfxPrefs::WebRenderAsyncSceneBuild())
|
||||
{
|
||||
// We need the if statement to avoid miscompilation on windows, see
|
||||
// bug 1449982 comment 22.
|
||||
if (gfxPrefs::WebRenderAsyncSceneBuild()) {
|
||||
mTxn = wr_transaction_new(true);
|
||||
mResourceUpdates = wr_resource_updates_new();
|
||||
} else {
|
||||
mResourceUpdates = wr_resource_updates_new();
|
||||
mTxn = wr_transaction_new(false);
|
||||
}
|
||||
mTxn = wr_transaction_new(mUseSceneBuilderThread);
|
||||
mResourceUpdates = wr_resource_updates_new();
|
||||
}
|
||||
|
||||
TransactionBuilder::~TransactionBuilder()
|
||||
@ -366,7 +360,7 @@ void
|
||||
WebRenderAPI::SendTransaction(TransactionBuilder& aTxn)
|
||||
{
|
||||
wr_transaction_update_resources(aTxn.Raw(), aTxn.RawUpdates());
|
||||
wr_api_send_transaction(mDocHandle, aTxn.Raw());
|
||||
wr_api_send_transaction(mDocHandle, aTxn.Raw(), aTxn.UseSceneBuilderThread());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -138,9 +138,11 @@ public:
|
||||
|
||||
void Clear();
|
||||
|
||||
bool UseSceneBuilderThread() const { return mUseSceneBuilderThread; }
|
||||
Transaction* Raw() { return mTxn; }
|
||||
wr::ResourceUpdates* RawUpdates() { return mResourceUpdates; }
|
||||
protected:
|
||||
bool mUseSceneBuilderThread;
|
||||
Transaction* mTxn;
|
||||
wr::ResourceUpdates* mResourceUpdates;
|
||||
};
|
||||
|
@ -981,8 +981,7 @@ pub unsafe extern "C" fn wr_api_shut_down(dh: &mut DocumentHandle) {
|
||||
dh.api.shut_down();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_transaction_new(do_async: bool) -> *mut Transaction {
|
||||
fn make_transaction(do_async: bool) -> Transaction {
|
||||
let mut transaction = Transaction::new();
|
||||
// Ensure that we either use async scene building or not based on the
|
||||
// gecko pref, regardless of what the default is. We can remove this once
|
||||
@ -992,7 +991,12 @@ pub extern "C" fn wr_transaction_new(do_async: bool) -> *mut Transaction {
|
||||
} else {
|
||||
transaction.skip_scene_builder();
|
||||
}
|
||||
Box::into_raw(Box::new(transaction))
|
||||
transaction
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_transaction_new(do_async: bool) -> *mut Transaction {
|
||||
Box::into_raw(Box::new(make_transaction(do_async)))
|
||||
}
|
||||
|
||||
/// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
|
||||
@ -1290,12 +1294,14 @@ pub extern "C" fn wr_resource_updates_delete_image(
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_api_send_transaction(
|
||||
dh: &mut DocumentHandle,
|
||||
transaction: &mut Transaction
|
||||
transaction: &mut Transaction,
|
||||
is_async: bool
|
||||
) {
|
||||
if transaction.is_empty() {
|
||||
return;
|
||||
}
|
||||
let txn = mem::replace(transaction, Transaction::new());
|
||||
let new_txn = make_transaction(is_async);
|
||||
let txn = mem::replace(transaction, new_txn);
|
||||
dh.api.send_transaction(dh.document_id, txn);
|
||||
}
|
||||
|
||||
|
@ -1073,7 +1073,8 @@ WR_DESTRUCTOR_SAFE_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
void wr_api_send_transaction(DocumentHandle *aDh,
|
||||
Transaction *aTransaction)
|
||||
Transaction *aTransaction,
|
||||
bool aIsAsync)
|
||||
WR_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
|
@ -1850,7 +1850,7 @@ RestyleManager::AnimationsWithDestroyedFrame
|
||||
// *compositor* at this point.
|
||||
EffectSet* effectSet = EffectSet::GetEffectSet(element, aPseudoType);
|
||||
if (effectSet) {
|
||||
for (KeyframeEffectReadOnly* effect : *effectSet) {
|
||||
for (KeyframeEffect* effect : *effectSet) {
|
||||
effect->ResetIsRunningOnCompositor();
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@
|
||||
#include "mozilla/dom/HTMLImageElement.h"
|
||||
#include "mozilla/dom/DOMRect.h"
|
||||
#include "mozilla/dom/DOMStringList.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "nsIImageLoadingContent.h"
|
||||
@ -207,7 +207,7 @@ template<typename TestType>
|
||||
static bool
|
||||
HasMatchingAnimations(EffectSet* aEffects, TestType&& aTest)
|
||||
{
|
||||
for (KeyframeEffectReadOnly* effect : *aEffects) {
|
||||
for (KeyframeEffect* effect : *aEffects) {
|
||||
if (aTest(*effect)) {
|
||||
return true;
|
||||
}
|
||||
@ -232,7 +232,7 @@ bool
|
||||
nsLayoutUtils::HasCurrentTransitions(const nsIFrame* aFrame)
|
||||
{
|
||||
return HasMatchingAnimations(aFrame,
|
||||
[](KeyframeEffectReadOnly& aEffect)
|
||||
[](KeyframeEffect& aEffect)
|
||||
{
|
||||
// Since |aEffect| is current, it must have an associated Animation
|
||||
// so we don't need to null-check the result of GetAnimation().
|
||||
@ -281,7 +281,7 @@ nsLayoutUtils::HasAnimationOfProperty(EffectSet* aEffectSet,
|
||||
}
|
||||
|
||||
return HasMatchingAnimations(aEffectSet,
|
||||
[&aProperty](KeyframeEffectReadOnly& aEffect)
|
||||
[&aProperty](KeyframeEffect& aEffect)
|
||||
{
|
||||
return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
|
||||
aEffect.HasAnimationOfProperty(aProperty);
|
||||
@ -298,7 +298,7 @@ nsLayoutUtils::HasAnimationOfProperty(const nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
return HasMatchingAnimations(aFrame,
|
||||
[&aProperty](KeyframeEffectReadOnly& aEffect)
|
||||
[&aProperty](KeyframeEffect& aEffect)
|
||||
{
|
||||
return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
|
||||
aEffect.HasAnimationOfProperty(aProperty);
|
||||
@ -318,7 +318,7 @@ nsLayoutUtils::HasEffectiveAnimation(const nsIFrame* aFrame,
|
||||
|
||||
|
||||
return HasMatchingAnimations(effects,
|
||||
[&aProperty](KeyframeEffectReadOnly& aEffect)
|
||||
[&aProperty](KeyframeEffect& aEffect)
|
||||
{
|
||||
return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
|
||||
aEffect.HasEffectiveAnimationOfProperty(aProperty);
|
||||
@ -374,7 +374,7 @@ GetMinAndMaxScaleForAnimationProperty(const nsIFrame* aFrame,
|
||||
// not yet finished or which are filling forwards).
|
||||
MOZ_ASSERT(anim->IsRelevant());
|
||||
|
||||
dom::KeyframeEffectReadOnly* effect =
|
||||
dom::KeyframeEffect* effect =
|
||||
anim->GetEffect() ? anim->GetEffect()->AsKeyframeEffect() : nullptr;
|
||||
MOZ_ASSERT(effect, "A playing animation should have a keyframe effect");
|
||||
for (size_t propIdx = effect->Properties().Length(); propIdx-- != 0; ) {
|
||||
|
@ -1409,8 +1409,6 @@ nsFloatManager::PolygonShapeInfo::PolygonShapeInfo(
|
||||
nscoord bInAppUnits = (b - kbExpansionPerSide) * aAppUnitsPerDevPixel;
|
||||
bool bIsInExpandedRegion(b < kbExpansionPerSide ||
|
||||
b >= bSize - kbExpansionPerSide);
|
||||
bool bIsLessThanPolygonBStart(bInAppUnits < mBStart);
|
||||
bool bIsMoreThanPolygonBEnd(bInAppUnits >= mBEnd);
|
||||
|
||||
// We now figure out the i values that correspond to the left edge and
|
||||
// the right edge of the polygon at one-dev-pixel-thick strip of b. We
|
||||
@ -1420,6 +1418,8 @@ nsFloatManager::PolygonShapeInfo::PolygonShapeInfo(
|
||||
// get out, we have to subtract away the aMarginRect.x value before
|
||||
// converting the app units to dev pixels.
|
||||
nscoord bInAppUnitsMarginRect = bInAppUnits + aMarginRect.y;
|
||||
bool bIsLessThanPolygonBStart(bInAppUnitsMarginRect < mBStart);
|
||||
bool bIsMoreThanPolygonBEnd(bInAppUnitsMarginRect >= mBEnd);
|
||||
|
||||
const int32_t iLeftEdge = (bIsInExpandedRegion ||
|
||||
bIsLessThanPolygonBStart ||
|
||||
|
@ -3019,6 +3019,7 @@ static const uint32_t APPEND_OWN_LAYER = 0x1;
|
||||
static const uint32_t APPEND_POSITIONED = 0x2;
|
||||
static const uint32_t APPEND_SCROLLBAR_CONTAINER = 0x4;
|
||||
static const uint32_t APPEND_OVERLAY = 0x8;
|
||||
static const uint32_t APPEND_TOP = 0x10;
|
||||
|
||||
static void
|
||||
AppendToTop(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists,
|
||||
@ -3056,7 +3057,9 @@ AppendToTop(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists,
|
||||
// but we don't want them to unnecessarily cover overlapping elements from
|
||||
// outside our scroll frame.
|
||||
Maybe<int32_t> zIndex = Nothing();
|
||||
if (aFlags & APPEND_OVERLAY) {
|
||||
if (aFlags & APPEND_TOP) {
|
||||
zIndex = Some(INT32_MAX);
|
||||
} else if (aFlags & APPEND_OVERLAY) {
|
||||
zIndex = MaxZIndexInList(aLists.PositionedDescendants(), aBuilder);
|
||||
} else if (aSourceFrame->StylePosition()->mZIndex.GetUnit() == eStyleUnit_Integer) {
|
||||
zIndex = Some(aSourceFrame->StylePosition()->mZIndex.GetIntValue());
|
||||
@ -3181,10 +3184,15 @@ ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder,
|
||||
if (aPositioned) {
|
||||
appendToTopFlags |= APPEND_POSITIONED;
|
||||
}
|
||||
if (overlayScrollbars ||
|
||||
|
||||
if (isOverlayScrollbar ||
|
||||
scrollParts[i] == mResizerBox) {
|
||||
appendToTopFlags |= APPEND_OVERLAY;
|
||||
aBuilder->SetDisablePartialUpdates(true);
|
||||
if (isOverlayScrollbar && mIsRoot) {
|
||||
appendToTopFlags |= APPEND_TOP;
|
||||
} else {
|
||||
appendToTopFlags |= APPEND_OVERLAY;
|
||||
aBuilder->SetDisablePartialUpdates(true);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "gfxContext.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/layers/PLayerTransaction.h"
|
||||
@ -698,7 +698,7 @@ AddAnimationsForProperty(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
|
||||
continue;
|
||||
}
|
||||
|
||||
dom::KeyframeEffectReadOnly* keyframeEffect =
|
||||
dom::KeyframeEffect* keyframeEffect =
|
||||
anim->GetEffect() ? anim->GetEffect()->AsKeyframeEffect() : nullptr;
|
||||
MOZ_ASSERT(keyframeEffect,
|
||||
"A playing animation should have a keyframe effect");
|
||||
|
@ -55,7 +55,7 @@ headers = [
|
||||
"nsThemeConstants.h",
|
||||
"mozilla/css/Loader.h",
|
||||
"mozilla/css/SheetLoadData.h",
|
||||
"mozilla/dom/AnimationEffectReadOnlyBinding.h",
|
||||
"mozilla/dom/AnimationEffectBinding.h",
|
||||
"mozilla/dom/HTMLSlotElement.h",
|
||||
"mozilla/dom/KeyframeEffectBinding.h",
|
||||
"mozilla/dom/MediaList.h",
|
||||
|
@ -15,9 +15,9 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "mozilla/dom/AnimationEffectReadOnly.h"
|
||||
#include "mozilla/dom/AnimationEffect.h"
|
||||
#include "mozilla/dom/DocumentTimeline.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
|
||||
#include "nsPresContext.h"
|
||||
#include "nsStyleChangeList.h"
|
||||
@ -35,9 +35,9 @@
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::css;
|
||||
using mozilla::dom::Animation;
|
||||
using mozilla::dom::AnimationEffectReadOnly;
|
||||
using mozilla::dom::AnimationEffect;
|
||||
using mozilla::dom::AnimationPlayState;
|
||||
using mozilla::dom::KeyframeEffectReadOnly;
|
||||
using mozilla::dom::KeyframeEffect;
|
||||
using mozilla::dom::CSSAnimation;
|
||||
|
||||
typedef mozilla::ComputedTiming::AnimationPhase AnimationPhase;
|
||||
@ -370,8 +370,7 @@ public:
|
||||
aTimingFunction,
|
||||
aKeyframes);
|
||||
}
|
||||
void SetKeyframes(KeyframeEffectReadOnly& aEffect,
|
||||
nsTArray<Keyframe>&& aKeyframes)
|
||||
void SetKeyframes(KeyframeEffect& aEffect, nsTArray<Keyframe>&& aKeyframes)
|
||||
{
|
||||
aEffect.SetKeyframes(Move(aKeyframes), mComputedStyle);
|
||||
}
|
||||
@ -402,12 +401,12 @@ public:
|
||||
// post the required restyles.
|
||||
void NotifyNewOrRemovedAnimation(const Animation& aAnimation)
|
||||
{
|
||||
dom::AnimationEffectReadOnly* effect = aAnimation.GetEffect();
|
||||
dom::AnimationEffect* effect = aAnimation.GetEffect();
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
|
||||
KeyframeEffectReadOnly* keyframeEffect = effect->AsKeyframeEffect();
|
||||
KeyframeEffect* keyframeEffect = effect->AsKeyframeEffect();
|
||||
if (!keyframeEffect) {
|
||||
return;
|
||||
}
|
||||
@ -433,11 +432,11 @@ UpdateOldAnimationPropertiesWithNew(
|
||||
// Update the old from the new so we can keep the original object
|
||||
// identity (and any expando properties attached to it).
|
||||
if (aOld.GetEffect()) {
|
||||
dom::AnimationEffectReadOnly* oldEffect = aOld.GetEffect();
|
||||
dom::AnimationEffect* oldEffect = aOld.GetEffect();
|
||||
animationChanged = oldEffect->SpecifiedTiming() != aNewTiming;
|
||||
oldEffect->SetSpecifiedTiming(aNewTiming);
|
||||
|
||||
KeyframeEffectReadOnly* oldKeyframeEffect = oldEffect->AsKeyframeEffect();
|
||||
KeyframeEffect* oldKeyframeEffect = oldEffect->AsKeyframeEffect();
|
||||
if (oldKeyframeEffect) {
|
||||
aBuilder.SetKeyframes(*oldKeyframeEffect, Move(aNewKeyframes));
|
||||
}
|
||||
@ -530,9 +529,8 @@ BuildAnimation(nsPresContext* aPresContext,
|
||||
Maybe<OwningAnimationTarget> target;
|
||||
target.emplace(aTarget.mElement, aTarget.mPseudoType);
|
||||
KeyframeEffectParams effectOptions;
|
||||
RefPtr<KeyframeEffectReadOnly> effect =
|
||||
new KeyframeEffectReadOnly(aPresContext->Document(), target, timing,
|
||||
effectOptions);
|
||||
RefPtr<KeyframeEffect> effect =
|
||||
new KeyframeEffect(aPresContext->Document(), target, timing, effectOptions);
|
||||
|
||||
aBuilder.SetKeyframes(*effect, Move(keyframes));
|
||||
|
||||
|
@ -27,7 +27,6 @@ namespace css {
|
||||
class Declaration;
|
||||
} /* namespace css */
|
||||
namespace dom {
|
||||
class KeyframeEffectReadOnly;
|
||||
class Promise;
|
||||
} /* namespace dom */
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "nsIWidget.h"
|
||||
#include "nsThemeConstants.h" // For system widget appearance types
|
||||
|
||||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for PlaybackDirection
|
||||
#include "mozilla/dom/AnimationEffectBinding.h" // for PlaybackDirection
|
||||
#include "mozilla/LookAndFeel.h" // for system colors
|
||||
|
||||
#include "nsString.h"
|
||||
|
@ -239,8 +239,8 @@ enum class StyleOrient : uint8_t {
|
||||
#define NS_STYLE_WILL_CHANGE_FIXPOS_CB (1<<4)
|
||||
#define NS_STYLE_WILL_CHANGE_ABSPOS_CB (1<<5)
|
||||
|
||||
// See AnimationEffectReadOnly.webidl
|
||||
// and mozilla/dom/AnimationEffectReadOnlyBinding.h
|
||||
// See AnimationEffect.webidl
|
||||
// and mozilla/dom/AnimationEffectBinding.h
|
||||
namespace dom {
|
||||
enum class PlaybackDirection : uint8_t;
|
||||
enum class FillMode : uint8_t;
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "imgIContainer.h"
|
||||
#include "CounterStyleManager.h"
|
||||
|
||||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for PlaybackDirection
|
||||
#include "mozilla/dom/AnimationEffectBinding.h" // for PlaybackDirection
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "mozilla/dom/ImageTracker.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user