Merge mozilla-central to autoland. a=merge on a CLOSED TREE

This commit is contained in:
Andreea Pavel 2018-03-13 19:26:13 +02:00
Родитель 62afea2749 8fa0b32c84
Коммит 11bec2e097
2146 изменённых файлов: 269675 добавлений и 146438 удалений

Просмотреть файл

@ -448,6 +448,7 @@ DocAccessible::Shutdown()
parentDocument->RemoveChildDocument(this); parentDocument->RemoveChildDocument(this);
mParent->RemoveChild(this); mParent->RemoveChild(this);
MOZ_ASSERT(!mParent, "Parent has to be null!");
} }
// Walk the array backwards because child documents remove themselves from the // Walk the array backwards because child documents remove themselves from the

Просмотреть файл

@ -104,7 +104,10 @@ OuterDocAccessible::Shutdown()
// to its parent document. Otherwise a document accessible may be lost if // to its parent document. Otherwise a document accessible may be lost if
// its outerdoc has being recreated (see bug 862863 for details). // its outerdoc has being recreated (see bug 862863 for details).
if (!mDoc->IsDefunct()) { if (!mDoc->IsDefunct()) {
mDoc->BindChildDocument(child->AsDoc()); MOZ_ASSERT(!child->IsDefunct(), "Attempt to reattach shutdown document accessible");
if (!child->IsDefunct()) {
mDoc->BindChildDocument(child->AsDoc());
}
} }
} }
@ -143,8 +146,8 @@ bool
OuterDocAccessible::RemoveChild(Accessible* aAccessible) OuterDocAccessible::RemoveChild(Accessible* aAccessible)
{ {
Accessible* child = mChildren.SafeElementAt(0, nullptr); Accessible* child = mChildren.SafeElementAt(0, nullptr);
MOZ_ASSERT(child == aAccessible, "Wrong child to remove!");
if (child != aAccessible) { if (child != aAccessible) {
NS_ERROR("Wrong child to remove!");
return false; return false;
} }

Просмотреть файл

@ -158,7 +158,7 @@ window._gBrowser = {
"resumeMedia", "mute", "unmute", "blockedPopups", "lastURI", "resumeMedia", "mute", "unmute", "blockedPopups", "lastURI",
"purgeSessionHistory", "stopScroll", "startScroll", "purgeSessionHistory", "stopScroll", "startScroll",
"userTypedValue", "userTypedClear", "mediaBlocked", "userTypedValue", "userTypedClear", "mediaBlocked",
"didStartLoadSinceLastUserTyping" "didStartLoadSinceLastUserTyping", "audioMuted"
], ],
_removingTabs: [], _removingTabs: [],
@ -1937,7 +1937,7 @@ window._gBrowser = {
let setter; let setter;
switch (name) { switch (name) {
case "audioMuted": case "audioMuted":
getter = () => false; getter = () => aTab.hasAttribute("muted");
break; break;
case "contentTitle": case "contentTitle":
getter = () => SessionStore.getLazyTabValue(aTab, "title"); getter = () => SessionStore.getLazyTabValue(aTab, "title");

Просмотреть файл

@ -1906,39 +1906,6 @@
<parameter name="aMuteReason"/> <parameter name="aMuteReason"/>
<body> <body>
<![CDATA[ <![CDATA[
// Do not attempt to toggle mute state if browser is lazy.
if (!this.linkedPanel) {
return;
}
let browser = this.linkedBrowser;
let modifiedAttrs = [];
let hist = Services.telemetry.getHistogramById("TAB_AUDIO_INDICATOR_USED");
if (this.hasAttribute("activemedia-blocked")) {
this.removeAttribute("activemedia-blocked");
modifiedAttrs.push("activemedia-blocked");
browser.resumeMedia();
hist.add(3 /* unblockByClickingIcon */);
this.finishMediaBlockTimer();
} else {
if (browser.audioMuted) {
browser.unmute();
this.removeAttribute("muted");
BrowserUITelemetry.countTabMutingEvent("unmute", aMuteReason);
hist.add(1 /* unmute */);
} else {
browser.mute();
this.setAttribute("muted", "true");
BrowserUITelemetry.countTabMutingEvent("mute", aMuteReason);
hist.add(0 /* mute */);
}
this.muteReason = aMuteReason || null;
modifiedAttrs.push("muted");
}
gBrowser._tabAttrModified(this, modifiedAttrs);
]]>
</body> </body>
</method> </method>

Просмотреть файл

@ -8,6 +8,7 @@ support-files =
head.js head.js
[browser_all_files_referenced.js] [browser_all_files_referenced.js]
skip-if = (os == 'win' && bits == 32)
[browser_misused_characters_in_strings.js] [browser_misused_characters_in_strings.js]
support-files = support-files =
bug1262648_string_with_newlines.dtd bug1262648_string_with_newlines.dtd

Просмотреть файл

@ -96,9 +96,6 @@ let propNameWhitelist = [
// Bug 1441837 // Bug 1441837
{propName: "--in-content-category-text-active", {propName: "--in-content-category-text-active",
isFromDevTools: false}, isFromDevTools: false},
// Bug 1441844
{propName: "--chrome-nav-bar-separator-color",
isFromDevTools: false},
// Bug 1441855 // Bug 1441855
{propName: "--chrome-nav-buttons-background", {propName: "--chrome-nav-buttons-background",
isFromDevTools: false}, isFromDevTools: false},

Просмотреть файл

@ -35,3 +35,4 @@ skip-if = (debug && os == 'mac') || (debug && os == 'linux' && bits == 64) #Bug
[browser_visibleTabs_bookmarkAllTabs.js] [browser_visibleTabs_bookmarkAllTabs.js]
[browser_visibleTabs_contextMenu.js] [browser_visibleTabs_contextMenu.js]
[browser_open_newtab_start_observer_notification.js] [browser_open_newtab_start_observer_notification.js]
[browser_bug_1387976_restore_lazy_tab_browser_muted_state.js]

Просмотреть файл

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { TabState } = ChromeUtils.import("resource:///modules/sessionstore/TabState.jsm", {});
/**
* Simulate a restart of a tab by removing it, then add a lazy tab
* which is restored with the tabData of the removed tab.
*
* @param tab
* The tab to restart.
* @return {Object} the restored lazy tab
*/
const restartTab = async function(tab) {
let tabData = TabState.clone(tab);
BrowserTestUtils.removeTab(tab);
let restoredLazyTab = BrowserTestUtils.addTab(gBrowser, "", {createLazyBrowser: true});
SessionStore.setTabState(restoredLazyTab, JSON.stringify(tabData));
return restoredLazyTab;
};
function get_tab_state(tab) {
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
return JSON.parse(ss.getTabState(tab));
}
add_task(async function() {
const tab = BrowserTestUtils.addTab(gBrowser, "http://mochi.test:8888/");
const browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
// Let's make sure the tab is not in a muted state at the beginning
ok(!("muted" in get_tab_state(tab)), "Tab should not be in a muted state");
info("toggling Muted audio...");
tab.toggleMuteAudio();
ok("muted" in get_tab_state(tab), "Tab should be in a muted state");
info("Restarting tab...");
let restartedTab = await restartTab(tab);
ok("muted" in get_tab_state(restartedTab), "Restored tab should still be in a muted state after restart");
BrowserTestUtils.removeTab(restartedTab);
});

Просмотреть файл

@ -89,7 +89,7 @@ var gTests = [
await BrowserTestUtils.removeTab(tab); await BrowserTestUtils.removeTab(tab);
// Check that we still show the sharing indicators for the first tab's stream. // Check that we still show the sharing indicators for the first tab's stream.
await promiseWaitForCondition(() => !webrtcUI.showCameraIndicator); await TestUtils.waitForCondition(() => !webrtcUI.showCameraIndicator);
ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown"); ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown");
ok(!webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator hidden"); ok(!webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator hidden");
ok(webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator shown"); ok(webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator shown");
@ -192,7 +192,7 @@ var gTests = [
await BrowserTestUtils.removeTab(tab); await BrowserTestUtils.removeTab(tab);
// Check that we still show the sharing indicators for the first tab's stream. // Check that we still show the sharing indicators for the first tab's stream.
await promiseWaitForCondition(() => webrtcUI.showCameraIndicator); await TestUtils.waitForCondition(() => webrtcUI.showCameraIndicator);
ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown"); ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown");
ok(webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator shown"); ok(webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator shown");
ok(!webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator hidden"); ok(!webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator hidden");

Просмотреть файл

@ -67,7 +67,7 @@ var gTests = [
menulist.getItemAtIndex(2).doCommand(); menulist.getItemAtIndex(2).doCommand();
ok(!document.getElementById("webRTC-all-windows-shared").hidden, ok(!document.getElementById("webRTC-all-windows-shared").hidden,
"the 'all windows will be shared' warning should now be visible"); "the 'all windows will be shared' warning should now be visible");
await promiseWaitForCondition(() => !document.getElementById("webRTC-preview").hidden, 100); await TestUtils.waitForCondition(() => !document.getElementById("webRTC-preview").hidden, 100, 100);
ok(!document.getElementById("webRTC-preview").hidden, ok(!document.getElementById("webRTC-preview").hidden,
"the preview area is visible"); "the preview area is visible");
ok(!document.getElementById("webRTC-previewWarning").hidden, ok(!document.getElementById("webRTC-previewWarning").hidden,
@ -169,7 +169,7 @@ var gTests = [
menulist.getItemAtIndex(scaryIndex).doCommand(); menulist.getItemAtIndex(scaryIndex).doCommand();
ok(document.getElementById("webRTC-all-windows-shared").hidden, ok(document.getElementById("webRTC-all-windows-shared").hidden,
"the 'all windows will be shared' warning should still be hidden"); "the 'all windows will be shared' warning should still be hidden");
await promiseWaitForCondition(() => !document.getElementById("webRTC-preview").hidden); await TestUtils.waitForCondition(() => !document.getElementById("webRTC-preview").hidden);
ok(!document.getElementById("webRTC-preview").hidden, ok(!document.getElementById("webRTC-preview").hidden,
"the preview area is visible"); "the preview area is visible");
ok(!document.getElementById("webRTC-previewWarning").hidden, ok(!document.getElementById("webRTC-previewWarning").hidden,
@ -186,7 +186,7 @@ var gTests = [
menulist.getItemAtIndex(nonScaryIndex).doCommand(); menulist.getItemAtIndex(nonScaryIndex).doCommand();
ok(document.getElementById("webRTC-all-windows-shared").hidden, ok(document.getElementById("webRTC-all-windows-shared").hidden,
"the 'all windows will be shared' warning should still be hidden"); "the 'all windows will be shared' warning should still be hidden");
await promiseWaitForCondition(() => !document.getElementById("webRTC-preview").hidden); await TestUtils.waitForCondition(() => !document.getElementById("webRTC-preview").hidden);
ok(!document.getElementById("webRTC-preview").hidden, ok(!document.getElementById("webRTC-preview").hidden,
"the preview area is visible"); "the preview area is visible");
ok(document.getElementById("webRTC-previewWarning").hidden, ok(document.getElementById("webRTC-previewWarning").hidden,
@ -277,7 +277,7 @@ var gTests = [
menulist.getItemAtIndex(2).doCommand(); menulist.getItemAtIndex(2).doCommand();
ok(document.getElementById("webRTC-all-windows-shared").hidden, ok(document.getElementById("webRTC-all-windows-shared").hidden,
"the 'all windows will be shared' warning should still be hidden"); "the 'all windows will be shared' warning should still be hidden");
await promiseWaitForCondition(() => !document.getElementById("webRTC-preview").hidden); await TestUtils.waitForCondition(() => !document.getElementById("webRTC-preview").hidden);
ok(!document.getElementById("webRTC-preview").hidden, ok(!document.getElementById("webRTC-preview").hidden,
"the preview area is visible"); "the preview area is visible");
ok(document.getElementById("webRTC-previewWarning").hidden, ok(document.getElementById("webRTC-previewWarning").hidden,
@ -328,7 +328,7 @@ var gTests = [
menulist.getItemAtIndex(2).doCommand(); menulist.getItemAtIndex(2).doCommand();
ok(!document.getElementById("webRTC-all-windows-shared").hidden, ok(!document.getElementById("webRTC-all-windows-shared").hidden,
"the 'all windows will be shared' warning should now be visible"); "the 'all windows will be shared' warning should now be visible");
await promiseWaitForCondition(() => !document.getElementById("webRTC-preview").hidden); await TestUtils.waitForCondition(() => !document.getElementById("webRTC-preview").hidden);
ok(!document.getElementById("webRTC-preview").hidden, ok(!document.getElementById("webRTC-preview").hidden,
"the preview area is visible"); "the preview area is visible");
ok(!document.getElementById("webRTC-previewWarning").hidden, ok(!document.getElementById("webRTC-previewWarning").hidden,
@ -498,7 +498,7 @@ var gTests = [
Services.wm.getMostRecentWindow("Browser:WebRTCGlobalIndicator"); Services.wm.getMostRecentWindow("Browser:WebRTCGlobalIndicator");
let elt = win.document.getElementById("screenShareButton"); let elt = win.document.getElementById("screenShareButton");
EventUtils.synthesizeMouseAtCenter(elt, {}, win); EventUtils.synthesizeMouseAtCenter(elt, {}, win);
await promiseWaitForCondition(() => !gIdentityHandler._identityPopup.hidden); await TestUtils.waitForCondition(() => !gIdentityHandler._identityPopup.hidden);
} }
ok(!gIdentityHandler._identityPopup.hidden, "control center should be open"); ok(!gIdentityHandler._identityPopup.hidden, "control center should be open");

Просмотреть файл

@ -21,7 +21,6 @@
--chrome-color: rgb(249, 249, 250); --chrome-color: rgb(249, 249, 250);
--chrome-secondary-background-color: hsl(240, 1%, 20%); --chrome-secondary-background-color: hsl(240, 1%, 20%);
--toolbox-border-bottom-color: hsla(240, 5%, 5%, .1); --toolbox-border-bottom-color: hsla(240, 5%, 5%, .1);
--chrome-nav-bar-separator-color: rgba(0,0,0,.2);
--chrome-nav-buttons-background: hsla(240, 5%, 5%, .1); --chrome-nav-buttons-background: hsla(240, 5%, 5%, .1);
--chrome-nav-buttons-hover-background: hsla(240, 5%, 5%, .15); --chrome-nav-buttons-hover-background: hsla(240, 5%, 5%, .15);
--chrome-nav-bar-controls-border-color: hsla(240, 5%, 5%, .3); --chrome-nav-bar-controls-border-color: hsla(240, 5%, 5%, .3);
@ -41,7 +40,6 @@
--chrome-color: #18191a; --chrome-color: #18191a;
--chrome-secondary-background-color: #f5f6f7; --chrome-secondary-background-color: #f5f6f7;
--toolbox-border-bottom-color: #cccccc; --toolbox-border-bottom-color: #cccccc;
--chrome-nav-bar-separator-color: #B6B6B8;
--chrome-nav-buttons-background: #ffffff; /* --theme-body-background */ --chrome-nav-buttons-background: #ffffff; /* --theme-body-background */
--chrome-nav-buttons-hover-background: #DADBDB; --chrome-nav-buttons-hover-background: #DADBDB;
--chrome-nav-bar-controls-border-color: #ccc; --chrome-nav-bar-controls-border-color: #ccc;

Просмотреть файл

@ -4,11 +4,6 @@
%include ../shared/compacttheme.inc.css %include ../shared/compacttheme.inc.css
:root {
/* Matches the #browser-border-start, #browser-border-end color */
--chrome-nav-bar-separator-color: rgba(10, 31, 51, 0.35);
}
/* The window background is white due to no accentcolor in the lightweight /* The window background is white due to no accentcolor in the lightweight
theme. It can't be changed to transparent when there is no compositor theme. It can't be changed to transparent when there is no compositor
(Win 7 in classic / basic theme), or else dragging and focus become (Win 7 in classic / basic theme), or else dragging and focus become

Просмотреть файл

@ -1,264 +1,264 @@
# This file contains an extensive compile-time blacklist for silencing highly # This file contains an extensive compile-time blacklist for silencing highly
# frequent signed integer overflows in our codebase, found by the use of # frequent signed integer overflows in our codebase, found by the use of
# -fsanitize=signed-integer-overflow. C/C++ say signed integer overflow is # -fsanitize=signed-integer-overflow. C/C++ say signed integer overflow is
# undefined behavior, so instances of this need to be fixed. But not all code # undefined behavior, so instances of this need to be fixed. But not all code
# has been properly written to not overflow, and overflow-checking can have # has been properly written to not overflow, and overflow-checking can have
# significant compile time and runtime costs, so we will sometimes disable # significant compile time and runtime costs, so we will sometimes disable
# signed overflow checking. # signed overflow checking.
# #
# The rules in this file are applied at compile time; changes to this list # The rules in this file are applied at compile time; changes to this list
# usually require a full rebuild to apply. If you can modify the source in # usually require a full rebuild to apply. If you can modify the source in
# question to exempt individual functions using MOZ_NO_SANITIZE_SINT_OVERFLOW, # question to exempt specific functions using MOZ_NO_SANITIZE_SIGNED_OVERFLOW,
# do that instead. # do that instead.
# #
# The extensive number of entries below is for two reasons. # The extensive number of entries below is for two reasons.
# #
# First, compiler instrumentation for signed integer overflows has a cost, at # First, compiler instrumentation for signed integer overflows has a cost, at
# compile time and at runtime. In performance-critical code proven to have no # compile time and at runtime. In performance-critical code proven to have no
# signed overflow, it makes sense to turn off overflow detection to avoid both # signed overflow, it makes sense to turn off overflow detection to avoid both
# costs. (Indeed, -fsanitize=signed-integer-overflow is unusably slow without # costs. (Indeed, -fsanitize=signed-integer-overflow is unusably slow without
# this.) # this.)
# #
# Second, many entries here are overly aggressive to get the build into a state # Second, many entries here are overly aggressive to get the build into a state
# that allows any testing to happen at all. Some of the entries here are for # that allows any testing to happen at all. Some of the entries here are for
# issues that are highly frequent in our test suites -- over 500 times per run. # issues that are highly frequent in our test suites -- over 500 times per run.
# Aggressive entries now let us start using this mode, without having to first # Aggressive entries now let us start using this mode, without having to first
# fix wide swaths of existing code. # fix wide swaths of existing code.
# #
# Entries should be removed 1) as issues are fixed; and 2) as blacklist entries # Entries should be removed 1) as issues are fixed; and 2) as blacklist entries
# can be moved out of this centralized file, into source-level blacklist # can be moved out of this centralized file, into source-level blacklist
# attributes on individual functions. # attributes on individual functions.
# All entries in this file are to suppress signed-integer-overflow problems. # All entries in this file are to suppress signed-integer-overflow problems.
# Blacklists for other reasons should go in separate blacklist files. # Blacklists for other reasons should go in separate blacklist files.
[signed-integer-overflow] [signed-integer-overflow]
# Overflows in the C++ std headers aren't necessarily bugs, because code inside # Overflows in the C++ std headers aren't necessarily bugs, because code inside
# a language implementation can depend on compiler-specific behavior where C/C++ # a language implementation can depend on compiler-specific behavior where C/C++
# leave the behavior undefined. # leave the behavior undefined.
src:*bits/basic_string.h src:*bits/basic_string.h
# Assume everything running through CheckedInt.h is ok. Signed overflows here # Assume everything running through CheckedInt.h is ok. Signed overflows here
# should generally have been guarded by safe overflow checks, so it's likely # should generally have been guarded by safe overflow checks, so it's likely
# safe to exempt it from overflow checking. (This should eventually be verified # safe to exempt it from overflow checking. (This should eventually be verified
# and functions individually tagged safe so this entry can be removed.) # and functions individually tagged safe so this entry can be removed.)
src:*/CheckedInt.h src:*/CheckedInt.h
# Exclude bignum # Exclude bignum
src:*/mfbt/double-conversion/source/bignum.cc src:*/mfbt/double-conversion/source/bignum.cc
# Exclude anything within gtests # Exclude anything within gtests
src:*/gtest/* src:*/gtest/*
# Atomics can overflow, but without a full stack we can't trace these back # Atomics can overflow, but without a full stack we can't trace these back
# to what is actually causing the overflow. Ignoring these for now, as it will # to what is actually causing the overflow. Ignoring these for now, as it will
# be too much effort to determine every single source here. # be too much effort to determine every single source here.
src:*/mfbt/Atomics.h src:*/mfbt/Atomics.h
# No reason to instrument certain parts of NSS that explicitely deal with # No reason to instrument certain parts of NSS that explicitely deal with
# arithmetics and crypto. # arithmetics and crypto.
src:*/security/nss/lib/freebl/mpi/* src:*/security/nss/lib/freebl/mpi/*
src:*/security/nss/lib/freebl/ecl/* src:*/security/nss/lib/freebl/ecl/*
# nsTArray_base<Alloc, Copy>::ShiftData performs overflows # nsTArray_base<Alloc, Copy>::ShiftData performs overflows
fun:*nsTArray_base*ShiftData* fun:*nsTArray_base*ShiftData*
### Frequent 0 - 1 overflows ### Frequent 0 - 1 overflows
# #
# We have several code patterns in our codebase that cause these overflows, # We have several code patterns in our codebase that cause these overflows,
# but they are typically all harmless and could be filtered easily at runtime. # but they are typically all harmless and could be filtered easily at runtime.
# However, some of them are so frequent that suppressing them at compile-time # However, some of them are so frequent that suppressing them at compile-time
# makes sense to increase runtime performance. # makes sense to increase runtime performance.
# #
src:*/netwerk/base/nsSocketTransportService2.cpp src:*/netwerk/base/nsSocketTransportService2.cpp
src:*/dom/xul/XULDocument.cpp src:*/dom/xul/XULDocument.cpp
src:*/nsCharTraits.h src:*/nsCharTraits.h
# Code in xpcom/base/CycleCollectedJSContext.cpp # Code in xpcom/base/CycleCollectedJSContext.cpp
fun:*CycleCollectedJSContext*ProcessMetastableStateQueue* fun:*CycleCollectedJSContext*ProcessMetastableStateQueue*
# Code in layout/painting/nsDisplayList.cpp # Code in layout/painting/nsDisplayList.cpp
fun:*nsDisplayOpacity*ShouldFlattenAway* fun:*nsDisplayOpacity*ShouldFlattenAway*
# Code in modules/libpref/Preferences.cpp # Code in modules/libpref/Preferences.cpp
fun:*pref_InitInitialObjects* fun:*pref_InitInitialObjects*
# Code in netwerk/base/nsIOService.cpp # Code in netwerk/base/nsIOService.cpp
fun:*nsIOService*GetCachedProtocolHandler* fun:*nsIOService*GetCachedProtocolHandler*
# Code in layout/style/nsCSSRuleProcessor.cpp # Code in layout/style/nsCSSRuleProcessor.cpp
fun:*0nsCSSRuleProcessor@@* fun:*0nsCSSRuleProcessor@@*
fun:*nsCSSRuleProcessor*ClearSheets* fun:*nsCSSRuleProcessor*ClearSheets*
fun:*TreeMatchContext*InitAncestors* fun:*TreeMatchContext*InitAncestors*
fun:*TreeMatchContext*InitStyleScopes* fun:*TreeMatchContext*InitStyleScopes*
# Code in layout/xul/nsXULPopupManager.cpp # Code in layout/xul/nsXULPopupManager.cpp
fun:*nsXULPopupManager*AdjustPopupsOnWindowChange* fun:*nsXULPopupManager*AdjustPopupsOnWindowChange*
# Code in dom/base/nsDocument.cpp # Code in dom/base/nsDocument.cpp
fun:*1nsDocument@@* fun:*1nsDocument@@*
# Code in gfx/layers/ipc/CompositorBridgeChild.cpp # Code in gfx/layers/ipc/CompositorBridgeChild.cpp
fun:*CompositorBridgeChild*Destroy* fun:*CompositorBridgeChild*Destroy*
# Code in gfx/layers/ipc/ImageBridgeChild.cpp # Code in gfx/layers/ipc/ImageBridgeChild.cpp
fun:*ImageBridgeChild*ShutdownStep1* fun:*ImageBridgeChild*ShutdownStep1*
# Code in dom/base/nsGlobalWindow.cpp # Code in dom/base/nsGlobalWindow.cpp
fun:*nsGlobalWindow*ClearControllers* fun:*nsGlobalWindow*ClearControllers*
# Code in layout/style/AnimationCollection.cpp # Code in layout/style/AnimationCollection.cpp
fun:*AnimationCollection*PropertyDtor* fun:*AnimationCollection*PropertyDtor*
# Code in layout/style/nsStyleSet.cpp # Code in layout/style/nsStyleSet.cpp
fun:*nsStyleSet*AddImportantRules* fun:*nsStyleSet*AddImportantRules*
fun:*nsStyleSet*CounterStyleRuleForName* fun:*nsStyleSet*CounterStyleRuleForName*
### Misc overflows ### Misc overflows
# Hot function in protobuf producing overflows # Hot function in protobuf producing overflows
fun:*CodedInputStream*ReadTagWithCutoff* fun:*CodedInputStream*ReadTagWithCutoff*
# SQLite3 is full of overflows :/ # SQLite3 is full of overflows :/
src:*/db/sqlite3/src/sqlite3.c src:*/db/sqlite3/src/sqlite3.c
# zlib has some overflows, we can't deal with them right now # zlib has some overflows, we can't deal with them right now
src:*/modules/zlib/src/* src:*/modules/zlib/src/*
# Our LZ4 implementation uses overflows. By listing it here we might # Our LZ4 implementation uses overflows. By listing it here we might
# miss some unintended overflows in that implementation, but we can't # miss some unintended overflows in that implementation, but we can't
# check for it right now. # check for it right now.
src:*/mfbt/lz4.c src:*/mfbt/lz4.c
# Apparently this overflows a lot, because it contains some allocators # Apparently this overflows a lot, because it contains some allocators
# that keep overflowing, not sure why. Disabling by function didn't seem # that keep overflowing, not sure why. Disabling by function didn't seem
# to work here for operator new. # to work here for operator new.
src:*/xpcom/ds/nsArrayEnumerator.cpp src:*/xpcom/ds/nsArrayEnumerator.cpp
# Memory usage reporting code in gfx/thebes/gfxASurface.cpp # Memory usage reporting code in gfx/thebes/gfxASurface.cpp
# We probably don't care about the frequent overflows there. # We probably don't care about the frequent overflows there.
fun:*SurfaceMemoryReporter*AdjustUsedMemory* fun:*SurfaceMemoryReporter*AdjustUsedMemory*
# Frequent overflower in gfx/thebes/gfxFontEntry.cpp # Frequent overflower in gfx/thebes/gfxFontEntry.cpp
fun:*WeightDistance* fun:*WeightDistance*
# Another frequent overflower # Another frequent overflower
fun:*nsTObserverArray_base*AdjustIterators* fun:*nsTObserverArray_base*AdjustIterators*
# Overflows in Skia # Overflows in Skia
fun:*SkPathRef*makeSpace* fun:*SkPathRef*makeSpace*
fun:*SkPathRef*resetToSize* fun:*SkPathRef*resetToSize*
# Expat Parser has some overflows # Expat Parser has some overflows
fun:*nsExpatDriver*ConsumeToken* fun:*nsExpatDriver*ConsumeToken*
# Frequent overflowers in harfbuzz # Frequent overflowers in harfbuzz
fun:*hb_in_range* fun:*hb_in_range*
fun:*OT*collect_glyphs* fun:*OT*collect_glyphs*
# These look like harmless layouting-related overflows # These look like harmless layouting-related overflows
src:*/gfx/cairo/libpixman/src/pixman-region.c src:*/gfx/cairo/libpixman/src/pixman-region.c
# Code in ipc/chromium/src/base/file_path.cc where a function returns -1 # Code in ipc/chromium/src/base/file_path.cc where a function returns -1
# being cast to unsigned and then overflowed. # being cast to unsigned and then overflowed.
fun:*FilePath*Append* fun:*FilePath*Append*
fun:*FilePath*StripTrailingSeparatorsInternal* fun:*FilePath*StripTrailingSeparatorsInternal*
# Code in dom/base/nsJSEnvironment.cpp # Code in dom/base/nsJSEnvironment.cpp
fun:*FireForgetSkippable* fun:*FireForgetSkippable*
# Code in gfx/thebes/gfxSkipChars.h # Code in gfx/thebes/gfxSkipChars.h
fun:*gfxSkipCharsIterator*AdvanceSkipped* fun:*gfxSkipCharsIterator*AdvanceSkipped*
# Code in gfx/thebes/gfxScriptItemizer.cpp # Code in gfx/thebes/gfxScriptItemizer.cpp
fun:*gfxScriptItemizer*fixup* fun:*gfxScriptItemizer*fixup*
fun:*gfxScriptItemizer*push* fun:*gfxScriptItemizer*push*
# Code in dom/base/nsDocument.cpp # Code in dom/base/nsDocument.cpp
fun:*nsDocument*BlockOnload* fun:*nsDocument*BlockOnload*
# Code in layout/base/nsCSSFrameConstructor.cpp # Code in layout/base/nsCSSFrameConstructor.cpp
fun:*nsCSSFrameConstructor*FrameConstructionItemList*AdjustCountsForItem* fun:*nsCSSFrameConstructor*FrameConstructionItemList*AdjustCountsForItem*
# Code in nsprpub/lib/ds/plarena.c doing ptrdiffs # Code in nsprpub/lib/ds/plarena.c doing ptrdiffs
fun:*PL_ArenaRelease* fun:*PL_ArenaRelease*
# This file contains a bunch of arithmetic operations on timestamps that # This file contains a bunch of arithmetic operations on timestamps that
# apparently are allowed to overflow. # apparently are allowed to overflow.
src:*/src/widget/SystemTimeConverter.h src:*/src/widget/SystemTimeConverter.h
# Code in dom/media/flac/FlacDemuxer.cpp purposely uses overflowing arithmetics # Code in dom/media/flac/FlacDemuxer.cpp purposely uses overflowing arithmetics
fun:*Frame*FindNext* fun:*Frame*FindNext*
# Code in netwerk/base/nsStandardURL.cpp, # Code in netwerk/base/nsStandardURL.cpp,
# these methods return signed but the subtraction is first performed unsigned # these methods return signed but the subtraction is first performed unsigned
fun:*nsStandardURL*ReplaceSegment* fun:*nsStandardURL*ReplaceSegment*
# Code in netwerk/protocol/http/nsHttpChannel.cpp # Code in netwerk/protocol/http/nsHttpChannel.cpp
# same as previous with the previous entry. # same as previous with the previous entry.
fun:*nsHttpChannel*ReportNetVSCacheTelemetry* fun:*nsHttpChannel*ReportNetVSCacheTelemetry*
# Code in layout/tables/nsCellMap.cpp # Code in layout/tables/nsCellMap.cpp
# again subtraction then cast to signed. # again subtraction then cast to signed.
fun:*nsTableCellMap*GetColInfoAt* fun:*nsTableCellMap*GetColInfoAt*
# Code in layout/generic/nsTextFrame.cpp # Code in layout/generic/nsTextFrame.cpp
# again subtraction then cast to signed. # again subtraction then cast to signed.
fun:*nsTextFrame*CharacterDataChanged* fun:*nsTextFrame*CharacterDataChanged*
# Not sure what is going on in this file, but it doesn't look # Not sure what is going on in this file, but it doesn't look
# related to what we are looking for. # related to what we are looking for.
src:*/xpcom/base/CountingAllocatorBase.h src:*/xpcom/base/CountingAllocatorBase.h
# Code in dom/base/nsDOMNavigationTiming.cpp # Code in dom/base/nsDOMNavigationTiming.cpp
# Timestamp related, probably expecting the overflow # Timestamp related, probably expecting the overflow
fun:*nsDOMNavigationTiming*TimeStampToDOM* fun:*nsDOMNavigationTiming*TimeStampToDOM*
# Several unsigned arithmetic operations with -1 # Several unsigned arithmetic operations with -1
src:*/hal/HalWakeLock.cpp src:*/hal/HalWakeLock.cpp
# Code in layout/generic/nsGfxScrollFrame.cpp that produces # Code in layout/generic/nsGfxScrollFrame.cpp that produces
# somewhat frequent signed integer overflows. Probably harmless # somewhat frequent signed integer overflows. Probably harmless
# because it's layout code. # because it's layout code.
fun:*ClampAndAlignWithPixels* fun:*ClampAndAlignWithPixels*
# Likely benign overflow in mozglue/misc/TimeStamp_posix.cpp # Likely benign overflow in mozglue/misc/TimeStamp_posix.cpp
fun:*ClockResolutionNs* fun:*ClockResolutionNs*
# This header has all sorts of operators that do post-operation # This header has all sorts of operators that do post-operation
# overflow and underflow checking, triggering frequent reports # overflow and underflow checking, triggering frequent reports
src:*/mozglue/misc/TimeStamp.h src:*/mozglue/misc/TimeStamp.h
# #
# Various hashing functions, both regular and cryptographic ones # Various hashing functions, both regular and cryptographic ones
# #
src:*/dom/canvas/MurmurHash3.cpp src:*/dom/canvas/MurmurHash3.cpp
src:*/gfx/skia/skia/include/private/SkChecksum.h src:*/gfx/skia/skia/include/private/SkChecksum.h
src:*/intl/icu/source/common/unifiedcache.h src:*/intl/icu/source/common/unifiedcache.h
src:*/mfbt/SHA1.cpp src:*/mfbt/SHA1.cpp
src:*/modules/zlib/src/adler32.c src:*/modules/zlib/src/adler32.c
src:*/netwerk/cache/nsDiskCacheDevice.cpp src:*/netwerk/cache/nsDiskCacheDevice.cpp
src:*/netwerk/cache2/CacheHashUtils.cpp src:*/netwerk/cache2/CacheHashUtils.cpp
src:*/netwerk/sctp/src/netinet/sctp_sha1.c src:*/netwerk/sctp/src/netinet/sctp_sha1.c
src:*/netwerk/srtp/src/crypto/hash/sha1.c src:*/netwerk/srtp/src/crypto/hash/sha1.c
src:*/netwerk/sctp/src/netinet/sctp_sha1.c src:*/netwerk/sctp/src/netinet/sctp_sha1.c
src:*/nsprpub/lib/ds/plhash.c src:*/nsprpub/lib/ds/plhash.c
src:*/security/manager/ssl/md4.c src:*/security/manager/ssl/md4.c
src:*/security/nss/lib/dbm/src/h_func.c src:*/security/nss/lib/dbm/src/h_func.c
src:*/security/nss/lib/freebl/sha512.c src:*/security/nss/lib/freebl/sha512.c
src:*/security/nss/lib/freebl/md5.c src:*/security/nss/lib/freebl/md5.c
src:*/xpcom/ds/PLDHashTable.cpp src:*/xpcom/ds/PLDHashTable.cpp
# Hash/Cache function in Skia # Hash/Cache function in Skia
fun:*GradientShaderCache*Build32bitCache* fun:*GradientShaderCache*Build32bitCache*
# Hashing functions in Cairo # Hashing functions in Cairo
fun:*_hash_matrix_fnv* fun:*_hash_matrix_fnv*
fun:*_hash_mix_bits* fun:*_hash_mix_bits*
fun:*_cairo_hash_string* fun:*_cairo_hash_string*
fun:*_cairo_hash_bytes* fun:*_cairo_hash_bytes*
# intl code hashing functions # intl code hashing functions
fun:*ustr_hash*CharsN* fun:*ustr_hash*CharsN*
fun:*hashEntry* fun:*hashEntry*
# harfbuzz hash/digest functions # harfbuzz hash/digest functions
fun:*hb_set_digest_lowest_bits_t* fun:*hb_set_digest_lowest_bits_t*
# Hash function in gfx # Hash function in gfx
fun:*gfxFontStyle*Hash* fun:*gfxFontStyle*Hash*
# expat uses a CHAR_HASH macro in several places that causes # expat uses a CHAR_HASH macro in several places that causes
# a high amount of overflows. We should try finding a better # a high amount of overflows. We should try finding a better
# way to disable this rather than blacklisting the whole thing. # way to disable this rather than blacklisting the whole thing.
src:*/parser/expat/* src:*/parser/expat/*

Просмотреть файл

@ -1,271 +1,271 @@
# This file contains an extensive compile-time blacklist for silencing highly # This file contains an extensive compile-time blacklist for silencing highly
# frequent *un*signed integer overflows in our codebase, found by the use of # frequent *un*signed integer overflows in our codebase, found by the use of
# -fsanitize=unsigned-integer-overflow. Such overflows are not necessarily # -fsanitize=unsigned-integer-overflow. Such overflows are not necessarily
# bugs -- unsigned integer overflow has well-defined semantics in C/C++. But # bugs -- unsigned integer overflow has well-defined semantics in C/C++. But
# overflow may still be *unexpected* and incorrectly handled, so we try to # overflow may still be *unexpected* and incorrectly handled, so we try to
# annotate those places where unsigned overflow is correct and desired. # annotate those places where unsigned overflow is correct and desired.
# #
# The rules in this file are applied at compile time; changes to this list # The rules in this file are applied at compile time; changes to this list
# usually require a full rebuild to apply. If you can modify the source in # usually require a full rebuild to apply. If you can modify the source in
# question to exempt individual functions using MOZ_NO_SANITIZE_UINT_OVERFLOW, # question to exempt specific functions using MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW,
# do that instead. # do that instead.
# #
# The extensive number of entries below is for two reasons. # The extensive number of entries below is for two reasons.
# #
# First, compiler instrumentation for unsigned integer overflows has a cost, at # First, compiler instrumentation for unsigned integer overflows has a cost, at
# compile time and at runtime. In places where code expects and depends upon # compile time and at runtime. In places where code expects and depends upon
# overflow behavior -- and especially in performance-critical code -- it makes # overflow behavior -- and especially in performance-critical code -- it makes
# sense to turn off overflow detection to avoid both costs. (Indeed, # sense to turn off overflow detection to avoid both costs. (Indeed,
# -fsanitize=signed-integer-overflow is unusably slow without this.) # -fsanitize=signed-integer-overflow is unusably slow without this.)
# #
# Second, many entries here are overly aggressive to get the build into a state # Second, many entries here are overly aggressive to get the build into a state
# that allows any testing to happen at all. Some of the entries here are for # that allows any testing to happen at all. Some of the entries here are for
# issues that are highly frequent in our test suites -- over 500 times per run. # issues that are highly frequent in our test suites -- over 500 times per run.
# Aggressive entries now let us start using this mode, without having to first # Aggressive entries now let us start using this mode, without having to first
# fix wide swaths of existing code. # fix wide swaths of existing code.
# #
# Entries should be removed 1) as issues are fixed; and 2) as blacklist entries # Entries should be removed 1) as issues are fixed; and 2) as blacklist entries
# can be moved out of this centralized file, into source-level blacklist # can be moved out of this centralized file, into source-level blacklist
# attributes on individual functions. # attributes on individual functions.
# All entries in this file are to suppress unsigned-integer-overflow problems. # All entries in this file are to suppress unsigned-integer-overflow problems.
# Blacklists for other reasons should go in separate blacklist files. # Blacklists for other reasons should go in separate blacklist files.
[unsigned-integer-overflow] [unsigned-integer-overflow]
# Overflows in the C++ std headers aren't necessarily bugs, because code inside # Overflows in the C++ std headers aren't necessarily bugs, because code inside
# a language implementation can depend on compiler-specific behavior where C/C++ # a language implementation can depend on compiler-specific behavior where C/C++
# leave the behavior undefined. # leave the behavior undefined.
src:*bits/basic_string.h src:*bits/basic_string.h
# Assume everything running through CheckedInt.h is ok. The CheckedInt class # Assume everything running through CheckedInt.h is ok. The CheckedInt class
# casts signed integers to unsigned first and then does a post-overflow # casts signed integers to unsigned first and then does a post-overflow
# check causing lots of unsigned integer overflow messages. # check causing lots of unsigned integer overflow messages.
src:*/CheckedInt.h src:*/CheckedInt.h
# Exclude bignum # Exclude bignum
src:*/mfbt/double-conversion/source/bignum.cc src:*/mfbt/double-conversion/source/bignum.cc
# Exclude anything within gtests # Exclude anything within gtests
src:*/gtest/* src:*/gtest/*
# The JS engine has a lot of code doing all sorts of overflows. This code # The JS engine has a lot of code doing all sorts of overflows. This code
# is pretty well tested though and excluding it here will allow us to go # is pretty well tested though and excluding it here will allow us to go
# for other, less tested code. Ideally, we would include the JS engine here # for other, less tested code. Ideally, we would include the JS engine here
# at some point. # at some point.
src:*/js/src/* src:*/js/src/*
src:*/js/public/* src:*/js/public/*
src:*/js/*.h src:*/js/*.h
src:*/jsfriendapi.h src:*/jsfriendapi.h
# Atomics can overflow, but without a full stack we can't trace these back # Atomics can overflow, but without a full stack we can't trace these back
# to what is actually causing the overflow. Ignoring these for now, as it will # to what is actually causing the overflow. Ignoring these for now, as it will
# be too much effort to determine every single source here. # be too much effort to determine every single source here.
src:*/mfbt/Atomics.h src:*/mfbt/Atomics.h
# No reason to instrument certain parts of NSS that explicitely deal with # No reason to instrument certain parts of NSS that explicitely deal with
# arithmetics and crypto. # arithmetics and crypto.
src:*/security/nss/lib/freebl/mpi/* src:*/security/nss/lib/freebl/mpi/*
src:*/security/nss/lib/freebl/ecl/* src:*/security/nss/lib/freebl/ecl/*
# nsTArray_base<Alloc, Copy>::ShiftData performs overflows # nsTArray_base<Alloc, Copy>::ShiftData performs overflows
fun:*nsTArray_base*ShiftData* fun:*nsTArray_base*ShiftData*
### Frequent 0 - 1 overflows ### Frequent 0 - 1 overflows
# #
# We have several code patterns in our codebase that cause these overflows, # We have several code patterns in our codebase that cause these overflows,
# but they are typically all harmless and could be filtered easily at runtime. # but they are typically all harmless and could be filtered easily at runtime.
# However, some of them are so frequent that suppressing them at compile-time # However, some of them are so frequent that suppressing them at compile-time
# makes sense to increase runtime performance. # makes sense to increase runtime performance.
# #
src:*/netwerk/base/nsSocketTransportService2.cpp src:*/netwerk/base/nsSocketTransportService2.cpp
src:*/dom/xul/XULDocument.cpp src:*/dom/xul/XULDocument.cpp
src:*/nsCharTraits.h src:*/nsCharTraits.h
# Code in xpcom/base/CycleCollectedJSContext.cpp # Code in xpcom/base/CycleCollectedJSContext.cpp
fun:*CycleCollectedJSContext*ProcessMetastableStateQueue* fun:*CycleCollectedJSContext*ProcessMetastableStateQueue*
# Code in layout/painting/nsDisplayList.cpp # Code in layout/painting/nsDisplayList.cpp
fun:*nsDisplayOpacity*ShouldFlattenAway* fun:*nsDisplayOpacity*ShouldFlattenAway*
# Code in modules/libpref/Preferences.cpp # Code in modules/libpref/Preferences.cpp
fun:*pref_InitInitialObjects* fun:*pref_InitInitialObjects*
# Code in netwerk/base/nsIOService.cpp # Code in netwerk/base/nsIOService.cpp
fun:*nsIOService*GetCachedProtocolHandler* fun:*nsIOService*GetCachedProtocolHandler*
# Code in layout/style/nsCSSRuleProcessor.cpp # Code in layout/style/nsCSSRuleProcessor.cpp
fun:*0nsCSSRuleProcessor@@* fun:*0nsCSSRuleProcessor@@*
fun:*nsCSSRuleProcessor*ClearSheets* fun:*nsCSSRuleProcessor*ClearSheets*
fun:*TreeMatchContext*InitAncestors* fun:*TreeMatchContext*InitAncestors*
fun:*TreeMatchContext*InitStyleScopes* fun:*TreeMatchContext*InitStyleScopes*
# Code in layout/xul/nsXULPopupManager.cpp # Code in layout/xul/nsXULPopupManager.cpp
fun:*nsXULPopupManager*AdjustPopupsOnWindowChange* fun:*nsXULPopupManager*AdjustPopupsOnWindowChange*
# Code in dom/base/nsDocument.cpp # Code in dom/base/nsDocument.cpp
fun:*1nsDocument@@* fun:*1nsDocument@@*
# Code in gfx/layers/ipc/CompositorBridgeChild.cpp # Code in gfx/layers/ipc/CompositorBridgeChild.cpp
fun:*CompositorBridgeChild*Destroy* fun:*CompositorBridgeChild*Destroy*
# Code in gfx/layers/ipc/ImageBridgeChild.cpp # Code in gfx/layers/ipc/ImageBridgeChild.cpp
fun:*ImageBridgeChild*ShutdownStep1* fun:*ImageBridgeChild*ShutdownStep1*
# Code in dom/base/nsGlobalWindow.cpp # Code in dom/base/nsGlobalWindow.cpp
fun:*nsGlobalWindow*ClearControllers* fun:*nsGlobalWindow*ClearControllers*
# Code in layout/style/AnimationCollection.cpp # Code in layout/style/AnimationCollection.cpp
fun:*AnimationCollection*PropertyDtor* fun:*AnimationCollection*PropertyDtor*
# Code in layout/style/nsStyleSet.cpp # Code in layout/style/nsStyleSet.cpp
fun:*nsStyleSet*AddImportantRules* fun:*nsStyleSet*AddImportantRules*
fun:*nsStyleSet*CounterStyleRuleForName* fun:*nsStyleSet*CounterStyleRuleForName*
### Misc overflows ### Misc overflows
# Hot function in protobuf producing overflows # Hot function in protobuf producing overflows
fun:*CodedInputStream*ReadTagWithCutoff* fun:*CodedInputStream*ReadTagWithCutoff*
# SQLite3 is full of overflows :/ # SQLite3 is full of overflows :/
src:*/db/sqlite3/src/sqlite3.c src:*/db/sqlite3/src/sqlite3.c
# zlib has some overflows, we can't deal with them right now # zlib has some overflows, we can't deal with them right now
src:*/modules/zlib/src/* src:*/modules/zlib/src/*
# Our LZ4 implementation uses overflows. By listing it here we might # Our LZ4 implementation uses overflows. By listing it here we might
# miss some unintended overflows in that implementation, but we can't # miss some unintended overflows in that implementation, but we can't
# check for it right now. # check for it right now.
src:*/mfbt/lz4.c src:*/mfbt/lz4.c
# Apparently this overflows a lot, because it contains some allocators # Apparently this overflows a lot, because it contains some allocators
# that keep overflowing, not sure why. Disabling by function didn't seem # that keep overflowing, not sure why. Disabling by function didn't seem
# to work here for operator new. # to work here for operator new.
src:*/xpcom/ds/nsArrayEnumerator.cpp src:*/xpcom/ds/nsArrayEnumerator.cpp
# Memory usage reporting code in gfx/thebes/gfxASurface.cpp # Memory usage reporting code in gfx/thebes/gfxASurface.cpp
# We probably don't care about the frequent overflows there. # We probably don't care about the frequent overflows there.
fun:*SurfaceMemoryReporter*AdjustUsedMemory* fun:*SurfaceMemoryReporter*AdjustUsedMemory*
# Frequent overflower in gfx/thebes/gfxFontEntry.cpp # Frequent overflower in gfx/thebes/gfxFontEntry.cpp
fun:*WeightDistance* fun:*WeightDistance*
# Another frequent overflower # Another frequent overflower
fun:*nsTObserverArray_base*AdjustIterators* fun:*nsTObserverArray_base*AdjustIterators*
# Overflows in Skia # Overflows in Skia
fun:*SkPathRef*makeSpace* fun:*SkPathRef*makeSpace*
fun:*SkPathRef*resetToSize* fun:*SkPathRef*resetToSize*
# Expat Parser has some overflows # Expat Parser has some overflows
fun:*nsExpatDriver*ConsumeToken* fun:*nsExpatDriver*ConsumeToken*
# Frequent overflowers in harfbuzz # Frequent overflowers in harfbuzz
fun:*hb_in_range* fun:*hb_in_range*
fun:*OT*collect_glyphs* fun:*OT*collect_glyphs*
# These look like harmless layouting-related overflows # These look like harmless layouting-related overflows
src:*/gfx/cairo/libpixman/src/pixman-region.c src:*/gfx/cairo/libpixman/src/pixman-region.c
# Code in ipc/chromium/src/base/file_path.cc where a function returns -1 # Code in ipc/chromium/src/base/file_path.cc where a function returns -1
# being cast to unsigned and then overflowed. # being cast to unsigned and then overflowed.
fun:*FilePath*Append* fun:*FilePath*Append*
fun:*FilePath*StripTrailingSeparatorsInternal* fun:*FilePath*StripTrailingSeparatorsInternal*
# Code in dom/base/nsJSEnvironment.cpp # Code in dom/base/nsJSEnvironment.cpp
fun:*FireForgetSkippable* fun:*FireForgetSkippable*
# Code in gfx/thebes/gfxSkipChars.h # Code in gfx/thebes/gfxSkipChars.h
fun:*gfxSkipCharsIterator*AdvanceSkipped* fun:*gfxSkipCharsIterator*AdvanceSkipped*
# Code in gfx/thebes/gfxScriptItemizer.cpp # Code in gfx/thebes/gfxScriptItemizer.cpp
fun:*gfxScriptItemizer*fixup* fun:*gfxScriptItemizer*fixup*
fun:*gfxScriptItemizer*push* fun:*gfxScriptItemizer*push*
# Code in dom/base/nsDocument.cpp # Code in dom/base/nsDocument.cpp
fun:*nsDocument*BlockOnload* fun:*nsDocument*BlockOnload*
# Code in layout/base/nsCSSFrameConstructor.cpp # Code in layout/base/nsCSSFrameConstructor.cpp
fun:*nsCSSFrameConstructor*FrameConstructionItemList*AdjustCountsForItem* fun:*nsCSSFrameConstructor*FrameConstructionItemList*AdjustCountsForItem*
# Code in nsprpub/lib/ds/plarena.c doing ptrdiffs # Code in nsprpub/lib/ds/plarena.c doing ptrdiffs
fun:*PL_ArenaRelease* fun:*PL_ArenaRelease*
# This file contains a bunch of arithmetic operations on timestamps that # This file contains a bunch of arithmetic operations on timestamps that
# apparently are allowed to overflow. # apparently are allowed to overflow.
src:*/src/widget/SystemTimeConverter.h src:*/src/widget/SystemTimeConverter.h
# Code in dom/media/flac/FlacDemuxer.cpp purposely uses overflowing arithmetics # Code in dom/media/flac/FlacDemuxer.cpp purposely uses overflowing arithmetics
fun:*Frame*FindNext* fun:*Frame*FindNext*
# Code in netwerk/base/nsStandardURL.cpp, # Code in netwerk/base/nsStandardURL.cpp,
# these methods return signed but the subtraction is first performed unsigned # these methods return signed but the subtraction is first performed unsigned
fun:*nsStandardURL*ReplaceSegment* fun:*nsStandardURL*ReplaceSegment*
# Code in netwerk/protocol/http/nsHttpChannel.cpp # Code in netwerk/protocol/http/nsHttpChannel.cpp
# same as previous with the previous entry. # same as previous with the previous entry.
fun:*nsHttpChannel*ReportNetVSCacheTelemetry* fun:*nsHttpChannel*ReportNetVSCacheTelemetry*
# Code in layout/tables/nsCellMap.cpp # Code in layout/tables/nsCellMap.cpp
# again subtraction then cast to signed. # again subtraction then cast to signed.
fun:*nsTableCellMap*GetColInfoAt* fun:*nsTableCellMap*GetColInfoAt*
# Code in layout/generic/nsTextFrame.cpp # Code in layout/generic/nsTextFrame.cpp
# again subtraction then cast to signed. # again subtraction then cast to signed.
fun:*nsTextFrame*CharacterDataChanged* fun:*nsTextFrame*CharacterDataChanged*
# Not sure what is going on in this file, but it doesn't look # Not sure what is going on in this file, but it doesn't look
# related to what we are looking for. # related to what we are looking for.
src:*/xpcom/base/CountingAllocatorBase.h src:*/xpcom/base/CountingAllocatorBase.h
# Code in dom/base/nsDOMNavigationTiming.cpp # Code in dom/base/nsDOMNavigationTiming.cpp
# Timestamp related, probably expecting the overflow # Timestamp related, probably expecting the overflow
fun:*nsDOMNavigationTiming*TimeStampToDOM* fun:*nsDOMNavigationTiming*TimeStampToDOM*
# Several unsigned arithmetic operations with -1 # Several unsigned arithmetic operations with -1
src:*/hal/HalWakeLock.cpp src:*/hal/HalWakeLock.cpp
# Code in layout/generic/nsGfxScrollFrame.cpp that produces # Code in layout/generic/nsGfxScrollFrame.cpp that produces
# somewhat frequent signed integer overflows. Probably harmless # somewhat frequent signed integer overflows. Probably harmless
# because it's layout code. # because it's layout code.
fun:*ClampAndAlignWithPixels* fun:*ClampAndAlignWithPixels*
# Likely benign overflow in mozglue/misc/TimeStamp_posix.cpp # Likely benign overflow in mozglue/misc/TimeStamp_posix.cpp
fun:*ClockResolutionNs* fun:*ClockResolutionNs*
# This header has all sorts of operators that do post-operation # This header has all sorts of operators that do post-operation
# overflow and underflow checking, triggering frequent reports # overflow and underflow checking, triggering frequent reports
src:*/mozglue/misc/TimeStamp.h src:*/mozglue/misc/TimeStamp.h
# #
# Various hashing functions, both regular and cryptographic ones # Various hashing functions, both regular and cryptographic ones
# #
src:*/dom/canvas/MurmurHash3.cpp src:*/dom/canvas/MurmurHash3.cpp
src:*/gfx/skia/skia/include/private/SkChecksum.h src:*/gfx/skia/skia/include/private/SkChecksum.h
src:*/intl/icu/source/common/unifiedcache.h src:*/intl/icu/source/common/unifiedcache.h
src:*/mfbt/SHA1.cpp src:*/mfbt/SHA1.cpp
src:*/modules/zlib/src/adler32.c src:*/modules/zlib/src/adler32.c
src:*/netwerk/cache/nsDiskCacheDevice.cpp src:*/netwerk/cache/nsDiskCacheDevice.cpp
src:*/netwerk/cache2/CacheHashUtils.cpp src:*/netwerk/cache2/CacheHashUtils.cpp
src:*/netwerk/sctp/src/netinet/sctp_sha1.c src:*/netwerk/sctp/src/netinet/sctp_sha1.c
src:*/netwerk/srtp/src/crypto/hash/sha1.c src:*/netwerk/srtp/src/crypto/hash/sha1.c
src:*/netwerk/sctp/src/netinet/sctp_sha1.c src:*/netwerk/sctp/src/netinet/sctp_sha1.c
src:*/nsprpub/lib/ds/plhash.c src:*/nsprpub/lib/ds/plhash.c
src:*/security/manager/ssl/md4.c src:*/security/manager/ssl/md4.c
src:*/security/nss/lib/dbm/src/h_func.c src:*/security/nss/lib/dbm/src/h_func.c
src:*/security/nss/lib/freebl/sha512.c src:*/security/nss/lib/freebl/sha512.c
src:*/security/nss/lib/freebl/md5.c src:*/security/nss/lib/freebl/md5.c
src:*/xpcom/ds/PLDHashTable.cpp src:*/xpcom/ds/PLDHashTable.cpp
# Hash/Cache function in Skia # Hash/Cache function in Skia
fun:*GradientShaderCache*Build32bitCache* fun:*GradientShaderCache*Build32bitCache*
# Hashing functions in Cairo # Hashing functions in Cairo
fun:*_hash_matrix_fnv* fun:*_hash_matrix_fnv*
fun:*_hash_mix_bits* fun:*_hash_mix_bits*
fun:*_cairo_hash_string* fun:*_cairo_hash_string*
fun:*_cairo_hash_bytes* fun:*_cairo_hash_bytes*
# intl code hashing functions # intl code hashing functions
fun:*ustr_hash*CharsN* fun:*ustr_hash*CharsN*
fun:*hashEntry* fun:*hashEntry*
# harfbuzz hash/digest functions # harfbuzz hash/digest functions
fun:*hb_set_digest_lowest_bits_t* fun:*hb_set_digest_lowest_bits_t*
# Hash function in gfx # Hash function in gfx
fun:*gfxFontStyle*Hash* fun:*gfxFontStyle*Hash*
# expat uses a CHAR_HASH macro in several places that causes # expat uses a CHAR_HASH macro in several places that causes
# a high amount of overflows. We should try finding a better # a high amount of overflows. We should try finding a better
# way to disable this rather than blacklisting the whole thing. # way to disable this rather than blacklisting the whole thing.
src:*/parser/expat/* src:*/parser/expat/*

Просмотреть файл

@ -91,7 +91,8 @@ nsChromeRegistry::LogMessageWithContext(nsIURI* aURL, uint32_t aLineNumber, uint
rv = error->Init(NS_ConvertUTF8toUTF16(formatted.get()), rv = error->Init(NS_ConvertUTF8toUTF16(formatted.get()),
NS_ConvertUTF8toUTF16(spec), NS_ConvertUTF8toUTF16(spec),
EmptyString(), EmptyString(),
aLineNumber, 0, flags, "chrome registration"); aLineNumber, 0, flags, "chrome registration",
false /* from private window */);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return; return;

Просмотреть файл

@ -120,8 +120,11 @@ CONFIG_TOOLS = $(MOZ_BUILD_ROOT)/config
AUTOCONF_TOOLS = $(MOZILLA_DIR)/build/autoconf AUTOCONF_TOOLS = $(MOZILLA_DIR)/build/autoconf
ifdef _MSC_VER ifdef _MSC_VER
# clang-cl is smart enough to generate dependencies directly.
ifndef CLANG_CL
CC_WRAPPER ?= $(call py_action,cl) CC_WRAPPER ?= $(call py_action,cl)
CXX_WRAPPER ?= $(call py_action,cl) CXX_WRAPPER ?= $(call py_action,cl)
endif # CLANG_CL
endif # _MSC_VER endif # _MSC_VER
CC := $(CC_WRAPPER) $(CC) CC := $(CC_WRAPPER) $(CC)

Просмотреть файл

@ -11,6 +11,7 @@ const { Provider } = require("devtools/client/shared/vendor/react-redux");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
const App = createFactory(require("./components/App")); const App = createFactory(require("./components/App"));
const CurrentTimeTimer = require("./current-time-timer");
const { const {
updateAnimations, updateAnimations,
@ -19,21 +20,38 @@ const {
updateSelectedAnimation, updateSelectedAnimation,
updateSidebarSize updateSidebarSize
} = require("./actions/animations"); } = require("./actions/animations");
const { isAllAnimationEqual } = require("./utils/utils"); const {
isAllAnimationEqual,
hasAnimationIterationCountInfinite,
hasRunningAnimation,
} = require("./utils/utils");
class AnimationInspector { class AnimationInspector {
constructor(inspector, win) { constructor(inspector, win) {
this.inspector = inspector; this.inspector = inspector;
this.win = win; this.win = win;
this.addAnimationsCurrentTimeListener =
this.addAnimationsCurrentTimeListener.bind(this);
this.getAnimatedPropertyMap = this.getAnimatedPropertyMap.bind(this); this.getAnimatedPropertyMap = this.getAnimatedPropertyMap.bind(this);
this.getAnimationsCurrentTime = this.getAnimationsCurrentTime.bind(this);
this.getComputedStyle = this.getComputedStyle.bind(this); this.getComputedStyle = this.getComputedStyle.bind(this);
this.getNodeFromActor = this.getNodeFromActor.bind(this); this.getNodeFromActor = this.getNodeFromActor.bind(this);
this.removeAnimationsCurrentTimeListener =
this.removeAnimationsCurrentTimeListener.bind(this);
this.rewindAnimationsCurrentTime = this.rewindAnimationsCurrentTime.bind(this);
this.selectAnimation = this.selectAnimation.bind(this); this.selectAnimation = this.selectAnimation.bind(this);
this.setAnimationsCurrentTime = this.setAnimationsCurrentTime.bind(this);
this.setAnimationsPlaybackRate = this.setAnimationsPlaybackRate.bind(this);
this.setAnimationsPlayState = this.setAnimationsPlayState.bind(this);
this.setDetailVisibility = this.setDetailVisibility.bind(this); this.setDetailVisibility = this.setDetailVisibility.bind(this);
this.simulateAnimation = this.simulateAnimation.bind(this); this.simulateAnimation = this.simulateAnimation.bind(this);
this.simulateAnimationForKeyframesProgressBar =
this.simulateAnimationForKeyframesProgressBar.bind(this);
this.toggleElementPicker = this.toggleElementPicker.bind(this); this.toggleElementPicker = this.toggleElementPicker.bind(this);
this.update = this.update.bind(this); this.update = this.update.bind(this);
this.onAnimationsCurrentTimeUpdated = this.onAnimationsCurrentTimeUpdated.bind(this);
this.onCurrentTimeTimerUpdated = this.onCurrentTimeTimerUpdated.bind(this);
this.onElementPickerStarted = this.onElementPickerStarted.bind(this); this.onElementPickerStarted = this.onElementPickerStarted.bind(this);
this.onElementPickerStopped = this.onElementPickerStopped.bind(this); this.onElementPickerStopped = this.onElementPickerStopped.bind(this);
this.onSidebarResized = this.onSidebarResized.bind(this); this.onSidebarResized = this.onSidebarResized.bind(this);
@ -56,19 +74,31 @@ class AnimationInspector {
} = this.inspector.getPanel("boxmodel").getComponentProps(); } = this.inspector.getPanel("boxmodel").getComponentProps();
const { const {
addAnimationsCurrentTimeListener,
emit: emitEventForTest, emit: emitEventForTest,
getAnimatedPropertyMap, getAnimatedPropertyMap,
getAnimationsCurrentTime,
getComputedStyle, getComputedStyle,
getNodeFromActor, getNodeFromActor,
isAnimationsRunning,
removeAnimationsCurrentTimeListener,
rewindAnimationsCurrentTime,
selectAnimation, selectAnimation,
setAnimationsCurrentTime,
setAnimationsPlaybackRate,
setAnimationsPlayState,
setDetailVisibility, setDetailVisibility,
simulateAnimation, simulateAnimation,
simulateAnimationForKeyframesProgressBar,
toggleElementPicker, toggleElementPicker,
} = this; } = this;
const target = this.inspector.target; const target = this.inspector.target;
this.animationsFront = new AnimationsFront(target.client, target.form); this.animationsFront = new AnimationsFront(target.client, target.form);
this.animationsCurrentTimeListeners = [];
this.isCurrentTimeSet = false;
const provider = createElement(Provider, const provider = createElement(Provider,
{ {
id: "newanimationinspector", id: "newanimationinspector",
@ -77,16 +107,25 @@ class AnimationInspector {
}, },
App( App(
{ {
addAnimationsCurrentTimeListener,
emitEventForTest, emitEventForTest,
getAnimatedPropertyMap, getAnimatedPropertyMap,
getAnimationsCurrentTime,
getComputedStyle, getComputedStyle,
getNodeFromActor, getNodeFromActor,
isAnimationsRunning,
onHideBoxModelHighlighter, onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode, onShowBoxModelHighlighterForNode,
removeAnimationsCurrentTimeListener,
rewindAnimationsCurrentTime,
selectAnimation, selectAnimation,
setAnimationsCurrentTime,
setAnimationsPlaybackRate,
setAnimationsPlayState,
setDetailVisibility, setDetailVisibility,
setSelectedNode, setSelectedNode,
simulateAnimation, simulateAnimation,
simulateAnimationForKeyframesProgressBar,
toggleElementPicker, toggleElementPicker,
} }
) )
@ -117,10 +156,25 @@ class AnimationInspector {
this.simulatedElement = null; this.simulatedElement = null;
} }
if (this.simulatedAnimationForKeyframesProgressBar) {
this.simulatedAnimationForKeyframesProgressBar.cancel();
this.simulatedAnimationForKeyframesProgressBar = null;
}
this.stopAnimationsCurrentTimeTimer();
this.inspector = null; this.inspector = null;
this.win = null; this.win = null;
} }
get state() {
return this.inspector.store.getState().animations;
}
addAnimationsCurrentTimeListener(listener) {
this.animationsCurrentTimeListeners.push(listener);
}
/** /**
* Return a map of animated property from given animation actor. * Return a map of animated property from given animation actor.
* *
@ -160,6 +214,10 @@ class AnimationInspector {
return animatedPropertyMap; return animatedPropertyMap;
} }
getAnimationsCurrentTime() {
return this.currentTime;
}
/** /**
* Return the computed style of the specified property after setting the given styles * Return the computed style of the specified property after setting the given styles
* to the simulated element. * to the simulated element.
@ -191,6 +249,110 @@ class AnimationInspector {
this.inspector.sidebar.getCurrentTabID() === "newanimationinspector"; this.inspector.sidebar.getCurrentTabID() === "newanimationinspector";
} }
/**
* This method should call when the current time is changed.
* Then, dispatches the current time to listeners that are registered
* by addAnimationsCurrentTimeListener.
*
* @param {Number} currentTime
*/
onAnimationsCurrentTimeUpdated(currentTime) {
this.currentTime = currentTime;
for (const listener of this.animationsCurrentTimeListeners) {
listener(currentTime);
}
}
/**
* This method is called when the current time proceed by CurrentTimeTimer.
*
* @param {Number} currentTime
* @param {Bool} shouldStop
*/
onCurrentTimeTimerUpdated(currentTime, shouldStop) {
if (shouldStop) {
this.setAnimationsCurrentTime(currentTime, true);
} else {
this.onAnimationsCurrentTimeUpdated(currentTime);
}
}
onElementPickerStarted() {
this.inspector.store.dispatch(updateElementPickerEnabled(true));
}
onElementPickerStopped() {
this.inspector.store.dispatch(updateElementPickerEnabled(false));
}
onSidebarSelect() {
this.update();
this.onSidebarResized(null, this.inspector.getSidebarSize());
}
onSidebarResized(type, size) {
if (!this.isPanelVisible()) {
return;
}
this.inspector.store.dispatch(updateSidebarSize(size));
}
removeAnimationsCurrentTimeListener(listener) {
this.animationsCurrentTimeListeners =
this.animationsCurrentTimeListeners.filter(l => l !== listener);
}
async rewindAnimationsCurrentTime() {
await this.setAnimationsCurrentTime(0, true);
}
selectAnimation(animation) {
this.inspector.store.dispatch(updateSelectedAnimation(animation));
}
async setAnimationsCurrentTime(currentTime, shouldRefresh) {
this.stopAnimationsCurrentTimeTimer();
this.onAnimationsCurrentTimeUpdated(currentTime);
if (!shouldRefresh && this.isCurrentTimeSet) {
return;
}
const animations = this.state.animations;
this.isCurrentTimeSet = true;
await this.animationsFront.setCurrentTimes(animations, currentTime, true);
await this.updateAnimations(animations);
this.isCurrentTimeSet = false;
if (shouldRefresh) {
this.updateState([...animations]);
}
}
async setAnimationsPlaybackRate(playbackRate) {
const animations = this.state.animations;
await this.animationsFront.setPlaybackRates(animations, playbackRate);
await this.updateAnimations(animations);
await this.updateState([...animations]);
}
async setAnimationsPlayState(doPlay) {
if (doPlay) {
await this.animationsFront.playAll();
} else {
await this.animationsFront.pauseAll();
}
await this.updateAnimations(this.state.animations);
await this.updateState([...this.state.animations]);
}
setDetailVisibility(isVisible) {
this.inspector.store.dispatch(updateDetailVisibility(isVisible));
}
/** /**
* Returns simulatable animation by given parameters. * Returns simulatable animation by given parameters.
* The returned animation is implementing Animation interface of Web Animation API. * The returned animation is implementing Animation interface of Web Animation API.
@ -233,6 +395,46 @@ class AnimationInspector {
return this.simulatedAnimation; return this.simulatedAnimation;
} }
/**
* Returns a simulatable efect timing animation for the keyframes progress bar.
* The returned animation is implementing Animation interface of Web Animation API.
* https://drafts.csswg.org/web-animations/#the-animation-interface
*
* @param {Object} effectTiming
* e.g. { duration: 1000, fill: "both" }
* @return {Animation}
* https://drafts.csswg.org/web-animations/#the-animation-interface
*/
simulateAnimationForKeyframesProgressBar(effectTiming) {
if (!this.simulatedAnimationForKeyframesProgressBar) {
this.simulatedAnimationForKeyframesProgressBar = new this.win.Animation();
}
this.simulatedAnimationForKeyframesProgressBar.effect =
new this.win.KeyframeEffect(null, null, effectTiming);
return this.simulatedAnimationForKeyframesProgressBar;
}
stopAnimationsCurrentTimeTimer() {
if (this.currentTimeTimer) {
this.currentTimeTimer.destroy();
this.currentTimeTimer = null;
}
}
startAnimationsCurrentTimeTimer() {
const timeScale = this.state.timeScale;
const shouldStopAfterEndTime =
!hasAnimationIterationCountInfinite(this.state.animations);
const currentTimeTimer =
new CurrentTimeTimer(timeScale, shouldStopAfterEndTime,
this.win, this.onCurrentTimeTimerUpdated);
currentTimeTimer.start();
this.currentTimeTimer = currentTimeTimer;
}
toggleElementPicker() { toggleElementPicker() {
this.inspector.toolbox.highlighterUtils.togglePicker(); this.inspector.toolbox.highlighterUtils.togglePicker();
} }
@ -246,48 +448,35 @@ class AnimationInspector {
const done = this.inspector.updating("newanimationinspector"); const done = this.inspector.updating("newanimationinspector");
const selection = this.inspector.selection; const selection = this.inspector.selection;
const animations = const nextAnimations =
selection.isConnected() && selection.isElementNode() selection.isConnected() && selection.isElementNode()
? await this.animationsFront.getAnimationPlayersForNode(selection.nodeFront) ? await this.animationsFront.getAnimationPlayersForNode(selection.nodeFront)
: []; : [];
const currentAnimations = this.state.animations;
if (!this.animations || !isAllAnimationEqual(animations, this.animations)) { if (!currentAnimations || !isAllAnimationEqual(currentAnimations, nextAnimations)) {
this.inspector.store.dispatch(updateAnimations(animations)); this.updateState(nextAnimations);
this.animations = animations;
// If number of displayed animations is one, we select the animation automatically.
this.selectAnimation(animations.length === 1 ? animations[0] : null);
} }
done(); done();
} }
selectAnimation(animation) { async updateAnimations(animations) {
this.inspector.store.dispatch(updateSelectedAnimation(animation)); const promises = animations.map(animation => {
return animation.refreshState();
});
await Promise.all(promises);
} }
setDetailVisibility(isVisible) { updateState(animations) {
this.inspector.store.dispatch(updateDetailVisibility(isVisible)); this.stopAnimationsCurrentTimeTimer();
}
onElementPickerStarted() { this.inspector.store.dispatch(updateAnimations(animations));
this.inspector.store.dispatch(updateElementPickerEnabled(true));
}
onElementPickerStopped() { if (hasRunningAnimation(animations)) {
this.inspector.store.dispatch(updateElementPickerEnabled(false)); this.startAnimationsCurrentTimeTimer();
}
onSidebarSelect() {
this.update();
this.onSidebarResized(null, this.inspector.getSidebarSize());
}
onSidebarResized(type, size) {
if (!this.isPanelVisible()) {
return;
} }
this.inspector.store.dispatch(updateSidebarSize(size));
} }
} }

Просмотреть файл

@ -14,28 +14,47 @@ const AnimatedPropertyListHeader = createFactory(require("./AnimatedPropertyList
class AnimatedPropertyListContainer extends PureComponent { class AnimatedPropertyListContainer extends PureComponent {
static get propTypes() { static get propTypes() {
return { return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
animation: PropTypes.object.isRequired, animation: PropTypes.object.isRequired,
emitEventForTest: PropTypes.func.isRequired, emitEventForTest: PropTypes.func.isRequired,
getAnimatedPropertyMap: PropTypes.func.isRequired, getAnimatedPropertyMap: PropTypes.func.isRequired,
getAnimationsCurrentTime: PropTypes.func.isRequired,
getComputedStyle: PropTypes.func.isRequired, getComputedStyle: PropTypes.func.isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
simulateAnimation: PropTypes.func.isRequired, simulateAnimation: PropTypes.func.isRequired,
simulateAnimationForKeyframesProgressBar: PropTypes.func.isRequired,
timeScale: PropTypes.object.isRequired,
}; };
} }
render() { render() {
const { const {
addAnimationsCurrentTimeListener,
animation, animation,
emitEventForTest, emitEventForTest,
getAnimatedPropertyMap, getAnimatedPropertyMap,
getAnimationsCurrentTime,
getComputedStyle, getComputedStyle,
removeAnimationsCurrentTimeListener,
simulateAnimation, simulateAnimation,
simulateAnimationForKeyframesProgressBar,
timeScale,
} = this.props; } = this.props;
return dom.div( return dom.div(
{ {
className: `animated-property-list-container ${ animation.state.type }` className: `animated-property-list-container ${ animation.state.type }`
}, },
AnimatedPropertyListHeader(), AnimatedPropertyListHeader(
{
addAnimationsCurrentTimeListener,
animation,
getAnimationsCurrentTime,
removeAnimationsCurrentTimeListener,
simulateAnimationForKeyframesProgressBar,
timeScale,
}
),
AnimatedPropertyList( AnimatedPropertyList(
{ {
animation, animation,

Просмотреть файл

@ -6,16 +6,48 @@
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories"); const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const KeyframesProgressBar = createFactory(require("./KeyframesProgressBar"));
const KeyframesProgressTickList = createFactory(require("./KeyframesProgressTickList")); const KeyframesProgressTickList = createFactory(require("./KeyframesProgressTickList"));
class AnimatedPropertyListHeader extends PureComponent { class AnimatedPropertyListHeader extends PureComponent {
static get propTypes() {
return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
animation: PropTypes.object.isRequired,
getAnimationsCurrentTime: PropTypes.func.isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
simulateAnimationForKeyframesProgressBar: PropTypes.func.isRequired,
timeScale: PropTypes.object.isRequired,
};
}
render() { render() {
const {
addAnimationsCurrentTimeListener,
animation,
getAnimationsCurrentTime,
removeAnimationsCurrentTimeListener,
simulateAnimationForKeyframesProgressBar,
timeScale,
} = this.props;
return dom.div( return dom.div(
{ {
className: "animated-property-list-header devtools-toolbar" className: "animated-property-list-header devtools-toolbar"
}, },
KeyframesProgressTickList() KeyframesProgressTickList(),
KeyframesProgressBar(
{
addAnimationsCurrentTimeListener,
animation,
getAnimationsCurrentTime,
removeAnimationsCurrentTimeListener,
simulateAnimationForKeyframesProgressBar,
timeScale,
}
)
); );
} }
} }

Просмотреть файл

@ -16,23 +16,33 @@ const AnimatedPropertyListContainer =
class AnimationDetailContainer extends PureComponent { class AnimationDetailContainer extends PureComponent {
static get propTypes() { static get propTypes() {
return { return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
animation: PropTypes.object.isRequired, animation: PropTypes.object.isRequired,
emitEventForTest: PropTypes.func.isRequired, emitEventForTest: PropTypes.func.isRequired,
getAnimatedPropertyMap: PropTypes.func.isRequired, getAnimatedPropertyMap: PropTypes.func.isRequired,
getAnimationsCurrentTime: PropTypes.func.isRequired,
getComputedStyle: PropTypes.func.isRequired, getComputedStyle: PropTypes.func.isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
setDetailVisibility: PropTypes.func.isRequired, setDetailVisibility: PropTypes.func.isRequired,
simulateAnimation: PropTypes.func.isRequired, simulateAnimation: PropTypes.func.isRequired,
simulateAnimationForKeyframesProgressBar: PropTypes.func.isRequired,
timeScale: PropTypes.object.isRequired,
}; };
} }
render() { render() {
const { const {
addAnimationsCurrentTimeListener,
animation, animation,
emitEventForTest, emitEventForTest,
getAnimatedPropertyMap, getAnimatedPropertyMap,
getAnimationsCurrentTime,
getComputedStyle, getComputedStyle,
removeAnimationsCurrentTimeListener,
setDetailVisibility, setDetailVisibility,
simulateAnimation, simulateAnimation,
simulateAnimationForKeyframesProgressBar,
timeScale,
} = this.props; } = this.props;
return dom.div( return dom.div(
@ -51,11 +61,16 @@ class AnimationDetailContainer extends PureComponent {
animation ? animation ?
AnimatedPropertyListContainer( AnimatedPropertyListContainer(
{ {
addAnimationsCurrentTimeListener,
animation, animation,
emitEventForTest, emitEventForTest,
getAnimatedPropertyMap, getAnimatedPropertyMap,
getAnimationsCurrentTime,
getComputedStyle, getComputedStyle,
removeAnimationsCurrentTimeListener,
simulateAnimation, simulateAnimation,
simulateAnimationForKeyframesProgressBar,
timeScale,
} }
) )
: :

Просмотреть файл

@ -18,7 +18,8 @@ class AnimationDetailHeader extends PureComponent {
}; };
} }
onClick() { onClick(event) {
event.stopPropagation();
const { setDetailVisibility } = this.props; const { setDetailVisibility } = this.props;
setDetailVisibility(false); setDetailVisibility(false);
} }

Просмотреть файл

@ -12,36 +12,41 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories");
const AnimationList = createFactory(require("./AnimationList")); const AnimationList = createFactory(require("./AnimationList"));
const AnimationListHeader = createFactory(require("./AnimationListHeader")); const AnimationListHeader = createFactory(require("./AnimationListHeader"));
const TimeScale = require("../utils/timescale");
class AnimationListContainer extends PureComponent { class AnimationListContainer extends PureComponent {
static get propTypes() { static get propTypes() {
return { return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
animations: PropTypes.arrayOf(PropTypes.object).isRequired, animations: PropTypes.arrayOf(PropTypes.object).isRequired,
emitEventForTest: PropTypes.func.isRequired, emitEventForTest: PropTypes.func.isRequired,
getAnimatedPropertyMap: PropTypes.func.isRequired, getAnimatedPropertyMap: PropTypes.func.isRequired,
getNodeFromActor: PropTypes.func.isRequired, getNodeFromActor: PropTypes.func.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired, onHideBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired, onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
selectAnimation: PropTypes.func.isRequired, selectAnimation: PropTypes.func.isRequired,
setAnimationsCurrentTime: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired, setSelectedNode: PropTypes.func.isRequired,
simulateAnimation: PropTypes.func.isRequired, simulateAnimation: PropTypes.func.isRequired,
timeScale: PropTypes.object.isRequired,
}; };
} }
render() { render() {
const { const {
addAnimationsCurrentTimeListener,
animations, animations,
emitEventForTest, emitEventForTest,
getAnimatedPropertyMap, getAnimatedPropertyMap,
getNodeFromActor, getNodeFromActor,
onHideBoxModelHighlighter, onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode, onShowBoxModelHighlighterForNode,
removeAnimationsCurrentTimeListener,
selectAnimation, selectAnimation,
setAnimationsCurrentTime,
setSelectedNode, setSelectedNode,
simulateAnimation, simulateAnimation,
timeScale,
} = this.props; } = this.props;
const timeScale = new TimeScale(animations);
return dom.div( return dom.div(
{ {
@ -49,6 +54,9 @@ class AnimationListContainer extends PureComponent {
}, },
AnimationListHeader( AnimationListHeader(
{ {
addAnimationsCurrentTimeListener,
removeAnimationsCurrentTimeListener,
setAnimationsCurrentTime,
timeScale, timeScale,
} }
), ),

Просмотреть файл

@ -10,16 +10,26 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories"); const dom = require("devtools/client/shared/vendor/react-dom-factories");
const AnimationTimelineTickList = createFactory(require("./AnimationTimelineTickList")); const AnimationTimelineTickList = createFactory(require("./AnimationTimelineTickList"));
const CurrentTimeScrubberController =
createFactory(require("./CurrentTimeScrubberController"));
class AnimationListHeader extends PureComponent { class AnimationListHeader extends PureComponent {
static get propTypes() { static get propTypes() {
return { return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
setAnimationsCurrentTime: PropTypes.func.isRequired,
timeScale: PropTypes.object.isRequired, timeScale: PropTypes.object.isRequired,
}; };
} }
render() { render() {
const { timeScale } = this.props; const {
addAnimationsCurrentTimeListener,
removeAnimationsCurrentTimeListener,
setAnimationsCurrentTime,
timeScale,
} = this.props;
return dom.div( return dom.div(
{ {
@ -29,6 +39,14 @@ class AnimationListHeader extends PureComponent {
{ {
timeScale timeScale
} }
),
CurrentTimeScrubberController(
{
addAnimationsCurrentTimeListener,
removeAnimationsCurrentTimeListener,
setAnimationsCurrentTime,
timeScale,
}
) )
); );
} }

Просмотреть файл

@ -35,11 +35,11 @@ class AnimationTimelineTickList extends PureComponent {
} }
componentDidMount() { componentDidMount() {
this.updateTickList(); this.updateTickList(this.props);
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
this.updateTickList(); this.updateTickList(nextProps);
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
@ -51,7 +51,7 @@ class AnimationTimelineTickList extends PureComponent {
const currentTickItem = this.state.tickList[i]; const currentTickItem = this.state.tickList[i];
const nextTickItem = nextState.tickList[i]; const nextTickItem = nextState.tickList[i];
if (currentTickItem.text !== nextTickItem.text) { if (currentTickItem.timeTickLabel !== nextTickItem.timeTickLabel) {
return true; return true;
} }
} }
@ -59,8 +59,8 @@ class AnimationTimelineTickList extends PureComponent {
return false; return false;
} }
updateTickList() { updateTickList(props) {
const { timeScale } = this.props; const { timeScale } = props;
const tickListEl = ReactDOM.findDOMNode(this); const tickListEl = ReactDOM.findDOMNode(this);
const width = tickListEl.offsetWidth; const width = tickListEl.offsetWidth;
const animationDuration = timeScale.getDuration(); const animationDuration = timeScale.getDuration();

Просмотреть файл

@ -0,0 +1,69 @@
/* 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";
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const CurrentTimeLabel = createFactory(require("./CurrentTimeLabel"));
const PauseResumeButton = createFactory(require("./PauseResumeButton"));
const PlaybackRateSelector = createFactory(require("./PlaybackRateSelector"));
const RewindButton = createFactory(require("./RewindButton"));
class AnimationToolbar extends PureComponent {
static get propTypes() {
return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
animations: PropTypes.arrayOf(PropTypes.object).isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
rewindAnimationsCurrentTime: PropTypes.func.isRequired,
setAnimationsPlaybackRate: PropTypes.func.isRequired,
setAnimationsPlayState: PropTypes.func.isRequired,
};
}
render() {
const {
addAnimationsCurrentTimeListener,
animations,
removeAnimationsCurrentTimeListener,
rewindAnimationsCurrentTime,
setAnimationsPlaybackRate,
setAnimationsPlayState,
} = this.props;
return dom.div(
{
className: "animation-toolbar devtools-toolbar",
},
RewindButton(
{
rewindAnimationsCurrentTime,
}
),
PauseResumeButton(
{
animations,
setAnimationsPlayState,
}
),
PlaybackRateSelector(
{
animations,
setAnimationsPlaybackRate,
}
),
CurrentTimeLabel(
{
addAnimationsCurrentTimeListener,
removeAnimationsCurrentTimeListener,
}
)
);
}
}
module.exports = AnimationToolbar;

Просмотреть файл

@ -11,24 +11,34 @@ const { connect } = require("devtools/client/shared/vendor/react-redux");
const AnimationDetailContainer = createFactory(require("./AnimationDetailContainer")); const AnimationDetailContainer = createFactory(require("./AnimationDetailContainer"));
const AnimationListContainer = createFactory(require("./AnimationListContainer")); const AnimationListContainer = createFactory(require("./AnimationListContainer"));
const AnimationToolbar = createFactory(require("./AnimationToolbar"));
const NoAnimationPanel = createFactory(require("./NoAnimationPanel")); const NoAnimationPanel = createFactory(require("./NoAnimationPanel"));
const SplitBox = createFactory(require("devtools/client/shared/components/splitter/SplitBox")); const SplitBox = createFactory(require("devtools/client/shared/components/splitter/SplitBox"));
class App extends PureComponent { class App extends PureComponent {
static get propTypes() { static get propTypes() {
return { return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
animations: PropTypes.arrayOf(PropTypes.object).isRequired, animations: PropTypes.arrayOf(PropTypes.object).isRequired,
detailVisibility: PropTypes.bool.isRequired, detailVisibility: PropTypes.bool.isRequired,
emitEventForTest: PropTypes.func.isRequired, emitEventForTest: PropTypes.func.isRequired,
getAnimatedPropertyMap: PropTypes.func.isRequired, getAnimatedPropertyMap: PropTypes.func.isRequired,
getAnimationsCurrentTime: PropTypes.func.isRequired,
getComputedStyle: PropTypes.func.isRequired, getComputedStyle: PropTypes.func.isRequired,
getNodeFromActor: PropTypes.func.isRequired, getNodeFromActor: PropTypes.func.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired, onHideBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired, onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
rewindAnimationsCurrentTime: PropTypes.func.isRequired,
selectAnimation: PropTypes.func.isRequired, selectAnimation: PropTypes.func.isRequired,
setAnimationsCurrentTime: PropTypes.func.isRequired,
setAnimationsPlaybackRate: PropTypes.func.isRequired,
setAnimationsPlayState: PropTypes.func.isRequired,
setDetailVisibility: PropTypes.func.isRequired, setDetailVisibility: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired, setSelectedNode: PropTypes.func.isRequired,
simulateAnimation: PropTypes.func.isRequired, simulateAnimation: PropTypes.func.isRequired,
simulateAnimationForKeyframesProgressBar: PropTypes.func.isRequired,
timeScale: PropTypes.object.isRequired,
toggleElementPicker: PropTypes.func.isRequired, toggleElementPicker: PropTypes.func.isRequired,
}; };
} }
@ -39,18 +49,27 @@ class App extends PureComponent {
render() { render() {
const { const {
addAnimationsCurrentTimeListener,
animations, animations,
detailVisibility, detailVisibility,
emitEventForTest, emitEventForTest,
getAnimatedPropertyMap, getAnimatedPropertyMap,
getAnimationsCurrentTime,
getComputedStyle, getComputedStyle,
getNodeFromActor, getNodeFromActor,
onHideBoxModelHighlighter, onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode, onShowBoxModelHighlighterForNode,
removeAnimationsCurrentTimeListener,
rewindAnimationsCurrentTime,
selectAnimation, selectAnimation,
setAnimationsCurrentTime,
setAnimationsPlaybackRate,
setAnimationsPlayState,
setDetailVisibility, setDetailVisibility,
setSelectedNode, setSelectedNode,
simulateAnimation, simulateAnimation,
simulateAnimationForKeyframesProgressBar,
timeScale,
toggleElementPicker, toggleElementPicker,
} = this.props; } = this.props;
@ -58,37 +77,59 @@ class App extends PureComponent {
{ {
id: "animation-container", id: "animation-container",
className: detailVisibility ? "animation-detail-visible" : "", className: detailVisibility ? "animation-detail-visible" : "",
tabIndex: -1,
}, },
animations.length ? animations.length ?
SplitBox({ [
className: "animation-container-splitter", AnimationToolbar(
endPanel: AnimationDetailContainer(
{
emitEventForTest,
getAnimatedPropertyMap,
getComputedStyle,
setDetailVisibility,
simulateAnimation,
}
),
endPanelControl: true,
initialHeight: "50%",
splitterSize: 1,
startPanel: AnimationListContainer(
{ {
addAnimationsCurrentTimeListener,
animations, animations,
emitEventForTest, removeAnimationsCurrentTimeListener,
getAnimatedPropertyMap, rewindAnimationsCurrentTime,
getNodeFromActor, setAnimationsPlaybackRate,
onHideBoxModelHighlighter, setAnimationsPlayState,
onShowBoxModelHighlighterForNode,
selectAnimation,
setSelectedNode,
simulateAnimation,
} }
), ),
vert: false, SplitBox({
}) className: "animation-container-splitter",
endPanel: AnimationDetailContainer(
{
addAnimationsCurrentTimeListener,
emitEventForTest,
getAnimatedPropertyMap,
getAnimationsCurrentTime,
getComputedStyle,
removeAnimationsCurrentTimeListener,
setDetailVisibility,
simulateAnimation,
simulateAnimationForKeyframesProgressBar,
timeScale,
}
),
endPanelControl: true,
initialHeight: "50%",
splitterSize: 1,
startPanel: AnimationListContainer(
{
addAnimationsCurrentTimeListener,
animations,
emitEventForTest,
getAnimatedPropertyMap,
getNodeFromActor,
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
removeAnimationsCurrentTimeListener,
selectAnimation,
setAnimationsCurrentTime,
setSelectedNode,
simulateAnimation,
timeScale,
}
),
vert: false,
})
]
: :
NoAnimationPanel( NoAnimationPanel(
{ {
@ -103,6 +144,7 @@ const mapStateToProps = state => {
return { return {
animations: state.animations.animations, animations: state.animations.animations,
detailVisibility: state.animations.detailVisibility, detailVisibility: state.animations.detailVisibility,
timeScale: state.animations.timeScale,
}; };
}; };

Просмотреть файл

@ -0,0 +1,83 @@
/* 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";
const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
class CurrentTimeLabel extends PureComponent {
static get propTypes() {
return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
};
}
constructor(props) {
super(props);
const { addAnimationsCurrentTimeListener } = props;
this.onCurrentTimeUpdated = this.onCurrentTimeUpdated.bind(this);
this.state = {
currentTime: 0,
};
addAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
}
componentWillUnmount() {
const { removeAnimationsCurrentTimeListener } = this.props;
removeAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
}
onCurrentTimeUpdated(currentTime) {
this.setState({ currentTime });
}
render() {
const { currentTime } = this.state;
return dom.label(
{
className: "current-time-label",
},
formatStopwatchTime(currentTime)
);
}
}
/**
* Format a timestamp (in ms) as a mm:ss.mmm string.
*
* @param {Number} time
* @return {String}
*/
function formatStopwatchTime(time) {
// Format falsy values as 0
if (!time) {
return "00:00.000";
}
let milliseconds = parseInt(time % 1000, 10);
let seconds = parseInt((time / 1000) % 60, 10);
let minutes = parseInt((time / (1000 * 60)), 10);
let pad = (nb, max) => {
if (nb < max) {
return new Array((max + "").length - (nb + "").length + 1).join("0") + nb;
}
return nb;
};
minutes = pad(minutes, 10);
seconds = pad(seconds, 10);
milliseconds = pad(milliseconds, 100);
return `${minutes}:${seconds}.${milliseconds}`;
}
module.exports = CurrentTimeLabel;

Просмотреть файл

@ -0,0 +1,32 @@
/* 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";
const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
class CurrentTimeScrubber extends PureComponent {
static get propTypes() {
return {
offset: PropTypes.number.isRequired,
};
}
render() {
const { offset } = this.props;
return dom.div(
{
className: "current-time-scrubber",
style: {
transform: `translateX(${ offset }px)`,
},
}
);
}
}
module.exports = CurrentTimeScrubber;

Просмотреть файл

@ -0,0 +1,141 @@
/* 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";
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const CurrentTimeScrubber = createFactory(require("./CurrentTimeScrubber"));
class CurrentTimeScrubberController extends PureComponent {
static get propTypes() {
return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
setAnimationsCurrentTime: PropTypes.func.isRequired,
timeScale: PropTypes.object.isRequired,
};
}
constructor(props) {
super(props);
const { addAnimationsCurrentTimeListener } = props;
this.onCurrentTimeUpdated = this.onCurrentTimeUpdated.bind(this);
this.onMouseDown = this.onMouseDown.bind(this);
this.onMouseMove = this.onMouseMove.bind(this);
this.onMouseOut = this.onMouseOut.bind(this);
this.onMouseUp = this.onMouseUp.bind(this);
this.state = {
// offset of the position for the scrubber
offset: 0,
};
addAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
}
componentDidMount() {
const parentEl = ReactDOM.findDOMNode(this).parentElement;
parentEl.addEventListener("mousedown", this.onMouseDown);
}
componentWillUnmount() {
const { removeAnimationsCurrentTimeListener } = this.props;
removeAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
}
onCurrentTimeUpdated(currentTime) {
const { timeScale } = this.props;
const thisEl = ReactDOM.findDOMNode(this);
const offset =
thisEl ? currentTime / timeScale.getDuration() * thisEl.clientWidth : 0;
this.setState({ offset });
}
onMouseDown(event) {
event.stopPropagation();
const thisEl = ReactDOM.findDOMNode(this);
this.controllerArea = thisEl.getBoundingClientRect();
this.listenerTarget = thisEl.closest(".animation-list-container");
this.listenerTarget.addEventListener("mousemove", this.onMouseMove);
this.listenerTarget.addEventListener("mouseout", this.onMouseOut);
this.listenerTarget.addEventListener("mouseup", this.onMouseUp);
this.listenerTarget.classList.add("active-scrubber");
this.updateAnimationsCurrentTime(event.pageX, true);
}
onMouseMove(event) {
event.stopPropagation();
this.isMouseMoved = true;
this.updateAnimationsCurrentTime(event.pageX);
}
onMouseOut(event) {
event.stopPropagation();
if (!this.listenerTarget.contains(event.relatedTarget)) {
const endX = this.controllerArea.x + this.controllerArea.width;
const pageX = endX < event.pageX ? endX : event.pageX;
this.updateAnimationsCurrentTime(pageX, true);
this.uninstallListeners();
}
}
onMouseUp(event) {
event.stopPropagation();
if (this.isMouseMoved) {
this.updateAnimationsCurrentTime(event.pageX, true);
this.isMouseMoved = null;
}
this.uninstallListeners();
}
uninstallListeners() {
this.listenerTarget.removeEventListener("mousemove", this.onMouseMove);
this.listenerTarget.removeEventListener("mouseout", this.onMouseOut);
this.listenerTarget.removeEventListener("mouseup", this.onMouseUp);
this.listenerTarget.classList.remove("active-scrubber");
this.listenerTarget = null;
this.controllerArea = null;
}
updateAnimationsCurrentTime(pageX, needRefresh) {
const {
setAnimationsCurrentTime,
timeScale,
} = this.props;
const time = pageX - this.controllerArea.x < 0 ?
0 :
(pageX - this.controllerArea.x) /
this.controllerArea.width * timeScale.getDuration();
setAnimationsCurrentTime(time, needRefresh);
}
render() {
const { offset } = this.state;
return dom.div(
{
className: "current-time-scrubber-controller devtools-toolbar",
},
CurrentTimeScrubber(
{
offset,
}
)
);
}
}
module.exports = CurrentTimeScrubberController;

Просмотреть файл

@ -0,0 +1,112 @@
/* 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";
const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
class KeyframesProgressBar extends PureComponent {
static get propTypes() {
return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
animation: PropTypes.object.isRequired,
getAnimationsCurrentTime: PropTypes.func.isRequired,
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
simulateAnimationForKeyframesProgressBar: PropTypes.func.isRequired,
timeScale: PropTypes.object.isRequired,
};
}
constructor(props) {
super(props);
this.onCurrentTimeUpdated = this.onCurrentTimeUpdated.bind(this);
this.state = {
// offset of the position for the progress bar
offset: 0,
};
}
componentDidMount() {
const { addAnimationsCurrentTimeListener } = this.props;
this.element = ReactDOM.findDOMNode(this);
this.setupAnimation(this.props);
addAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
}
componentWillReceiveProps(nextProps) {
const { getAnimationsCurrentTime } = nextProps;
this.setupAnimation(nextProps);
this.onCurrentTimeUpdated(getAnimationsCurrentTime());
}
componentWillUnmount() {
const { removeAnimationsCurrentTimeListener } = this.props;
removeAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
this.element = null;
this.simulatedAnimation = null;
}
onCurrentTimeUpdated(currentTime) {
const {
animation,
timeScale,
} = this.props;
const {
playbackRate,
previousStartTime = 0,
} = animation.state;
this.simulatedAnimation.currentTime =
(timeScale.minStartTime + currentTime - previousStartTime) * playbackRate;
const offset = this.element.offsetWidth *
this.simulatedAnimation.effect.getComputedTiming().progress;
this.setState({ offset });
}
setupAnimation(props) {
const {
animation,
simulateAnimationForKeyframesProgressBar,
} = props;
if (this.simulatedAnimation) {
this.simulatedAnimation.cancel();
}
const timing = Object.assign({}, animation.state, {
iterations: animation.state.iterationCount || Infinity
});
this.simulatedAnimation = simulateAnimationForKeyframesProgressBar(timing);
}
render() {
const { offset } = this.state;
return dom.div(
{
className: "keyframes-progress-bar-area devtools-toolbar",
},
dom.div(
{
className: "keyframes-progress-bar",
style: {
transform: `translateX(${ offset }px)`,
},
}
)
);
}
}
module.exports = KeyframesProgressBar;

Просмотреть файл

@ -41,7 +41,10 @@ class NoAnimationPanel extends PureComponent {
className: "animation-element-picker devtools-button" + className: "animation-element-picker devtools-button" +
(elementPickerEnabled ? " checked" : ""), (elementPickerEnabled ? " checked" : ""),
"data-standalone": true, "data-standalone": true,
onClick: toggleElementPicker onClick: event => {
event.stopPropagation();
toggleElementPicker();
}
} }
) )
); );

Просмотреть файл

@ -0,0 +1,93 @@
/* 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";
const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const { KeyCodes } = require("devtools/client/shared/keycodes");
const { getStr } = require("../utils/l10n");
const { hasRunningAnimation } = require("../utils/utils");
class PauseResumeButton extends PureComponent {
static get propTypes() {
return {
animations: PropTypes.arrayOf(PropTypes.object).isRequired,
setAnimationsPlayState: PropTypes.func.isRequired,
};
}
constructor(props) {
super(props);
this.onKeyDown = this.onKeyDown.bind(this);
this.state = {
isRunning: false,
};
}
componentWillMount() {
this.updateState(this.props);
}
componentDidMount() {
const targetEl = this.getKeyEventTarget();
targetEl.addEventListener("keydown", this.onKeyDown);
}
componentWillReceiveProps(nextProps) {
this.updateState(nextProps);
}
componentWillUnount() {
const targetEl = this.getKeyEventTarget();
targetEl.removeEventListener("keydown", this.onKeyDown);
}
getKeyEventTarget() {
return ReactDOM.findDOMNode(this).closest("#animation-container");
}
onToggleAnimationsPlayState(event) {
event.stopPropagation();
const { setAnimationsPlayState } = this.props;
const { isRunning } = this.state;
setAnimationsPlayState(!isRunning);
}
onKeyDown(event) {
if (event.keyCode === KeyCodes.DOM_VK_SPACE) {
this.onToggleAnimationsPlayState(event);
}
}
updateState() {
const { animations } = this.props;
const isRunning = hasRunningAnimation(animations);
this.setState({ isRunning });
}
render() {
const { isRunning } = this.state;
return dom.button(
{
className: "pause-resume-button devtools-button" +
(isRunning ? "" : " paused"),
onClick: this.onToggleAnimationsPlayState.bind(this),
title: isRunning ?
getStr("timeline.resumedButtonTooltip") :
getStr("timeline.pausedButtonTooltip"),
}
);
}
}
module.exports = PauseResumeButton;

Просмотреть файл

@ -0,0 +1,103 @@
/* 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";
const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { getFormatStr } = require("../utils/l10n");
const PLAYBACK_RATES = [.1, .25, .5, 1, 2, 5, 10];
class PlaybackRateSelector extends PureComponent {
static get propTypes() {
return {
animations: PropTypes.arrayOf(PropTypes.object).isRequired,
setAnimationsPlaybackRate: PropTypes.func.isRequired,
};
}
constructor(props) {
super(props);
this.state = {
options: [],
selected: 1,
};
}
componentWillMount() {
this.updateState(this.props);
}
componentWillReceiveProps(nextProps) {
this.updateState(nextProps);
}
getPlaybackRates(animations) {
return sortAndUnique(animations.map(a => a.state.playbackRate));
}
getSelectablePlaybackRates(animationsRates) {
return sortAndUnique(PLAYBACK_RATES.concat(animationsRates));
}
onChange(e) {
const { setAnimationsPlaybackRate } = this.props;
if (!e.target.value) {
return;
}
setAnimationsPlaybackRate(e.target.value);
}
updateState(props) {
const { animations } = props;
let options;
let selected;
const rates = this.getPlaybackRates(animations);
if (rates.length === 1) {
options = this.getSelectablePlaybackRates(rates);
selected = rates[0];
} else {
// When the animations displayed have mixed playback rates, we can't
// select any of the predefined ones.
options = ["", ...PLAYBACK_RATES];
selected = "";
}
this.setState({ options, selected });
}
render() {
const { options, selected } = this.state;
return dom.select(
{
className: "playback-rate-selector devtools-button",
onChange: this.onChange.bind(this),
},
options.map(rate => {
return dom.option(
{
selected: rate === selected ? "true" : null,
value: rate,
},
rate ? getFormatStr("player.playbackRateLabel", rate) : "-"
);
})
);
}
}
function sortAndUnique(array) {
return [...new Set(array)].sort((a, b) => a > b);
}
module.exports = PlaybackRateSelector;

Просмотреть файл

@ -0,0 +1,36 @@
/* 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";
const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { getStr } = require("../utils/l10n");
class RewindButton extends PureComponent {
static get propTypes() {
return {
rewindAnimationsCurrentTime: PropTypes.func.isRequired,
};
}
render() {
const { rewindAnimationsCurrentTime } = this.props;
return dom.button(
{
className: "rewind-button devtools-button",
onClick: event => {
event.stopPropagation();
rewindAnimationsCurrentTime();
},
title: getStr("timeline.rewindButtonTooltip"),
}
);
}
}
module.exports = RewindButton;

Просмотреть файл

@ -16,6 +16,7 @@ class ComputedTimingPath extends TimingPath {
animation: PropTypes.object.isRequired, animation: PropTypes.object.isRequired,
durationPerPixel: PropTypes.number.isRequired, durationPerPixel: PropTypes.number.isRequired,
keyframes: PropTypes.object.isRequired, keyframes: PropTypes.object.isRequired,
offset: PropTypes.number.isRequired,
opacity: PropTypes.number.isRequired, opacity: PropTypes.number.isRequired,
simulateAnimation: PropTypes.func.isRequired, simulateAnimation: PropTypes.func.isRequired,
totalDuration: PropTypes.number.isRequired, totalDuration: PropTypes.number.isRequired,
@ -27,6 +28,7 @@ class ComputedTimingPath extends TimingPath {
animation, animation,
durationPerPixel, durationPerPixel,
keyframes, keyframes,
offset,
opacity, opacity,
simulateAnimation, simulateAnimation,
totalDuration, totalDuration,
@ -78,7 +80,6 @@ class ComputedTimingPath extends TimingPath {
const helper = new SummaryGraphHelper(state, keyframes, const helper = new SummaryGraphHelper(state, keyframes,
totalDuration, durationPerPixel, totalDuration, durationPerPixel,
getValueFunc, toPathStringFunc); getValueFunc, toPathStringFunc);
const offset = state.previousStartTime ? state.previousStartTime : 0;
return dom.g( return dom.g(
{ {

Просмотреть файл

@ -21,19 +21,23 @@ class DelaySign extends PureComponent {
animation, animation,
timeScale, timeScale,
} = this.props; } = this.props;
const {
fill,
playbackRate,
previousStartTime = 0,
} = animation.state;
const { state } = animation; const delay = animation.state.delay / playbackRate;
const startTime = (state.previousStartTime || 0) - timeScale.minStartTime const startTime =
+ (state.delay < 0 ? state.delay : 0); previousStartTime - timeScale.minStartTime + (delay < 0 ? delay : 0);
const offset = startTime / timeScale.getDuration() * 100; const offset = startTime / timeScale.getDuration() * 100;
const width = Math.abs(state.delay) / timeScale.getDuration() * 100; const width = Math.abs(delay) / timeScale.getDuration() * 100;
const delayClass = state.delay < 0 ? "negative" : "";
const fillClass = state.fill === "both" || state.fill === "backwards" ? "fill" : "";
return dom.div( return dom.div(
{ {
className: `animation-delay-sign ${ delayClass } ${ fillClass }`, className: "animation-delay-sign" +
(delay < 0 ? " negative" : "") +
(fill === "both" || fill === "backwards" ? " fill" : ""),
style: { style: {
width: `${ width }%`, width: `${ width }%`,
left: `${ offset }%`, left: `${ offset }%`,

Просмотреть файл

@ -15,6 +15,7 @@ class EffectTimingPath extends TimingPath {
return { return {
animation: PropTypes.object.isRequired, animation: PropTypes.object.isRequired,
durationPerPixel: PropTypes.number.isRequired, durationPerPixel: PropTypes.number.isRequired,
offset: PropTypes.number.isRequired,
simulateAnimation: PropTypes.func.isRequired, simulateAnimation: PropTypes.func.isRequired,
totalDuration: PropTypes.number.isRequired, totalDuration: PropTypes.number.isRequired,
}; };
@ -24,6 +25,7 @@ class EffectTimingPath extends TimingPath {
const { const {
animation, animation,
durationPerPixel, durationPerPixel,
offset,
simulateAnimation, simulateAnimation,
totalDuration, totalDuration,
} = this.props; } = this.props;
@ -57,7 +59,6 @@ class EffectTimingPath extends TimingPath {
const helper = new SummaryGraphHelper(state, null, const helper = new SummaryGraphHelper(state, null,
totalDuration, durationPerPixel, totalDuration, durationPerPixel,
getValueFunc, toPathStringFunc); getValueFunc, toPathStringFunc);
const offset = state.previousStartTime ? state.previousStartTime : 0;
return dom.g( return dom.g(
{ {

Просмотреть файл

@ -21,20 +21,27 @@ class EndDelaySign extends PureComponent {
animation, animation,
timeScale, timeScale,
} = this.props; } = this.props;
const {
delay,
duration,
fill,
iterationCount,
playbackRate,
previousStartTime = 0,
} = animation.state;
const { state } = animation; const endDelay = animation.state.endDelay / playbackRate;
const startTime = (state.previousStartTime || 0) - timeScale.minStartTime; const startTime = previousStartTime - timeScale.minStartTime;
const endTime = state.duration * state.iterationCount + state.delay; const endTime =
const endDelay = state.endDelay < 0 ? state.endDelay : 0; (duration * iterationCount + delay) / playbackRate + (endDelay < 0 ? endDelay : 0);
const offset = (startTime + endTime + endDelay) / timeScale.getDuration() * 100; const offset = (startTime + endTime) / timeScale.getDuration() * 100;
const width = Math.abs(state.endDelay) / timeScale.getDuration() * 100; const width = Math.abs(endDelay) / timeScale.getDuration() * 100;
const endDelayClass = state.endDelay < 0 ? "negative" : "";
const fillClass = state.fill === "both" || state.fill === "forwards" ? "fill" : "";
return dom.div( return dom.div(
{ {
className: `animation-end-delay-sign ${ endDelayClass } ${ fillClass }`, className: "animation-end-delay-sign" +
(endDelay < 0 ? " negative" : "") +
(fill === "both" || fill === "forwards" ? " fill" : ""),
style: { style: {
width: `${ width }%`, width: `${ width }%`,
left: `${ offset }%`, left: `${ offset }%`,

Просмотреть файл

@ -4,25 +4,13 @@
"use strict"; "use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories"); const dom = require("devtools/client/shared/vendor/react-dom-factories");
const NegativePath = require("./NegativePath"); const NegativePath = require("./NegativePath");
class NegativeDelayPath extends NegativePath { class NegativeDelayPath extends NegativePath {
static get propTypes() { getClassName() {
return { return "animation-negative-delay-path";
animation: PropTypes.object.isRequired,
durationPerPixel: PropTypes.number.isRequired,
keyframes: PropTypes.object.isRequired,
simulateAnimation: PropTypes.func.isRequired,
totalDuration: PropTypes.number.isRequired,
};
}
constructor(props) {
props.className = "animation-negative-delay-path";
super(props);
} }
renderGraph(state, helper) { renderGraph(state, helper) {

Просмотреть файл

@ -4,25 +4,13 @@
"use strict"; "use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories"); const dom = require("devtools/client/shared/vendor/react-dom-factories");
const NegativePath = require("./NegativePath"); const NegativePath = require("./NegativePath");
class NegativeEndDelayPath extends NegativePath { class NegativeEndDelayPath extends NegativePath {
static get propTypes() { getClassName() {
return { return "animation-negative-end-delay-path";
animation: PropTypes.object.isRequired,
durationPerPixel: PropTypes.number.isRequired,
keyframes: PropTypes.object.isRequired,
simulateAnimation: PropTypes.func.isRequired,
totalDuration: PropTypes.number.isRequired,
};
}
constructor(props) {
props.className = "animation-negative-end-delay-path";
super(props);
} }
renderGraph(state, helper) { renderGraph(state, helper) {

Просмотреть файл

@ -17,6 +17,7 @@ class NegativePath extends PureComponent {
className: PropTypes.string.isRequired, className: PropTypes.string.isRequired,
durationPerPixel: PropTypes.number.isRequired, durationPerPixel: PropTypes.number.isRequired,
keyframes: PropTypes.object.isRequired, keyframes: PropTypes.object.isRequired,
offset: PropTypes.number.isRequired,
simulateAnimation: PropTypes.func.isRequired, simulateAnimation: PropTypes.func.isRequired,
totalDuration: PropTypes.number.isRequired, totalDuration: PropTypes.number.isRequired,
}; };
@ -25,9 +26,9 @@ class NegativePath extends PureComponent {
render() { render() {
const { const {
animation, animation,
className,
durationPerPixel, durationPerPixel,
keyframes, keyframes,
offset,
simulateAnimation, simulateAnimation,
totalDuration, totalDuration,
} = this.props; } = this.props;
@ -75,11 +76,10 @@ class NegativePath extends PureComponent {
const helper = new SummaryGraphHelper(state, keyframes, const helper = new SummaryGraphHelper(state, keyframes,
totalDuration, durationPerPixel, totalDuration, durationPerPixel,
getValueFunc, toPathStringFunc); getValueFunc, toPathStringFunc);
const offset = state.previousStartTime ? state.previousStartTime : 0;
return dom.g( return dom.g(
{ {
className, className: this.getClassName(),
transform: `translate(${ offset })` transform: `translate(${ offset })`
}, },
this.renderGraph(state, helper) this.renderGraph(state, helper)

Просмотреть файл

@ -33,7 +33,8 @@ class SummaryGraph extends PureComponent {
this.onClick = this.onClick.bind(this); this.onClick = this.onClick.bind(this);
} }
onClick() { onClick(event) {
event.stopPropagation();
this.props.selectAnimation(this.props.animation); this.props.selectAnimation(this.props.animation);
} }

Просмотреть файл

@ -174,7 +174,9 @@ class SummaryGraphPath extends PureComponent {
} = this.props; } = this.props;
const totalDuration = this.getTotalDuration(animation, timeScale); const totalDuration = this.getTotalDuration(animation, timeScale);
const startTime = timeScale.minStartTime; const { playbackRate, previousStartTime = 0 } = animation.state;
const startTime = timeScale.minStartTime * playbackRate;
const offset = previousStartTime * playbackRate;
const opacity = Math.max(1 / keyframesList.length, MIN_KEYFRAMES_EASING_OPACITY); const opacity = Math.max(1 / keyframesList.length, MIN_KEYFRAMES_EASING_OPACITY);
return dom.svg( return dom.svg(
@ -190,6 +192,7 @@ class SummaryGraphPath extends PureComponent {
animation, animation,
durationPerPixel, durationPerPixel,
keyframes, keyframes,
offset,
opacity, opacity,
simulateAnimation, simulateAnimation,
totalDuration, totalDuration,
@ -201,6 +204,7 @@ class SummaryGraphPath extends PureComponent {
{ {
animation, animation,
durationPerPixel, durationPerPixel,
offset,
simulateAnimation, simulateAnimation,
totalDuration, totalDuration,
} }
@ -214,6 +218,7 @@ class SummaryGraphPath extends PureComponent {
animation, animation,
durationPerPixel, durationPerPixel,
keyframes, keyframes,
offset,
simulateAnimation, simulateAnimation,
totalDuration, totalDuration,
} }
@ -228,6 +233,7 @@ class SummaryGraphPath extends PureComponent {
animation, animation,
durationPerPixel, durationPerPixel,
keyframes, keyframes,
offset,
simulateAnimation, simulateAnimation,
totalDuration, totalDuration,
} }

Просмотреть файл

@ -22,8 +22,16 @@ DevToolsModules(
'AnimationTarget.js', 'AnimationTarget.js',
'AnimationTimelineTickItem.js', 'AnimationTimelineTickItem.js',
'AnimationTimelineTickList.js', 'AnimationTimelineTickList.js',
'AnimationToolbar.js',
'App.js', 'App.js',
'CurrentTimeLabel.js',
'CurrentTimeScrubber.js',
'CurrentTimeScrubberController.js',
'KeyframesProgressBar.js',
'KeyframesProgressTickItem.js', 'KeyframesProgressTickItem.js',
'KeyframesProgressTickList.js', 'KeyframesProgressTickList.js',
'NoAnimationPanel.js', 'NoAnimationPanel.js',
'PauseResumeButton.js',
'PlaybackRateSelector.js',
'RewindButton.js',
) )

Просмотреть файл

@ -0,0 +1,75 @@
/* 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";
/**
* In animation inspector, the scrubber and the progress bar moves along the current time
* of animation. However, the processing which sync with actual animations is heavy since
* we have to communication by the actor. The role of this class is to make the pseudo
* current time in animation inspector to proceed.
*/
class CurrentTimeTimer {
/**
* Constructor.
*
* @param {Object} timeScale
* @param {Bool} shouldStopAfterEndTime
* If need to stop the timer after animation end time, set true.
* @param {window} win
* Be used for requestAnimationFrame and performance.
* @param {Function} onUpdated
* Listener function to get updating.
* This function is called with 2 parameters.
* 1st: current time
* 2nd: if shouldStopAfterEndTime is true and
* the current time is over the end time, true is given.
*/
constructor(timeScale, shouldStopAfterEndTime, win, onUpdated) {
this.baseCurrentTime = timeScale.documentCurrentTime - timeScale.minStartTime;
this.endTime = timeScale.maxEndTime - timeScale.minStartTime;
this.timerStartTime = win.performance.now();
this.shouldStopAfterEndTime = shouldStopAfterEndTime;
this.onUpdated = onUpdated;
this.win = win;
this.next = this.next.bind(this);
}
destroy() {
this.stop();
this.onUpdated = null;
this.win = null;
}
/**
* Proceed the pseudo current time.
*/
next() {
if (this.doStop) {
return;
}
const currentTime =
this.baseCurrentTime + this.win.performance.now() - this.timerStartTime;
if (this.endTime < currentTime && this.shouldStopAfterEndTime) {
this.onUpdated(this.endTime, true);
return;
}
this.onUpdated(currentTime);
this.win.requestAnimationFrame(this.next);
}
start() {
this.next();
}
stop() {
this.doStop = true;
}
}
module.exports = CurrentTimeTimer;

Просмотреть файл

@ -12,5 +12,6 @@ DIRS += [
BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
DevToolsModules( DevToolsModules(
'animation.js' 'animation.js',
'current-time-timer.js'
) )

Просмотреть файл

@ -12,6 +12,8 @@ const {
UPDATE_SIDEBAR_SIZE, UPDATE_SIDEBAR_SIZE,
} = require("../actions/index"); } = require("../actions/index");
const TimeScale = require("../utils/timescale");
const INITIAL_STATE = { const INITIAL_STATE = {
animations: [], animations: [],
detailVisibility: false, detailVisibility: false,
@ -21,12 +23,25 @@ const INITIAL_STATE = {
height: 0, height: 0,
width: 0, width: 0,
}, },
timeScale: null,
}; };
const reducers = { const reducers = {
[UPDATE_ANIMATIONS](state, { animations }) { [UPDATE_ANIMATIONS](state, { animations }) {
let detailVisibility = state.detailVisibility;
let selectedAnimation = state.selectedAnimation;
if (!state.selectedAnimation ||
!animations.find(animation => animation.actorID === selectedAnimation.actorID)) {
selectedAnimation = animations.length === 1 ? animations[0] : null;
detailVisibility = !!selectedAnimation;
}
return Object.assign({}, state, { return Object.assign({}, state, {
animations, animations,
detailVisibility,
selectedAnimation,
timeScale: new TimeScale(animations),
}); });
}, },

Просмотреть файл

@ -2,6 +2,7 @@
tags = devtools tags = devtools
subsuite = devtools subsuite = devtools
support-files = support-files =
doc_custom_playback_rate.html
doc_multi_easings.html doc_multi_easings.html
doc_multi_keyframes.html doc_multi_keyframes.html
doc_multi_timings.html doc_multi_timings.html
@ -22,11 +23,19 @@ support-files =
[browser_animation_animation-list.js] [browser_animation_animation-list.js]
[browser_animation_animation-target.js] [browser_animation_animation-target.js]
[browser_animation_animation-timeline-tick.js] [browser_animation_animation-timeline-tick.js]
[browser_animation_current-time-label.js]
[browser_animation_current-time-scrubber.js]
[browser_animation_empty_on_invalid_nodes.js] [browser_animation_empty_on_invalid_nodes.js]
[browser_animation_inspector_exists.js] [browser_animation_inspector_exists.js]
[browser_animation_keyframes-graph_computed-value-path.js] [browser_animation_keyframes-graph_computed-value-path.js]
[browser_animation_keyframes-graph_computed-value-path_easing-hint.js] [browser_animation_keyframes-graph_computed-value-path_easing-hint.js]
[browser_animation_keyframes-graph_keyframe-marker.js] [browser_animation_keyframes-graph_keyframe-marker.js]
[browser_animation_keyframes-progress-bar.js]
[browser_animation_logic_auto-stop.js]
[browser_animation_pause-resume-button.js]
[browser_animation_pause-resume-button_spacebar.js]
[browser_animation_playback-rate-selector.js]
[browser_animation_rewind-button.js]
[browser_animation_summary-graph_animation-name.js] [browser_animation_summary-graph_animation-name.js]
[browser_animation_summary-graph_compositor.js] [browser_animation_summary-graph_compositor.js]
[browser_animation_summary-graph_computed-timing-path.js] [browser_animation_summary-graph_computed-timing-path.js]

Просмотреть файл

@ -14,7 +14,7 @@ add_task(async function() {
ok(panel.querySelector(".animation-list"), ok(panel.querySelector(".animation-list"),
"The animation-list is in the DOM"); "The animation-list is in the DOM");
is(panel.querySelectorAll(".animation-list .animation-item").length, is(panel.querySelectorAll(".animation-list .animation-item").length,
animationInspector.animations.length, animationInspector.state.animations.length,
"The number of animations displayed matches the number of animations"); "The number of animations displayed matches the number of animations");
info("Checking the background color for the animation list items"); info("Checking the background color for the animation list items");

Просмотреть файл

@ -14,7 +14,7 @@ add_task(async function() {
info("Checking the animation target elements existance"); info("Checking the animation target elements existance");
const animationItemEls = panel.querySelectorAll(".animation-list .animation-item"); const animationItemEls = panel.querySelectorAll(".animation-list .animation-item");
is(animationItemEls.length, animationInspector.animations.length, is(animationItemEls.length, animationInspector.state.animations.length,
"Number of animation target element should be same to number of animations " "Number of animation target element should be same to number of animations "
+ "that displays"); + "that displays");

Просмотреть файл

@ -19,7 +19,7 @@ const TIME_GRADUATION_MIN_SPACING = 40;
add_task(async function() { add_task(async function() {
await addTab(URL_ROOT + "doc_simple_animation.html"); await addTab(URL_ROOT + "doc_simple_animation.html");
const { animationInspector, inspector, panel } = await openAnimationInspector(); const { animationInspector, inspector, panel } = await openAnimationInspector();
const timeScale = new TimeScale(animationInspector.animations); const timeScale = new TimeScale(animationInspector.state.animations);
info("Checking animation list header element existence"); info("Checking animation list header element existence");
const listContainerEl = panel.querySelector(".animation-list-container"); const listContainerEl = panel.querySelector(".animation-list-container");

Просмотреть файл

@ -0,0 +1,61 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following CurrentTimeLabel component:
// * element existence
// * label content at plural timing
add_task(async function() {
await addTab(URL_ROOT + "doc_multi_timings.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking current time label existence");
const labelEl = panel.querySelector(".current-time-label");
ok(labelEl, "current time label should exist");
info("Checking current time label content");
await selectNodeAndWaitForAnimations(".keyframes-easing-step", inspector);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
assertLabelContent(labelEl, animationInspector.state.animations[0].state.currentTime);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.2);
assertLabelContent(labelEl, animationInspector.state.animations[0].state.currentTime);
info("Checking current time label content during running");
// Resume
await clickOnPauseResumeButton(animationInspector, panel);
const previousContent = labelEl.textContent;
await wait(1000);
const currentContent = labelEl.textContent;
isnot(previousContent, currentContent, "Current time label should change");
});
function assertLabelContent(labelEl, time) {
const expected = formatStopwatchTime(time);
is(labelEl.textContent, expected, `Content of label should be ${ expected }`);
}
function formatStopwatchTime(time) {
// Format falsy values as 0
if (!time) {
return "00:00.000";
}
let milliseconds = parseInt(time % 1000, 10);
let seconds = parseInt((time / 1000) % 60, 10);
let minutes = parseInt((time / (1000 * 60)), 10);
let pad = (nb, max) => {
if (nb < max) {
return new Array((max + "").length - (nb + "").length + 1).join("0") + nb;
}
return nb;
};
minutes = pad(minutes, 10);
seconds = pad(seconds, 10);
milliseconds = pad(milliseconds, 100);
return `${minutes}:${seconds}.${milliseconds}`;
}

Просмотреть файл

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following CurrentTimeScrubber and CurrentTimeScrubberController components:
// * element existence
// * scrubber position validity
// * make animations currentTime to change by click on the controller
// * mouse drag on the scrubber
add_task(async function() {
await addTab(URL_ROOT + "doc_multi_timings.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking scrubber controller existence");
const controllerEl = panel.querySelector(".current-time-scrubber-controller");
ok(controllerEl, "scrubber controller should exist");
info("Checking scrubber existence");
const scrubberEl = controllerEl.querySelector(".current-time-scrubber");
ok(scrubberEl, "scrubber should exist");
info("Checking scrubber changes current time of animation and the position");
await selectNodeAndWaitForAnimations(".enddelay-with-iterations-infinity", inspector);
const duration = animationInspector.state.timeScale.getDuration();
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0);
assertAnimationsCurrentTime(animationInspector, 0);
assertPosition(scrubberEl, controllerEl, 0, animationInspector);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 1);
assertAnimationsCurrentTime(animationInspector, duration);
assertPosition(scrubberEl, controllerEl, duration, animationInspector);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
assertAnimationsCurrentTime(animationInspector, duration * 0.5);
assertPosition(scrubberEl, controllerEl, duration * 0.5, animationInspector);
info("Checking current time scrubber position during running");
// Running again
await clickOnPauseResumeButton(animationInspector, panel);
let previousX = scrubberEl.getBoundingClientRect().x;
await wait(100);
let currentX = scrubberEl.getBoundingClientRect().x;
isnot(previousX, currentX, "Scrubber should be moved");
info("Checking draggable on scrubber over animation list");
await clickOnPauseResumeButton(animationInspector, panel);
previousX = scrubberEl.getBoundingClientRect().x;
await dragOnCurrentTimeScrubber(animationInspector, panel, 0.5, 2, 30);
currentX = scrubberEl.getBoundingClientRect().x;
isnot(previousX, currentX, "Scrubber should be draggable");
info("Checking a behavior which mouse out from animation inspector area " +
"during dragging from controller");
await dragOnCurrentTimeScrubberController(animationInspector, panel, 0.5, 2);
ok(!panel.querySelector(".animation-list-container")
.classList.contains("active-scrubber"), "Click and DnD should be inactive");
});
function assertPosition(scrubberEl, controllerEl, time, animationInspector) {
const controllerBounds = controllerEl.getBoundingClientRect();
const scrubberBounds = scrubberEl.getBoundingClientRect();
const scrubberX = scrubberBounds.x + scrubberBounds.width / 2 - controllerBounds.x;
const timeScale = animationInspector.state.timeScale;
const expected = Math.round(time / timeScale.getDuration() * controllerBounds.width);
is(scrubberX, expected, `Position should be ${ expected } at ${ time }ms`);
}

Просмотреть файл

@ -0,0 +1,91 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following KeyframesProgressBar:
// * element existence
// * progress bar position in multi effect timings
// * progress bar position after changing playback rate
// * progress bar position when select another animation
const POSITION_TESTCASES = [
{
targetClassName: "cssanimation-linear",
scrubberPositions: [0, 0.25, 0.5, 0.75, 1],
expectedPositions: [0, 0.25, 0.5, 0.75, 0],
},
{
targetClassName: "easing-step",
scrubberPositions: [0, 0.49, 0.5, 0.99],
expectedPositions: [0, 0, 0.5, 0.5],
},
{
targetClassName: "delay-positive",
scrubberPositions: [0, 0.33, 0.5],
expectedPositions: [0, 0, 0.25],
},
{
targetClassName: "delay-negative",
scrubberPositions: [0, 0.49, 0.5, 0.75],
expectedPositions: [0, 0, 0.5, 0.75],
},
{
targetClassName: "enddelay-positive",
scrubberPositions: [0, 0.66, 0.67, 0.99],
expectedPositions: [0, 0.99, 0, 0],
},
{
targetClassName: "enddelay-negative",
scrubberPositions: [0, 0.49, 0.5, 0.99],
expectedPositions: [0, 0.49, 0, 0],
},
{
targetClassName: "direction-reverse-with-iterations-infinity",
scrubberPositions: [0, 0.25, 0.5, 0.75, 1],
expectedPositions: [1, 0.75, 0.5, 0.25, 1],
},
{
targetClassName: "fill-both-width-delay-iterationstart",
scrubberPositions: [0, 0.33, 0.66, 0.833, 1],
expectedPositions: [0.5, 0.5, 0.99, 0.25, 0.5],
},
];
add_task(async function() {
await addTab(URL_ROOT + "doc_multi_timings.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking progress bar position in multi effect timings");
await clickOnPauseResumeButton(animationInspector, panel);
for (const testcase of POSITION_TESTCASES) {
info(`Checking progress bar position for ${ testcase.targetClassName }`);
await selectNodeAndWaitForAnimations(`.${ testcase.targetClassName }`, inspector);
info("Checking progress bar existence");
const areaEl = panel.querySelector(".keyframes-progress-bar-area");
ok(areaEl, "progress bar area should exist");
const barEl = areaEl.querySelector(".keyframes-progress-bar");
ok(barEl, "progress bar should exist");
const scrubberPositions = testcase.scrubberPositions;
const expectedPositions = testcase.expectedPositions;
for (let i = 0; i < scrubberPositions.length; i++) {
info(`Scrubber position is ${ scrubberPositions[i] }`);
await clickOnCurrentTimeScrubberController(animationInspector,
panel, scrubberPositions[i]);
assertPosition(barEl, areaEl, expectedPositions[i], animationInspector);
}
}
});
function assertPosition(barEl, areaEl, expectedRate, animationInspector) {
const controllerBounds = areaEl.getBoundingClientRect();
const barBounds = barEl.getBoundingClientRect();
const barX = barBounds.x + barBounds.width / 2 - controllerBounds.x;
const expected = controllerBounds.width * expectedRate;
ok(expected - 1 < barX && barX < expected + 1,
`Position should apploximately be ${ expected } (x of bar is ${ barX })`);
}

Просмотреть файл

@ -0,0 +1,63 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Animation inspector makes the current time to stop
// after end of animation duration except iterations infinity.
// Test followings:
// * state of animations and UI components after end of animation duration
// * state of animations and UI components after end of animation duration
// but iteration count is infinity
add_task(async function() {
await addTab(URL_ROOT + "doc_multi_timings.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking state after end of animation duration");
await selectNodeAndWaitForAnimations(".easing-step", inspector);
const pixelsData = getDurationAndRate(animationInspector, panel, 5);
await clickOnCurrentTimeScrubberController(animationInspector,
panel, 1 - pixelsData.rate);
await clickOnPauseResumeButton(animationInspector, panel);
// Must be able to catch rendering event after stopping the animation.
await waitForSummaryAndDetail(animationInspector);
await assertStates(animationInspector, panel, false);
info("Checking state after end of animation duration and infinity iterations");
await clickOnPauseResumeButton(animationInspector, panel);
await selectNodeAndWaitForAnimations(".enddelay-with-iterations-infinity", inspector);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 1);
await clickOnPauseResumeButton(animationInspector, panel);
await assertStates(animationInspector, panel, true);
});
async function assertStates(animationInspector, panel, shouldRunning) {
const buttonEl = panel.querySelector(".pause-resume-button");
const labelEl = panel.querySelector(".current-time-label");
const scrubberEl = panel.querySelector(".current-time-scrubber");
const previousLabelContent = labelEl.textContent;
const previousScrubberX = scrubberEl.getBoundingClientRect().x;
await wait(100);
const currentLabelContent = labelEl.textContent;
const currentScrubberX = scrubberEl.getBoundingClientRect().x;
if (shouldRunning) {
isnot(previousLabelContent, currentLabelContent,
"Current time label content should change");
isnot(previousScrubberX, currentScrubberX,
"Current time scrubber position should change");
ok(!buttonEl.classList.contains("paused"),
"State of button should be running");
assertAnimationsRunning(animationInspector, panel);
} else {
is(previousLabelContent, currentLabelContent,
"Current time label Content should not change");
is(previousScrubberX, currentScrubberX,
"Current time scrubber position should not change");
ok(buttonEl.classList.contains("paused"),
"State of button should be paused");
assertAnimationsPausing(animationInspector, panel);
}
}

Просмотреть файл

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following PauseResumeButton component:
// * element existence
// * state during running animations
// * state during pausing animations
// * make animations to pause by push button
// * make animations to resume by push button
add_task(async function() {
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
const { animationInspector, panel } = await openAnimationInspector();
info("Checking pause/resume button existence");
const buttonEl = panel.querySelector(".pause-resume-button");
ok(buttonEl, "pause/resume button should exist");
info("Checking state during running animations");
ok(!buttonEl.classList.contains("paused"), "State of button should be running");
info("Checking button makes animations to pause");
await clickOnPauseResumeButton(animationInspector, panel);
assertAnimationsPausing(animationInspector, panel);
ok(buttonEl.classList.contains("paused"), "State of button should be paused");
info("Checking button makes animations to resume");
await clickOnPauseResumeButton(animationInspector, panel);
assertAnimationsRunning(animationInspector, panel);
ok(!buttonEl.classList.contains("paused"), "State of button should be resumed");
});

Просмотреть файл

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following PauseResumeButton component with spacebar:
// * make animations to pause/resume by spacebar
// * combination with other UI components
add_task(async function() {
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
const { animationInspector, panel } = await openAnimationInspector();
info("Checking spacebar makes animations to pause");
await sendSpaceKeyEvent(animationInspector, panel);
assertAnimationsPausing(animationInspector, panel);
await sendSpaceKeyEvent(animationInspector, panel);
assertAnimationsRunning(animationInspector, panel);
info("Checking spacebar works with other UI components");
// To pause
await clickOnPauseResumeButton(animationInspector, panel);
// To resume
await sendSpaceKeyEvent(animationInspector, panel);
assertAnimationsRunning(animationInspector, panel);
// To pause
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
// To resume
await clickOnPauseResumeButton(animationInspector, panel);
// To pause
await sendSpaceKeyEvent(animationInspector, panel);
assertAnimationsPausing(animationInspector, panel);
});

Просмотреть файл

@ -0,0 +1,54 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following PlaybackRateSelector component:
// * element existence
// * make playback rate of animations by the selector
// * in case of animations have mixed playback rate
// * in case of animations have playback rate which is not default selectable value
add_task(async function() {
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking playback rate selector existence");
const selectEl = panel.querySelector(".playback-rate-selector");
ok(selectEl, "scrubber controller should exist");
info("Checking playback rate existence which includes custom rate of animations");
const selectableRates = [0.1, 0.25, 0.5, 1, 1.5, 2, 5, 10];
is(selectEl.options.length, selectableRates.length,
`Length of options should be ${ selectableRates.length }`);
for (let i = 0; i < selectEl.options.length; i++) {
const optionEl = selectEl.options[i];
const selectableRate = selectableRates[i];
is(Number(optionEl.value), selectableRate,
`Option of index[${ i }] should be ${ selectableRate }`);
}
info("Checking selected playback rate");
is(Number(selectEl.value), 1.5, "Selected option should be 1.5");
info("Checking playback rate of animations");
await clickOnPlaybackRateSelector(animationInspector, panel, 0.5);
assertPlaybackRate(animationInspector, 0.5);
info("Checking mixed playback rate");
await selectNodeAndWaitForAnimations("div", inspector);
await clickOnPlaybackRateSelector(animationInspector, panel, 2);
assertPlaybackRate(animationInspector, 2);
await selectNodeAndWaitForAnimations("body", inspector);
is(selectEl.value, "", "Selected option should be empty");
info("Checking playback rate after re-setting");
await clickOnPlaybackRateSelector(animationInspector, panel, 1);
assertPlaybackRate(animationInspector, 1);
});
async function assertPlaybackRate(animationInspector, rate) {
const isRateEqual =
animationInspector.state.animations.every(({state}) => state.playbackRate === rate);
ok(isRateEqual, `Playback rate of animations should be ${ rate }`);
}

Просмотреть файл

@ -0,0 +1,28 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following RewindButton component:
// * element existence
// * make animations to rewind to zero
// * the state should be always paused after rewinding
add_task(async function() {
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
const { animationInspector, panel } = await openAnimationInspector();
info("Checking button existence");
ok(panel.querySelector(".rewind-button"), "Rewind button should exist");
info("Checking rewind button makes animations to rewind to zero");
await clickOnRewindButton(animationInspector, panel);
assertAnimationsCurrentTime(animationInspector, 0);
assertAnimationsPausing(animationInspector, panel);
info("Checking rewind button makes animations after clicking scrubber");
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
await clickOnRewindButton(animationInspector, panel);
assertAnimationsCurrentTime(animationInspector, 0);
assertAnimationsPausing(animationInspector, panel);
});

Просмотреть файл

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
div {
background-color: lime;
height: 100px;
}
</style>
</head>
<body>
<script>
"use strict";
const duration = 100000;
function createAnimation() {
const div = document.createElement("div");
document.body.appendChild(div);
const animation = div.animate([{ opacity: 0 }], duration);
animation.playbackRate = 1.5;
}
createAnimation();
createAnimation();
</script>
</body>
</html>

Просмотреть файл

@ -121,6 +121,178 @@ const clickOnDetailCloseButton = function(panel) {
EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal); EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
}; };
/**
* Click on pause/resume button.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* The panel instance.
*/
const clickOnPauseResumeButton = async function(animationInspector, panel) {
info("Click on pause/resume button");
const buttonEl = panel.querySelector(".pause-resume-button");
const bounds = buttonEl.getBoundingClientRect();
const x = bounds.width / 2;
const y = bounds.height / 2;
EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Click on rewind button.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* The panel instance.
*/
const clickOnRewindButton = async function(animationInspector, panel) {
info("Click on rewind button");
const buttonEl = panel.querySelector(".rewind-button");
const bounds = buttonEl.getBoundingClientRect();
const x = bounds.width / 2;
const y = bounds.height / 2;
EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Click on the scrubber controller pane to update the animation current time.
*
* @param {AnimationsPanel} panel
* @param {Number} mouseDownPosition
* rate on scrubber controller pane.
* This method calculates
* `mouseDownPosition * offsetWidth + offsetLeft of scrubber controller pane`
* as the clientX of MouseEvent.
*/
const clickOnCurrentTimeScrubberController = async function(animationInspector,
panel,
mouseDownPosition,
mouseMovePosition) {
const controllerEl = panel.querySelector(".current-time-scrubber-controller");
const bounds = controllerEl.getBoundingClientRect();
const mousedonwX = bounds.width * mouseDownPosition;
info(`Click ${ mousedonwX } on scrubber controller`);
EventUtils.synthesizeMouse(controllerEl, mousedonwX, 0, {}, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Click on playback rate selector to select given rate.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* @param {Number} rate
*/
const clickOnPlaybackRateSelector = async function(animationInspector, panel, rate) {
info(`Click on playback rate selector to select ${rate}`);
const selectEl = panel.querySelector(".playback-rate-selector");
const optionEl = [...selectEl.options].filter(o => Number(o.value) === rate)[0];
if (!optionEl) {
ok(false, `Could not find an option for rate ${ rate } in the rate selector. ` +
`Values are: ${ [...selectEl.options].map(o => o.value) }`);
return;
}
const win = selectEl.ownerGlobal;
EventUtils.synthesizeMouseAtCenter(selectEl, { type: "mousedown" }, win);
EventUtils.synthesizeMouseAtCenter(optionEl, { type: "mouseup" }, win);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Drag on the scrubber to update the animation current time.
*
* @param {AnimationsPanel} panel
* @param {Number} mouseDownPosition
* rate on scrubber controller pane.
* This method calculates
* `mouseDownPosition * offsetWidth + offsetLeft of scrubber controller pane`
* as the clientX of MouseEvent.
* @param {Number} mouseMovePosition
* Dispatch mousemove event with mouseMovePosition after mousedown.
* Calculation for clinetX is same to above.
* @param {Number} mouseYPixel
* Y of mouse in pixel.
*/
const dragOnCurrentTimeScrubber = async function(animationInspector,
panel,
mouseDownPosition,
mouseMovePosition,
mouseYPixel) {
const controllerEl = panel.querySelector(".current-time-scrubber");
const bounds = controllerEl.getBoundingClientRect();
const mousedonwX = bounds.width * mouseDownPosition;
const mousemoveX = bounds.width * mouseMovePosition;
info(`Drag on scrubber from ${ mousedonwX } to ${ mousemoveX }`);
EventUtils.synthesizeMouse(controllerEl, mousedonwX, mouseYPixel,
{ type: "mousedown" }, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
EventUtils.synthesizeMouse(controllerEl, mousemoveX, mouseYPixel,
{ type: "mousemove" }, controllerEl.ownerGlobal);
EventUtils.synthesizeMouse(controllerEl, mousemoveX, mouseYPixel,
{ type: "mouseup" }, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Drag on the scrubber controller pane to update the animation current time.
*
* @param {AnimationsPanel} panel
* @param {Number} mouseDownPosition
* rate on scrubber controller pane.
* This method calculates
* `mouseDownPosition * offsetWidth + offsetLeft of scrubber controller pane`
* as the clientX of MouseEvent.
* @param {Number} mouseMovePosition
* Dispatch mousemove event with mouseMovePosition after mousedown.
* Calculation for clinetX is same to above.
*/
const dragOnCurrentTimeScrubberController = async function(animationInspector,
panel,
mouseDownPosition,
mouseMovePosition) {
const controllerEl = panel.querySelector(".current-time-scrubber-controller");
const bounds = controllerEl.getBoundingClientRect();
const mousedonwX = bounds.width * mouseDownPosition;
const mousemoveX = bounds.width * mouseMovePosition;
info(`Drag on scrubber controller from ${ mousedonwX } to ${ mousemoveX }`);
EventUtils.synthesizeMouse(controllerEl, mousedonwX, 0,
{ type: "mousedown" }, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
EventUtils.synthesizeMouse(controllerEl, mousemoveX, 0,
{ type: "mousemove" }, controllerEl.ownerGlobal);
EventUtils.synthesizeMouse(controllerEl, mousemoveX, 0,
{ type: "mouseup" }, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Get current animation duration and rate of
* clickOrDragOnCurrentTimeScrubberController in given pixels.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* @param {Number} pixels
* @return {Object}
* {
* duration,
* rate,
* }
*/
const getDurationAndRate = function(animationInspector, panel, pixels) {
const controllerEl = panel.querySelector(".current-time-scrubber-controller");
const bounds = controllerEl.getBoundingClientRect();
const duration =
animationInspector.state.timeScale.getDuration() / bounds.width * pixels;
const rate = 1 / bounds.width * pixels;
return { duration, rate };
};
/** /**
* Set the inspector's current selection to a node or to the first match of the * Set the inspector's current selection to a node or to the first match of the
* given css selector and wait for the animations to be displayed * given css selector and wait for the animations to be displayed
@ -144,6 +316,18 @@ const selectNodeAndWaitForAnimations = async function(data, inspector, reason =
await waitForRendering(inspector.animationinspector); await waitForRendering(inspector.animationinspector);
}; };
/**
* Send keyboard event of space to given panel.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
*/
const sendSpaceKeyEvent = async function(animationInspector, panel) {
panel.focus();
EventUtils.sendKey("SPACE", panel.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/** /**
* Set the sidebar width by given parameter. * Set the sidebar width by given parameter.
* *
@ -177,8 +361,10 @@ const waitForRendering = async function(animationInspector) {
* *
* @param {AnimationInspector} inspector * @param {AnimationInspector} inspector
*/ */
const waitForAnimationDetail = async function(animationInspector) { const waitForAnimationDetail = async function(animationInspector) {
if (animationInspector.animations.length === 1) { if (animationInspector.state.selectedAnimation &&
animationInspector.state.detailVisibility) {
await animationInspector.once("animation-keyframes-rendered"); await animationInspector.once("animation-keyframes-rendered");
} }
}; };
@ -190,7 +376,7 @@ const waitForAnimationDetail = async function(animationInspector) {
* @param {AnimationInspector} animationInspector * @param {AnimationInspector} animationInspector
*/ */
const waitForAllAnimationTargets = async function(animationInspector) { const waitForAllAnimationTargets = async function(animationInspector) {
for (let i = 0; i < animationInspector.animations.length; i++) { for (let i = 0; i < animationInspector.state.animations.length; i++) {
await animationInspector.once("animation-target-rendered"); await animationInspector.once("animation-target-rendered");
} }
}; };
@ -201,11 +387,74 @@ const waitForAllAnimationTargets = async function(animationInspector) {
* @param {AnimationInspector} inspector * @param {AnimationInspector} inspector
*/ */
const waitForAllSummaryGraph = async function(animationInspector) { const waitForAllSummaryGraph = async function(animationInspector) {
for (let i = 0; i < animationInspector.animations.length; i++) { for (let i = 0; i < animationInspector.state.animations.length; i++) {
await animationInspector.once("animation-summary-graph-rendered"); await animationInspector.once("animation-summary-graph-rendered");
} }
}; };
/**
* Wait for rendering of all summary graph and detail.
*
* @param {AnimationInspector} inspector
*/
const waitForSummaryAndDetail = async function(animationInspector) {
await Promise.all([
waitForAllSummaryGraph(animationInspector),
waitForAnimationDetail(animationInspector),
]);
};
/**
* Check whether current time of all animations and UI are given specified time.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* @param {Number} time
*/
function assertAnimationsCurrentTime(animationInspector, time) {
const isTimeEqual =
animationInspector.state.animations.every(({state}) => state.currentTime === time);
ok(isTimeEqual, `Current time of animations should be ${ time }`);
}
/**
* Check whether the animations are pausing.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
*/
function assertAnimationsPausing(animationInspector, panel) {
assertAnimationsPausingOrRunning(animationInspector, panel, true);
}
/**
* Check whether the animations are pausing/running.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* @param {boolean} shouldPause
*/
function assertAnimationsPausingOrRunning(animationInspector, panel, shouldPause) {
const hasRunningAnimation =
animationInspector.state.animations.some(({state}) => state.playState === "running");
if (shouldPause) {
is(hasRunningAnimation, false, "All animations should be paused");
} else {
is(hasRunningAnimation, true, "Animations should be running at least one");
}
}
/**
* Check whether the animations are running.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
*/
function assertAnimationsRunning(animationInspector, panel) {
assertAnimationsPausingOrRunning(animationInspector, panel, false);
}
/** /**
* Check the <stop> element in the given linearGradientEl for the correct offset * Check the <stop> element in the given linearGradientEl for the correct offset
* and color attributes. * and color attributes.

Просмотреть файл

@ -24,6 +24,8 @@ class TimeScale {
constructor(animations) { constructor(animations) {
this.minStartTime = Infinity; this.minStartTime = Infinity;
this.maxEndTime = 0; this.maxEndTime = 0;
this.documentCurrentTime = 0;
for (const animation of animations) { for (const animation of animations) {
this.addAnimation(animation.state); this.addAnimation(animation.state);
} }
@ -38,11 +40,12 @@ class TimeScale {
addAnimation(state) { addAnimation(state) {
let { let {
delay, delay,
documentCurrentTime,
duration, duration,
endDelay = 0, endDelay = 0,
iterationCount, iterationCount,
playbackRate, playbackRate,
previousStartTime, previousStartTime = 0,
} = state; } = state;
const toRate = v => v / playbackRate; const toRate = v => v / playbackRate;
@ -53,8 +56,6 @@ class TimeScale {
// be displaying the delay outside the time window if we didn't take it into // be displaying the delay outside the time window if we didn't take it into
// account here. // account here.
const relevantDelay = delay < 0 ? toRate(delay) : 0; const relevantDelay = delay < 0 ? toRate(delay) : 0;
previousStartTime = previousStartTime || 0;
const startTime = toRate(minZero(delay)) + const startTime = toRate(minZero(delay)) +
rateRelativeDuration + rateRelativeDuration +
endDelay; endDelay;
@ -67,6 +68,8 @@ class TimeScale {
const length = toRate(delay) + rateRelativeDuration + toRate(minZero(endDelay)); const length = toRate(delay) + rateRelativeDuration + toRate(minZero(endDelay));
const endTime = previousStartTime + length; const endTime = previousStartTime + length;
this.maxEndTime = Math.max(this.maxEndTime, endTime); this.maxEndTime = Math.max(this.maxEndTime, endTime);
this.documentCurrentTime = Math.max(this.documentCurrentTime, documentCurrentTime);
} }
/** /**

Просмотреть файл

@ -69,6 +69,27 @@ function isAllAnimationEqual(animationsA, animationsB) {
return true; return true;
} }
/**
* Check whether or not the given list of animations has an iteration count of infinite.
*
* @param {Array} animations.
* @return {Boolean} true if there is an animation in the list of animations
* whose animation iteration count is infinite.
*/
function hasAnimationIterationCountInfinite(animations) {
return animations.some(({state}) => !state.iterationCount);
}
/**
* Check wether the animations are running at least one.
*
* @param {Array} animations.
* @return {Boolean} true: running
*/
function hasRunningAnimation(animations) {
return animations.some(({state}) => state.playState === "running");
}
/** /**
* Check the equality given states as effect timing. * Check the equality given states as effect timing.
* *
@ -88,5 +109,7 @@ function isTimingEffectEqual(stateA, stateB) {
} }
exports.findOptimalTimeInterval = findOptimalTimeInterval; exports.findOptimalTimeInterval = findOptimalTimeInterval;
exports.hasAnimationIterationCountInfinite = hasAnimationIterationCountInfinite;
exports.hasRunningAnimation = hasRunningAnimation;
exports.isAllAnimationEqual = isAllAnimationEqual; exports.isAllAnimationEqual = isAllAnimationEqual;
exports.isTimingEffectEqual = isTimingEffectEqual; exports.isTimingEffectEqual = isTimingEffectEqual;

Просмотреть файл

@ -49,6 +49,7 @@ class Census extends Component {
return Tree({ return Tree({
autoExpandDepth: 0, autoExpandDepth: 0,
preventNavigationOnArrowRight: false,
focused: census.focused, focused: census.focused,
getParent: node => { getParent: node => {
const parent = parentMap[node.id]; const parent = parentMap[node.id];

Просмотреть файл

@ -134,6 +134,7 @@ class DominatorTree extends Component {
return Tree({ return Tree({
key: "dominator-tree-tree", key: "dominator-tree-tree",
autoExpandDepth: DOMINATOR_TREE_AUTO_EXPAND_DEPTH, autoExpandDepth: DOMINATOR_TREE_AUTO_EXPAND_DEPTH,
preventNavigationOnArrowRight: false,
focused: dominatorTree.focused, focused: dominatorTree.focused,
getParent: node => getParent: node =>
node instanceof DominatorTreeLazyChildren node instanceof DominatorTreeLazyChildren

Просмотреть файл

@ -35,6 +35,7 @@ class Individuals extends Component {
return Tree({ return Tree({
key: "individuals-tree", key: "individuals-tree",
autoExpandDepth: 0, autoExpandDepth: 0,
preventNavigationOnArrowRight: false,
focused: individuals.focused, focused: individuals.focused,
getParent: node => null, getParent: node => null,
getChildren: node => [], getChildren: node => [],

Просмотреть файл

@ -189,6 +189,7 @@ class JITOptimizations extends Component {
return Tree({ return Tree({
autoExpandDepth, autoExpandDepth,
preventNavigationOnArrowRight: false,
getParent: node => { getParent: node => {
let site = getSite(node.id); let site = getSite(node.id);
let parent; let parent;

Просмотреть файл

@ -163,6 +163,7 @@ class WaterfallTree extends Component {
render() { render() {
return Tree({ return Tree({
preventNavigationOnArrowRight: false,
getRoots: this._getRoots, getRoots: this._getRoots,
getParent: this._getParent, getParent: this._getParent,
getChildren: this._getChildren, getChildren: this._getChildren,

Просмотреть файл

@ -198,6 +198,10 @@ class Tree extends Component {
// Handle when item is activated with a keyboard (using Space or Enter) // Handle when item is activated with a keyboard (using Space or Enter)
onActivate: PropTypes.func, onActivate: PropTypes.func,
// Indicates if pressing ArrowRight key should only expand expandable node
// or if the selection should also move to the next node.
preventNavigationOnArrowRight: PropTypes.bool,
// The depth to which we should automatically expand new items. // The depth to which we should automatically expand new items.
autoExpandDepth: PropTypes.number, autoExpandDepth: PropTypes.number,
@ -228,6 +232,7 @@ class Tree extends Component {
static get defaultProps() { static get defaultProps() {
return { return {
autoExpandDepth: AUTO_EXPAND_DEPTH, autoExpandDepth: AUTO_EXPAND_DEPTH,
preventNavigationOnArrowRight: true,
}; };
} }
@ -502,9 +507,10 @@ class Tree extends Component {
break; break;
case "ArrowRight": case "ArrowRight":
if (!this.props.isExpanded(this.props.focused)) { if (this.props.getChildren(this.props.focused).length &&
!this.props.isExpanded(this.props.focused)) {
this._onExpand(this.props.focused); this._onExpand(this.props.focused);
} else { } else if (!this.props.preventNavigationOnArrowRight) {
this._focusNextNode(); this._focusNextNode();
} }
break; break;

Просмотреть файл

@ -16,12 +16,17 @@ Test keyboard navigation with the Tree component.
<pre id="test"> <pre id="test">
<script src="head.js" type="application/javascript"></script> <script src="head.js" type="application/javascript"></script>
<script type="application/javascript"> <script type="application/javascript">
"use strict";
window.onload = async function () { window.onload = async function () {
try { try {
const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom"); const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
const { createFactory } = browserRequire("devtools/client/shared/vendor/react"); const { createFactory } = browserRequire("devtools/client/shared/vendor/react");
const { Simulate } = browserRequire("devtools/client/shared/vendor/react-dom-test-utils"); const { Simulate } =
const Tree = createFactory(browserRequire("devtools/client/shared/components/VirtualizedTree")); browserRequire("devtools/client/shared/vendor/react-dom-test-utils");
const Tree =
createFactory(browserRequire("devtools/client/shared/components/VirtualizedTree"));
function renderTree(props) { function renderTree(props) {
const treeProps = Object.assign({}, const treeProps = Object.assign({},
@ -175,7 +180,8 @@ window.onload = async function () {
"M:false", "M:false",
"-N:false", "-N:false",
"--O:true", "--O:true",
], "After the DOWN, O should still be focused and we shouldn't have overflowed past it."); ], "After the DOWN, O should still be focused " +
"and we shouldn't have overflowed past it.");
// LEFT -------------------------------------------------------------------- // LEFT --------------------------------------------------------------------
@ -246,7 +252,30 @@ window.onload = async function () {
"--O:false", "--O:false",
], "After the RIGHT, E's children should be expanded again."); ], "After the RIGHT, E's children should be expanded again.");
info("Right to go to next item."); info("Right on already expanded node.");
Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowRight" });
await forceRender(tree);
isRenderedTree(document.body.textContent, [
"A:false",
"-B:false",
"--E:true",
"---K:false",
"---L:false",
"--F:false",
"--G:false",
"-C:false",
"--H:false",
"--I:false",
"-D:false",
"--J:false",
"M:false",
"-N:false",
"--O:false",
], "After the RIGHT on already expanded node, E should remain focused.");
info("Right when preventNavigationOnArrowRight is unset to go to next item.");
renderTree({ focused: "E", preventNavigationOnArrowRight: false });
Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowRight" }); Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowRight" });
await forceRender(tree); await forceRender(tree);
@ -275,6 +304,8 @@ window.onload = async function () {
{ key: "ArrowDown", metaKey: true }, { key: "ArrowDown", metaKey: true },
{ key: "ArrowDown", shiftKey: true }, { key: "ArrowDown", shiftKey: true },
]; ];
await forceRender(tree);
for (let key of keysWithModifier) { for (let key of keysWithModifier) {
Simulate.keyDown(document.querySelector(".tree"), key); Simulate.keyDown(document.querySelector(".tree"), key);
await forceRender(tree); await forceRender(tree);
@ -297,7 +328,7 @@ window.onload = async function () {
"--O:false", "--O:false",
], "After DOWN + (alt|ctrl|meta|shift), K should remain focused."); ], "After DOWN + (alt|ctrl|meta|shift), K should remain focused.");
} }
} catch(e) { } catch (e) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
} finally { } finally {
SimpleTest.finish(); SimpleTest.finish();

Просмотреть файл

@ -13,6 +13,11 @@
--fill-color-scriptanimation: var(--theme-graphs-green); --fill-color-scriptanimation: var(--theme-graphs-green);
--graph-right-offset: 10px; --graph-right-offset: 10px;
--keyframe-marker-shadow-color: #c4c4c4; --keyframe-marker-shadow-color: #c4c4c4;
--pause-image: url(chrome://devtools/skin/images/pause.svg);
--progress-bar-color: #909090;
--resume-image: url(chrome://devtools/skin/images/play.svg);
--rewind-image: url(chrome://devtools/skin/images/rewind.svg);
--scrubber-color: #dd00a9;
--sidebar-width: 200px; --sidebar-width: 200px;
--stroke-color-cssanimation: var(--theme-highlight-lightorange); --stroke-color-cssanimation: var(--theme-highlight-lightorange);
--stroke-color-csstransition: var(--theme-highlight-bluegrey); --stroke-color-csstransition: var(--theme-highlight-bluegrey);
@ -27,10 +32,15 @@
:root.theme-firebug { :root.theme-firebug {
--command-pick-image: url(chrome://devtools/skin/images/firebug/command-pick.svg); --command-pick-image: url(chrome://devtools/skin/images/firebug/command-pick.svg);
--pause-image: url(chrome://devtools/skin/images/firebug/pause.svg);
--resume-image: url(chrome://devtools/skin/images/firebug/play.svg);
--rewind-image: url(chrome://devtools/skin/images/firebug/rewind.svg);
} }
/* Root element of animation inspector */ /* Root element of animation inspector */
#animation-container { #animation-container {
display: flex;
flex-direction: column;
height: 100%; height: 100%;
} }
@ -42,6 +52,44 @@
display: none; display: none;
} }
#animation-container .animation-container-splitter {
overflow: auto;
}
/* Animation Toolbar */
.animation-toolbar {
display: flex;
}
.pause-resume-button::before {
background-image: var(--pause-image);
}
.pause-resume-button.paused::before {
background-image: var(--resume-image);
}
select.playback-rate-selector.devtools-button {
background-image: url("chrome://devtools/skin/images/dropmarker.svg");
background-position: calc(100% - 4px) center;
background-repeat: no-repeat;
padding-right: 1em;
text-align: center;
}
select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.checked):hover {
background: none;
background-color: var(--toolbarbutton-background);
background-image: url("chrome://devtools/skin/images/dropmarker.svg");
background-position: calc(100% - 4px) center;
background-repeat: no-repeat;
border-color: var(--toolbarbutton-hover-border-color);
}
.rewind-button::before {
background-image: var(--rewind-image);
}
/* Animation List Container */ /* Animation List Container */
.animation-list-container { .animation-list-container {
display: flex; display: flex;
@ -49,28 +97,69 @@
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
-moz-user-select: none;
}
.animation-list-container.active-scrubber {
cursor: col-resize;
} }
/* Animation List Header */ /* Animation List Header */
.animation-list-header { .animation-list-header {
display: flex; display: grid;
justify-content: flex-end; grid-template-columns: var(--sidebar-width) calc(100% - var(--sidebar-width) - var(--graph-right-offset)) var(--graph-right-offset);
padding: 0; padding: 0;
} }
/* Animation Timeline Tick List */ /* Animation Timeline Tick List */
.animation-timeline-tick-list { .animation-timeline-tick-list {
margin-right: var(--graph-right-offset); grid-column: 2/3;
position: relative; position: relative;
width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
} }
.animation-timeline-tick-item { .animation-timeline-tick-item {
border-left: var(--tick-line-style); border-left: var(--tick-line-style);
height: 100vh; height: 100vh;
pointer-events: none;
position: absolute; position: absolute;
} }
/* Current Time Scrubber */
.current-time-scrubber-controller {
cursor: col-resize;
grid-column: 2 / 3;
padding: 0;
}
.current-time-scrubber {
cursor: col-resize;
height: 100vh;
margin-left: -6px;
position: absolute;
width: 12px;
z-index: 1;
}
.current-time-scrubber::before {
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid var(--scrubber-color);
content: "";
position: absolute;
top: 0;
width: 0;
}
.current-time-scrubber::after {
border-left: 1px solid var(--scrubber-color);
content: "";
height: 100%;
left: 5px;
position: absolute;
top: 0;
width: 0;
}
/* Animation List */ /* Animation List */
.animation-list { .animation-list {
flex: 1; flex: 1;
@ -241,11 +330,13 @@
/* Animation Detail */ /* Animation Detail */
.animation-detail-container { .animation-detail-container {
background-color: var(--theme-body-background);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
z-index: 1;
} }
.animation-detail-header { .animation-detail-header {
@ -266,21 +357,20 @@
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
overflow-y: auto; overflow: hidden;
} }
/* Animated Property List Header */ /* Animated Property List Header */
.animated-property-list-header { .animated-property-list-header {
display: flex; display: grid;
justify-content: flex-end; grid-template-columns: var(--sidebar-width) calc(100% - var(--sidebar-width) - var(--graph-right-offset)) var(--graph-right-offset);
padding: 0; padding: 0;
} }
/* Keyframes Progress Tick List */ /* Keyframes Progress Tick List */
.keyframes-progress-tick-list { .keyframes-progress-tick-list {
margin-right: var(--graph-right-offset); grid-column: 2 / 3;
position: absolute; position: relative;
width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
} }
.keyframes-progress-tick-item { .keyframes-progress-tick-item {
@ -296,6 +386,41 @@
border-right: var(--tick-line-style); border-right: var(--tick-line-style);
} }
/* Keyframes Progress Bar */
.keyframes-progress-bar-area {
background: none;
grid-column: 2 / 3;
padding: 0;
pointer-events: none;
position: relative;
}
.keyframes-progress-bar {
height: 100vh;
position: absolute;
z-index: 1;
}
.keyframes-progress-bar::before {
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid var(--progress-bar-color);
content: "";
left: -5px;
position: absolute;
top: 0;
width: 0;
}
.keyframes-progress-bar::after {
border-left: 1px solid var(--progress-bar-color);
content: "";
height: 100%;
position: absolute;
top: 0;
width: 0;
}
/* Animated Property List */ /* Animated Property List */
.animated-property-list { .animated-property-list {
flex: 1; flex: 1;

Просмотреть файл

@ -1918,7 +1918,7 @@ DebuggerServer.ObjectActorPreviewers.Object = [
props.push("propertyName", "pseudoElement"); props.push("propertyName", "pseudoElement");
} else if (obj.class == "AnimationEvent") { } else if (obj.class == "AnimationEvent") {
props.push("animationName", "pseudoElement"); props.push("animationName", "pseudoElement");
} else if (rawObj instanceof Ci.nsIDOMClipboardEvent) { } else if (obj.class == "ClipboardEvent") {
props.push("clipboardData"); props.push("clipboardData");
} }

Просмотреть файл

@ -214,6 +214,12 @@ Element::GetSVGAnimatedClass() const
NS_IMETHODIMP NS_IMETHODIMP
Element::QueryInterface(REFNSIID aIID, void** aInstancePtr) Element::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{ {
if (aIID.Equals(NS_GET_IID(Element))) {
NS_ADDREF_THIS();
*aInstancePtr = this;
return NS_OK;
}
NS_ASSERTION(aInstancePtr, NS_ASSERTION(aInstancePtr,
"QueryInterface requires a non-NULL destination!"); "QueryInterface requires a non-NULL destination!");
nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr); nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr);
@ -1706,11 +1712,6 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
if (ShadowRoot* shadowRootParent = ShadowRoot::FromNode(parent)) { if (ShadowRoot* shadowRootParent = ShadowRoot::FromNode(parent)) {
parent = shadowRootParent->GetHost(); parent = shadowRootParent->GetHost();
} }
bool inStyleScope = parent->IsElementInStyleScope();
SetIsElementInStyleScope(inStyleScope);
SetIsElementInStyleScopeFlagOnShadowTree(inStyleScope);
} }
// This has to be here, rather than in nsGenericHTMLElement::BindToTree, // This has to be here, rather than in nsGenericHTMLElement::BindToTree,

Просмотреть файл

@ -2093,7 +2093,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN(FragmentOrElement) NS_INTERFACE_MAP_BEGIN(FragmentOrElement)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(FragmentOrElement) NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(FragmentOrElement)
NS_INTERFACE_MAP_ENTRY(Element)
NS_INTERFACE_MAP_ENTRY(nsIContent) NS_INTERFACE_MAP_ENTRY(nsIContent)
NS_INTERFACE_MAP_ENTRY(nsINode) NS_INTERFACE_MAP_ENTRY(nsINode)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
@ -2469,40 +2468,3 @@ FragmentOrElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
*aNodeSize += slots->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf); *aNodeSize += slots->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
} }
} }
void
FragmentOrElement::SetIsElementInStyleScopeFlagOnSubtree(bool aInStyleScope)
{
if (aInStyleScope && IsElementInStyleScope()) {
return;
}
if (IsElement()) {
SetIsElementInStyleScope(aInStyleScope);
SetIsElementInStyleScopeFlagOnShadowTree(aInStyleScope);
}
nsIContent* n = GetNextNode(this);
while (n) {
if (n->IsElementInStyleScope()) {
n = n->GetNextNonChildNode(this);
} else {
if (n->IsElement()) {
n->SetIsElementInStyleScope(aInStyleScope);
n->AsElement()->SetIsElementInStyleScopeFlagOnShadowTree(aInStyleScope);
}
n = n->GetNextNode(this);
}
}
}
void
FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
{
NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
"on a non-Element is useless");
ShadowRoot* shadowRoot = GetShadowRoot();
if (shadowRoot) {
shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
}
}

Просмотреть файл

@ -164,14 +164,6 @@ public:
return Children()->Length(); return Children()->Length();
} }
/**
* Sets the IsElementInStyleScope flag on each element in the subtree rooted
* at this node, including any elements reachable through shadow trees.
*
* @param aInStyleScope The flag value to set.
*/
void SetIsElementInStyleScopeFlagOnSubtree(bool aInStyleScope);
public: public:
/** /**
* If there are listeners for DOMNodeInserted event, fires the event on all * If there are listeners for DOMNodeInserted event, fires the event on all
@ -375,14 +367,6 @@ protected:
return static_cast<nsExtendedDOMSlots*>(GetExistingExtendedContentSlots()); return static_cast<nsExtendedDOMSlots*>(GetExistingExtendedContentSlots());
} }
/**
* Calls SetIsElementInStyleScopeFlagOnSubtree for each shadow tree attached
* to this node, which is assumed to be an Element.
*
* @param aInStyleScope The IsElementInStyleScope flag value to set.
*/
void SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope);
friend class ::ContentUnbinder; friend class ::ContentUnbinder;
/** /**
* Array containing all attributes and children for this element * Array containing all attributes and children for this element

Просмотреть файл

@ -148,6 +148,7 @@ nsSimpleContentList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto
NS_IMPL_CYCLE_COLLECTION_INHERITED(nsEmptyContentList, nsBaseContentList, mRoot) NS_IMPL_CYCLE_COLLECTION_INHERITED(nsEmptyContentList, nsBaseContentList, mRoot)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEmptyContentList) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEmptyContentList)
NS_INTERFACE_MAP_ENTRY(nsIHTMLCollection)
NS_INTERFACE_MAP_END_INHERITING(nsBaseContentList) NS_INTERFACE_MAP_END_INHERITING(nsBaseContentList)
@ -157,7 +158,7 @@ NS_IMPL_RELEASE_INHERITED(nsEmptyContentList, nsBaseContentList)
JSObject* JSObject*
nsEmptyContentList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) nsEmptyContentList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
{ {
return NodeListBinding::Wrap(cx, this, aGivenProto); return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
} }
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -311,7 +311,6 @@ bool nsContentUtils::sAutoFocusEnabled = true;
#ifndef RELEASE_OR_BETA #ifndef RELEASE_OR_BETA
bool nsContentUtils::sBypassCSSOMOriginCheck = false; bool nsContentUtils::sBypassCSSOMOriginCheck = false;
#endif #endif
bool nsContentUtils::sIsScopedStyleEnabled = false;
bool nsContentUtils::sIsBytecodeCacheEnabled = false; bool nsContentUtils::sIsBytecodeCacheEnabled = false;
int32_t nsContentUtils::sBytecodeCacheStrategy = 0; int32_t nsContentUtils::sBytecodeCacheStrategy = 0;
@ -716,9 +715,6 @@ nsContentUtils::Init()
sBypassCSSOMOriginCheck = getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK"); sBypassCSSOMOriginCheck = getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK");
#endif #endif
Preferences::AddBoolVarCache(&sIsScopedStyleEnabled,
"layout.css.scoped-style.enabled", false);
Preferences::AddBoolVarCache(&sLowerNetworkPriority, Preferences::AddBoolVarCache(&sLowerNetworkPriority,
"privacy.trackingprotection.lower_network_priority", false); "privacy.trackingprotection.lower_network_priority", false);
@ -4146,7 +4142,8 @@ nsresult nsContentUtils::FormatLocalizedString(
/* static */ void /* static */ void
nsContentUtils::LogSimpleConsoleError(const nsAString& aErrorText, nsContentUtils::LogSimpleConsoleError(const nsAString& aErrorText,
const char * classification) const char * classification,
bool aFromPrivateWindow)
{ {
nsCOMPtr<nsIScriptError> scriptError = nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
@ -4156,7 +4153,8 @@ nsContentUtils::LogSimpleConsoleError(const nsAString& aErrorText,
if (console && NS_SUCCEEDED(scriptError->Init(aErrorText, EmptyString(), if (console && NS_SUCCEEDED(scriptError->Init(aErrorText, EmptyString(),
EmptyString(), 0, 0, EmptyString(), 0, 0,
nsIScriptError::errorFlag, nsIScriptError::errorFlag,
classification))) { classification,
aFromPrivateWindow))) {
console->LogMessage(scriptError); console->LogMessage(scriptError);
} }
} }
@ -5834,7 +5832,8 @@ nsContentUtils::WarnScriptWasIgnored(nsIDocument* aDocument)
} }
msg.AppendLiteral("Unable to run script because scripts are blocked internally."); msg.AppendLiteral("Unable to run script because scripts are blocked internally.");
LogSimpleConsoleError(msg, "DOM"); LogSimpleConsoleError(msg, "DOM",
!!aDocument->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId);
} }
/* static */ /* static */

Просмотреть файл

@ -1008,7 +1008,8 @@ public:
* @param classification Name of the module reporting error * @param classification Name of the module reporting error
*/ */
static void LogSimpleConsoleError(const nsAString& aErrorText, static void LogSimpleConsoleError(const nsAString& aErrorText,
const char * classification); const char * classification,
bool aFromPrivateWindow);
/** /**
* Report a non-localized error message to the error console. * Report a non-localized error message to the error console.
@ -2445,14 +2446,6 @@ public:
#endif #endif
} }
/**
* Returns true if the <style scoped> enabling pref is true.
*/
static bool IsScopedStylePrefEnabled()
{
return sIsScopedStyleEnabled;
}
/** /**
* Fire mutation events for changes caused by parsing directly into a * Fire mutation events for changes caused by parsing directly into a
* context node. * context node.
@ -3468,7 +3461,6 @@ private:
#ifndef RELEASE_OR_BETA #ifndef RELEASE_OR_BETA
static bool sBypassCSSOMOriginCheck; static bool sBypassCSSOMOriginCheck;
#endif #endif
static bool sIsScopedStyleEnabled;
static bool sIsBytecodeCacheEnabled; static bool sIsBytecodeCacheEnabled;
static int32_t sBytecodeCacheStrategy; static int32_t sBytecodeCacheStrategy;
static uint32_t sCookiesLifetimePolicy; static uint32_t sCookiesLifetimePolicy;

Просмотреть файл

@ -62,6 +62,7 @@
#include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/FramingChecker.h" #include "mozilla/dom/FramingChecker.h"
#include "mozilla/dom/HTMLSharedElement.h"
#include "nsGenericHTMLElement.h" #include "nsGenericHTMLElement.h"
#include "mozilla/dom/CDATASection.h" #include "mozilla/dom/CDATASection.h"
#include "mozilla/dom/ProcessingInstruction.h" #include "mozilla/dom/ProcessingInstruction.h"
@ -1500,8 +1501,8 @@ nsIDocument::nsIDocument()
mDelayFrameLoaderInitialization(false), mDelayFrameLoaderInitialization(false),
mSynchronousDOMContentLoaded(false), mSynchronousDOMContentLoaded(false),
mMaybeServiceWorkerControlled(false), mMaybeServiceWorkerControlled(false),
mIsScopedStyleEnabled(eScopedStyle_Unknown),
mPendingFullscreenRequests(0), mPendingFullscreenRequests(0),
mXMLDeclarationBits(0),
mCompatMode(eCompatibility_FullStandards), mCompatMode(eCompatibility_FullStandards),
mReadyState(ReadyState::READYSTATE_UNINITIALIZED), mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
mStyleBackendType(StyleBackendType::None), mStyleBackendType(StyleBackendType::None),
@ -1557,7 +1558,6 @@ nsDocument::nsDocument(const char* aContentType)
: nsIDocument() : nsIDocument()
, mParserAborted(false) , mParserAborted(false)
, mReportedUseCounters(false) , mReportedUseCounters(false)
, mXMLDeclarationBits(0)
, mOnloadBlockCount(0) , mOnloadBlockCount(0)
, mAsyncOnloadBlockCount(0) , mAsyncOnloadBlockCount(0)
, mValidWidth(false) , mValidWidth(false)
@ -1973,6 +1973,13 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingAnimationTracker) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingAnimationTracker)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImages);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEmbeds);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLinks);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mForms);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScripts);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplets);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
// Traverse all our nsCOMArrays. // Traverse all our nsCOMArrays.
@ -2063,6 +2070,13 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker) NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection) NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mImages);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEmbeds);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLinks);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mForms);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mScripts);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplets);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchors);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise) NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle); NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle);
@ -6316,6 +6330,12 @@ nsIDocument::SetBody(nsGenericHTMLElement* newBody, ErrorResult& rv)
} }
} }
HTMLSharedElement*
nsIDocument::GetHead()
{
return static_cast<HTMLSharedElement*>(GetHeadElement());
}
Element* Element*
nsIDocument::GetTitleElement() nsIDocument::GetTitleElement()
{ {
@ -6800,6 +6820,87 @@ nsIDocument::SetDir(const nsAString& aDirection)
} }
} }
nsIHTMLCollection*
nsIDocument::Images()
{
if (!mImages) {
mImages = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::img, nsGkAtoms::img);
}
return mImages;
}
nsIHTMLCollection*
nsIDocument::Embeds()
{
if (!mEmbeds) {
mEmbeds = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::embed, nsGkAtoms::embed);
}
return mEmbeds;
}
static bool
MatchLinks(Element* aElement, int32_t aNamespaceID,
nsAtom* aAtom, void* aData)
{
return aElement->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href);
}
nsIHTMLCollection*
nsIDocument::Links()
{
if (!mLinks) {
mLinks = new nsContentList(this, MatchLinks, nullptr, nullptr);
}
return mLinks;
}
nsIHTMLCollection*
nsIDocument::Forms()
{
if (!mForms) {
// Please keep this in sync with nsHTMLDocument::GetFormsAndFormControls.
mForms = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::form, nsGkAtoms::form);
}
return mForms;
}
nsIHTMLCollection*
nsIDocument::Scripts()
{
if (!mScripts) {
mScripts = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::script, nsGkAtoms::script);
}
return mScripts;
}
nsIHTMLCollection*
nsIDocument::Applets()
{
if (!mApplets) {
mApplets = new nsEmptyContentList(this);
}
return mApplets;
}
static bool
MatchAnchors(Element* aElement, int32_t aNamespaceID,
nsAtom* aAtom, void* aData)
{
return aElement->IsHTMLElement(nsGkAtoms::a) &&
aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::name);
}
nsIHTMLCollection*
nsIDocument::Anchors()
{
if (!mAnchors) {
mAnchors = new nsContentList(this, MatchAnchors, nullptr, nullptr);
}
return mAnchors;
}
/* static */ /* static */
bool bool
nsIDocument::MatchNameAttribute(Element* aElement, int32_t aNamespaceID, nsIDocument::MatchNameAttribute(Element* aElement, int32_t aNamespaceID,
@ -7626,9 +7727,9 @@ nsIDocument::FlushExternalResources(FlushType aType)
} }
void void
nsDocument::SetXMLDeclaration(const char16_t *aVersion, nsIDocument::SetXMLDeclaration(const char16_t* aVersion,
const char16_t *aEncoding, const char16_t* aEncoding,
const int32_t aStandalone) const int32_t aStandalone)
{ {
if (!aVersion || *aVersion == '\0') { if (!aVersion || *aVersion == '\0') {
mXMLDeclarationBits = 0; mXMLDeclarationBits = 0;
@ -7651,8 +7752,9 @@ nsDocument::SetXMLDeclaration(const char16_t *aVersion,
} }
void void
nsDocument::GetXMLDeclaration(nsAString& aVersion, nsAString& aEncoding, nsIDocument::GetXMLDeclaration(nsAString& aVersion,
nsAString& aStandalone) nsAString& aEncoding,
nsAString& aStandalone)
{ {
aVersion.Truncate(); aVersion.Truncate();
aEncoding.Truncate(); aEncoding.Truncate();
@ -13238,18 +13340,6 @@ nsIDocument::IsThirdParty()
return mIsThirdParty.value(); return mIsThirdParty.value();
} }
bool
nsIDocument::IsScopedStyleEnabled()
{
if (mIsScopedStyleEnabled == eScopedStyle_Unknown) {
mIsScopedStyleEnabled = nsContentUtils::IsChromeDoc(this) ||
nsContentUtils::IsScopedStylePrefEnabled()
? eScopedStyle_Enabled
: eScopedStyle_Disabled;
}
return mIsScopedStyleEnabled == eScopedStyle_Enabled;
}
void void
nsIDocument::ClearStaleServoData() nsIDocument::ClearStaleServoData()
{ {

Просмотреть файл

@ -199,13 +199,6 @@ public:
virtual void BeginLoad() override; virtual void BeginLoad() override;
virtual void EndLoad() override; virtual void EndLoad() override;
virtual void SetXMLDeclaration(const char16_t *aVersion,
const char16_t *aEncoding,
const int32_t aStandalone) override;
virtual void GetXMLDeclaration(nsAString& aVersion,
nsAString& aEncoding,
nsAString& Standalone) override;
// nsIRadioGroupContainer // nsIRadioGroupContainer
NS_IMETHOD WalkRadioGroup(const nsAString& aName, NS_IMETHOD WalkRadioGroup(const nsAString& aName,
nsIRadioVisitor* aVisitor, nsIRadioVisitor* aVisitor,
@ -404,8 +397,6 @@ public:
// that we only report them once for the document. // that we only report them once for the document.
bool mReportedUseCounters:1; bool mReportedUseCounters:1;
uint8_t mXMLDeclarationBits;
// The application cache that this document is associated with, if // The application cache that this document is associated with, if
// any. This can change during the lifetime of the document. // any. This can change during the lifetime of the document.
nsCOMPtr<nsIApplicationCache> mApplicationCache; nsCOMPtr<nsIApplicationCache> mApplicationCache;

Просмотреть файл

@ -515,7 +515,8 @@ GetParamsForMessage(JSContext* aCx,
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
error->Init(NS_LITERAL_STRING("Sending message that cannot be cloned. Are you trying to send an XPCOM object?"), error->Init(NS_LITERAL_STRING("Sending message that cannot be cloned. Are you trying to send an XPCOM object?"),
filename, EmptyString(), lineno, column, filename, EmptyString(), lineno, column,
nsIScriptError::warningFlag, "chrome javascript"); nsIScriptError::warningFlag, "chrome javascript",
false /* from private window */);
console->LogMessage(error); console->LogMessage(error);
} }
@ -1111,7 +1112,8 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
if (console) { if (console) {
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
error->Init(msg, EmptyString(), EmptyString(), error->Init(msg, EmptyString(), EmptyString(),
0, 0, nsIScriptError::warningFlag, "chrome javascript"); 0, 0, nsIScriptError::warningFlag, "chrome javascript",
false /* from private window */);
console->LogMessage(error); console->LogMessage(error);
} }

Просмотреть файл

@ -5826,7 +5826,8 @@ nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> a
R"(origin "%s" from a system principal scope with mismatched )" R"(origin "%s" from a system principal scope with mismatched )"
R"(origin "%s".)", R"(origin "%s".)",
targetURL.get(), targetOrigin.get(), sourceOrigin.get())), targetURL.get(), targetOrigin.get(), sourceOrigin.get())),
"DOM"); "DOM",
!!principal->PrivateBrowsingId());
attrs = principal->OriginAttributesRef(); attrs = principal->OriginAttributesRef();
} }

Просмотреть файл

@ -166,6 +166,7 @@ class FrameRequestCallback;
struct FullscreenRequest; struct FullscreenRequest;
class ImageTracker; class ImageTracker;
class HTMLBodyElement; class HTMLBodyElement;
class HTMLSharedElement;
class HTMLImageElement; class HTMLImageElement;
struct LifecycleCallbackArgs; struct LifecycleCallbackArgs;
class Link; class Link;
@ -1598,6 +1599,8 @@ public:
nsGenericHTMLElement* GetBody(); nsGenericHTMLElement* GetBody();
// Set the "body" in the sense of document.body. // Set the "body" in the sense of document.body.
void SetBody(nsGenericHTMLElement* aBody, mozilla::ErrorResult& rv); void SetBody(nsGenericHTMLElement* aBody, mozilla::ErrorResult& rv);
// Get the "head" element in the sense of document.head.
mozilla::dom::HTMLSharedElement* GetHead();
/** /**
* Accessors to the collection of stylesheets owned by this document. * Accessors to the collection of stylesheets owned by this document.
@ -2134,12 +2137,12 @@ public:
* was no standalone parameter in the declaration, that it was given as no, * was no standalone parameter in the declaration, that it was given as no,
* or that it was given as yes. * or that it was given as yes.
*/ */
virtual void SetXMLDeclaration(const char16_t *aVersion, void SetXMLDeclaration(const char16_t* aVersion,
const char16_t *aEncoding, const char16_t* aEncoding,
const int32_t aStandalone) = 0; const int32_t aStandalone);
virtual void GetXMLDeclaration(nsAString& aVersion, void GetXMLDeclaration(nsAString& aVersion,
nsAString& aEncoding, nsAString& aEncoding,
nsAString& Standalone) = 0; nsAString& Standalone);
/** /**
* Returns true if this is what HTML 5 calls an "HTML document" (for example * Returns true if this is what HTML 5 calls an "HTML document" (for example
@ -3280,6 +3283,15 @@ public:
void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv); void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv);
void GetDir(nsAString& aDirection) const; void GetDir(nsAString& aDirection) const;
void SetDir(const nsAString& aDirection); void SetDir(const nsAString& aDirection);
nsIHTMLCollection* Images();
nsIHTMLCollection* Embeds();
nsIHTMLCollection* Plugins()
{
return Embeds();
}
nsIHTMLCollection* Links();
nsIHTMLCollection* Forms();
nsIHTMLCollection* Scripts();
already_AddRefed<nsContentList> GetElementsByName(const nsAString& aName) already_AddRefed<nsContentList> GetElementsByName(const nsAString& aName)
{ {
return GetFuncStringContentList<nsCachableElementsByNameNodeList>(this, return GetFuncStringContentList<nsCachableElementsByNameNodeList>(this,
@ -3294,6 +3306,8 @@ public:
} }
Element* GetActiveElement(); Element* GetActiveElement();
bool HasFocus(mozilla::ErrorResult& rv) const; bool HasFocus(mozilla::ErrorResult& rv) const;
nsIHTMLCollection* Applets();
nsIHTMLCollection* Anchors();
mozilla::TimeStamp LastFocusTime() const; mozilla::TimeStamp LastFocusTime() const;
void SetLastFocusTime(const mozilla::TimeStamp& aFocusTime); void SetLastFocusTime(const mozilla::TimeStamp& aFocusTime);
// Event handlers are all on nsINode already // Event handlers are all on nsINode already
@ -3871,6 +3885,15 @@ protected:
// Our cached .children collection // Our cached .children collection
nsCOMPtr<nsIHTMLCollection> mChildrenCollection; nsCOMPtr<nsIHTMLCollection> mChildrenCollection;
// Various DOM lists
RefPtr<nsContentList> mImages;
RefPtr<nsContentList> mEmbeds;
RefPtr<nsContentList> mLinks;
RefPtr<nsContentList> mForms;
RefPtr<nsContentList> mScripts;
nsCOMPtr<nsIHTMLCollection> mApplets;
RefPtr<nsContentList> mAnchors;
// container for per-context fonts (downloadable, SVG, etc.) // container for per-context fonts (downloadable, SVG, etc.)
RefPtr<mozilla::dom::FontFaceSet> mFontFaceSet; RefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
@ -4105,12 +4128,10 @@ protected:
// Used to prevent multiple requests to ServiceWorkerManager. // Used to prevent multiple requests to ServiceWorkerManager.
bool mMaybeServiceWorkerControlled: 1; bool mMaybeServiceWorkerControlled: 1;
// Whether <style scoped> support is enabled in this document.
enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
unsigned int mIsScopedStyleEnabled : 2;
uint8_t mPendingFullscreenRequests; uint8_t mPendingFullscreenRequests;
uint8_t mXMLDeclarationBits;
// Compatibility mode // Compatibility mode
nsCompatibility mCompatMode; nsCompatibility mCompatMode;

Просмотреть файл

@ -1662,11 +1662,6 @@ private:
NodeHasTextNodeDirectionalityMap, NodeHasTextNodeDirectionalityMap,
// Set if a node in the node's parent chain has dir=auto. // Set if a node in the node's parent chain has dir=auto.
NodeAncestorHasDirAuto, NodeAncestorHasDirAuto,
// Set if the element is in the scope of a scoped style sheet; this flag is
// only accurate for elements bound to a document
ElementIsInStyleScope,
// Set if the element is a scoped style sheet root
ElementIsScopedStyleRoot,
// Set if the node is handling a click. // Set if the node is handling a click.
NodeHandlingClick, NodeHandlingClick,
// Set if the node has had :hover selectors matched against it // Set if the node has had :hover selectors matched against it
@ -1795,23 +1790,6 @@ public:
// Implemented in nsIContentInlines.h. // Implemented in nsIContentInlines.h.
inline bool NodeOrAncestorHasDirAuto() const; inline bool NodeOrAncestorHasDirAuto() const;
void SetIsElementInStyleScope(bool aValue) {
MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node");
SetBoolFlag(ElementIsInStyleScope, aValue);
}
void SetIsElementInStyleScope() {
MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node");
SetBoolFlag(ElementIsInStyleScope);
}
void ClearIsElementInStyleScope() {
MOZ_ASSERT(IsElement(), "ClearIsInStyleScope on a non-Element node");
ClearBoolFlag(ElementIsInStyleScope);
}
bool IsElementInStyleScope() const { return GetBoolFlag(ElementIsInStyleScope); }
void SetIsScopedStyleRoot() { SetBoolFlag(ElementIsScopedStyleRoot); }
void ClearIsScopedStyleRoot() { ClearBoolFlag(ElementIsScopedStyleRoot); }
bool IsScopedStyleRoot() { return GetBoolFlag(ElementIsScopedStyleRoot); }
bool HasRelevantHoverRules() const { return GetBoolFlag(NodeHasRelevantHoverRules); } bool HasRelevantHoverRules() const { return GetBoolFlag(NodeHasRelevantHoverRules); }
void SetHasRelevantHoverRules() { SetBoolFlag(NodeHasRelevantHoverRules); } void SetHasRelevantHoverRules() { SetBoolFlag(NodeHasRelevantHoverRules); }
void SetParserHasNotified() { SetBoolFlag(ParserHasNotified); }; void SetParserHasNotified() { SetBoolFlag(ParserHasNotified); };

Просмотреть файл

@ -330,56 +330,6 @@ nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument *aOldDocument,
&alternate, aForceUpdate); &alternate, aForceUpdate);
} }
static bool
IsScopedStyleElement(nsIContent* aContent)
{
// This is quicker than, say, QIing aContent to nsStyleLinkElement
// and then calling its virtual GetStyleSheetInfo method to find out
// if it is scoped.
return (aContent->IsHTMLElement(nsGkAtoms::style) ||
aContent->IsSVGElement(nsGkAtoms::style)) &&
aContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::scoped) &&
aContent->OwnerDoc()->IsScopedStyleEnabled();
}
static bool
HasScopedStyleSheetChild(nsIContent* aContent)
{
for (nsIContent* n = aContent->GetFirstChild(); n; n = n->GetNextSibling()) {
if (IsScopedStyleElement(n)) {
return true;
}
}
return false;
}
// Called when aElement has had a <style scoped> child removed.
static void
UpdateIsElementInStyleScopeFlagOnSubtree(Element* aElement)
{
NS_ASSERTION(aElement->IsElementInStyleScope(),
"only call UpdateIsElementInStyleScopeFlagOnSubtree on a "
"subtree that has IsElementInStyleScope boolean flag set");
if (HasScopedStyleSheetChild(aElement)) {
return;
}
aElement->ClearIsElementInStyleScope();
nsIContent* n = aElement->GetNextNode(aElement);
while (n) {
if (HasScopedStyleSheetChild(n)) {
n = n->GetNextNonChildNode(aElement);
} else {
if (n->IsElement()) {
n->ClearIsElementInStyleScope();
}
n = n->GetNextNode(aElement);
}
}
}
nsresult nsresult
nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument, nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
ShadowRoot* aOldShadowRoot, ShadowRoot* aOldShadowRoot,
@ -409,20 +359,6 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
return NS_OK; return NS_OK;
} }
// XXXheycam ServoStyleSheets do not support <style scoped>.
Element* oldScopeElement = nullptr;
if (mStyleSheet) {
if (mStyleSheet->IsServo()) {
// XXXheycam ServoStyleSheets don't support <style scoped>.
} else {
#ifdef MOZ_OLD_STYLE
oldScopeElement = mStyleSheet->AsGecko()->GetScopeElement();
#else
MOZ_CRASH("old style system disabled");
#endif
}
}
if (mStyleSheet && (aOldDocument || aOldShadowRoot)) { if (mStyleSheet && (aOldDocument || aOldShadowRoot)) {
MOZ_ASSERT(!(aOldDocument && aOldShadowRoot), MOZ_ASSERT(!(aOldDocument && aOldShadowRoot),
"ShadowRoot content is never in document, thus " "ShadowRoot content is never in document, thus "
@ -442,9 +378,6 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
} }
nsStyleLinkElement::SetStyleSheet(nullptr); nsStyleLinkElement::SetStyleSheet(nullptr);
if (oldScopeElement) {
UpdateIsElementInStyleScopeFlagOnSubtree(oldScopeElement);
}
} }
// When static documents are created, stylesheets are cloned manually. // When static documents are created, stylesheets are cloned manually.
@ -492,21 +425,14 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
} }
nsAutoString title, type, media; nsAutoString title, type, media;
bool isScoped;
bool isAlternate; bool isAlternate;
GetStyleSheetInfo(title, type, media, &isScoped, &isAlternate); GetStyleSheetInfo(title, type, media, &isAlternate);
if (!type.LowerCaseEqualsLiteral("text/css")) { if (!type.LowerCaseEqualsLiteral("text/css")) {
return NS_OK; return NS_OK;
} }
Element* scopeElement = isScoped ? thisContent->GetParentElement() : nullptr;
if (scopeElement) {
NS_ASSERTION(isInline, "non-inline style must not have scope element");
scopeElement->SetIsElementInStyleScopeFlagOnSubtree(true);
}
bool doneLoading = false; bool doneLoading = false;
nsresult rv = NS_OK; nsresult rv = NS_OK;
@ -538,7 +464,7 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
// Parse the style sheet. // Parse the style sheet.
rv = doc->CSSLoader()-> rv = doc->CSSLoader()->
LoadInlineStyle(thisContent, text, triggeringPrincipal, mLineNumber, LoadInlineStyle(thisContent, text, triggeringPrincipal, mLineNumber,
title, media, referrerPolicy, scopeElement, title, media, referrerPolicy,
aObserver, &doneLoading, &isAlternate); aObserver, &doneLoading, &isAlternate);
} else { } else {
nsAutoString integrity; nsAutoString integrity;
@ -577,60 +503,3 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
return NS_OK; return NS_OK;
} }
void
nsStyleLinkElement::UpdateStyleSheetScopedness(bool aIsNowScoped)
{
if (!mStyleSheet) {
return;
}
if (mStyleSheet->IsServo()) {
// XXXheycam ServoStyleSheets don't support <style scoped>.
NS_ERROR("stylo: ServoStyleSheets don't support <style scoped>");
return;
}
#ifdef MOZ_OLD_STYLE
CSSStyleSheet* sheet = mStyleSheet->AsGecko();
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
Element* oldScopeElement = sheet->GetScopeElement();
Element* newScopeElement = aIsNowScoped ?
thisContent->GetParentElement() :
nullptr;
if (oldScopeElement == newScopeElement) {
return;
}
nsIDocument* document = thisContent->GetOwnerDocument();
if (thisContent->IsInShadowTree()) {
ShadowRoot* containingShadow = thisContent->GetContainingShadow();
containingShadow->RemoveSheet(mStyleSheet);
sheet->SetScopeElement(newScopeElement);
containingShadow->InsertSheet(mStyleSheet, thisContent);
} else {
document->BeginUpdate(UPDATE_STYLE);
document->RemoveStyleSheet(mStyleSheet);
sheet->SetScopeElement(newScopeElement);
document->AddStyleSheet(mStyleSheet);
document->EndUpdate(UPDATE_STYLE);
}
if (oldScopeElement) {
UpdateIsElementInStyleScopeFlagOnSubtree(oldScopeElement);
}
if (newScopeElement) {
newScopeElement->SetIsElementInStyleScopeFlagOnSubtree(true);
}
#else
MOZ_CRASH("old style system disabled");
#endif
}

Просмотреть файл

@ -91,13 +91,10 @@ protected:
mozilla::dom::ShadowRoot *aOldShadowRoot, mozilla::dom::ShadowRoot *aOldShadowRoot,
bool aForceUpdate = false); bool aForceUpdate = false);
void UpdateStyleSheetScopedness(bool aIsNowScoped);
virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) = 0; virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) = 0;
virtual void GetStyleSheetInfo(nsAString& aTitle, virtual void GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType, nsAString& aType,
nsAString& aMedia, nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) = 0; bool* aIsAlternate) = 0;
virtual mozilla::CORSMode GetCORSMode() const virtual mozilla::CORSMode GetCORSMode() const

Просмотреть файл

@ -17296,7 +17296,7 @@ class GlobalGenRoots():
def fieldSizeAssert(amount, jitInfoField, message): def fieldSizeAssert(amount, jitInfoField, message):
maxFieldValue = "(uint64_t(1) << (sizeof(((JSJitInfo*)nullptr)->%s) * 8))" % jitInfoField maxFieldValue = "(uint64_t(1) << (sizeof(((JSJitInfo*)nullptr)->%s) * 8))" % jitInfoField
return CGGeneric(declare="static_assert(%s < %s, \"%s\");\n\n" return CGGeneric(define="static_assert(%s < %s, \"%s\");\n\n"
% (amount, maxFieldValue, message)) % (amount, maxFieldValue, message))
idEnum.append(fieldSizeAssert("id::_ID_Count", "protoID", idEnum.append(fieldSizeAssert("id::_ID_Count", "protoID",
@ -17308,7 +17308,8 @@ class GlobalGenRoots():
idEnum = CGWrapper(idEnum, post='\n') idEnum = CGWrapper(idEnum, post='\n')
curr = CGList([CGGeneric(define="#include <stdint.h>\n\n"), curr = CGList([CGGeneric(define="#include <stdint.h>\n\n"),
CGGeneric(declare='#include "jsfriendapi.h"\n\n'), CGGeneric(define='#include "jsfriendapi.h"\n\n'),
CGGeneric(define='#include "mozilla/dom/PrototypeList.h"\n\n'),
idEnum]) idEnum])
# Let things know the maximum length of the prototype chain. # Let things know the maximum length of the prototype chain.

Просмотреть файл

@ -95,7 +95,8 @@ interface nsIScriptError : nsIConsoleMessage
in uint32_t lineNumber, in uint32_t lineNumber,
in uint32_t columnNumber, in uint32_t columnNumber,
in uint32_t flags, in uint32_t flags,
in string category); in string category,
[optional] in bool fromPrivateWindow);
/* This should be called instead of nsIScriptError.init to /* This should be called instead of nsIScriptError.init to
* initialize with a window id. The window id should be for the * initialize with a window id. The window id should be for the

Просмотреть файл

@ -181,22 +181,6 @@ nsScriptErrorBase::SetErrorMessageName(const nsAString& aErrorMessageName) {
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsScriptErrorBase::Init(const nsAString& message,
const nsAString& sourceName,
const nsAString& sourceLine,
uint32_t lineNumber,
uint32_t columnNumber,
uint32_t flags,
const char* category)
{
return InitWithWindowID(message, sourceName, sourceLine, lineNumber,
columnNumber, flags,
category ? nsDependentCString(category)
: EmptyCString(),
0);
}
static void static void
AssignSourceNameHelper(nsString& aSourceNameDest, const nsAString& aSourceNameSrc) AssignSourceNameHelper(nsString& aSourceNameDest, const nsAString& aSourceNameSrc)
{ {
@ -227,6 +211,26 @@ AssignSourceNameHelper(nsIURI* aSourceURI, nsString& aSourceNameDest)
} }
} }
NS_IMETHODIMP
nsScriptErrorBase::Init(const nsAString& message,
const nsAString& sourceName,
const nsAString& sourceLine,
uint32_t lineNumber,
uint32_t columnNumber,
uint32_t flags,
const char* category,
bool fromPrivateWindow)
{
InitializationHelper(message, sourceLine, lineNumber, columnNumber, flags,
category ? nsDependentCString(category)
: EmptyCString(),
0 /* inner Window ID */);
AssignSourceNameHelper(mSourceName, sourceName);
mIsFromPrivateWindow = fromPrivateWindow;
return NS_OK;
}
void void
nsScriptErrorBase::InitializationHelper(const nsAString& message, nsScriptErrorBase::InitializationHelper(const nsAString& message,
const nsAString& sourceLine, const nsAString& sourceLine,

Просмотреть файл

@ -96,14 +96,6 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack)
NS_IMETHOD Init(const nsAString& message,
const nsAString& sourceName,
const nsAString& sourceLine,
uint32_t lineNumber,
uint32_t columnNumber,
uint32_t flags,
const char* category) override;
NS_IMETHOD GetStack(JS::MutableHandleValue) override; NS_IMETHOD GetStack(JS::MutableHandleValue) override;
NS_IMETHOD ToString(nsACString& aResult) override; NS_IMETHOD ToString(nsACString& aResult) override;

Просмотреть файл

@ -73,18 +73,6 @@ nsScriptErrorWithStack::~nsScriptErrorWithStack() {
mozilla::DropJSObjects(this); mozilla::DropJSObjects(this);
} }
NS_IMETHODIMP
nsScriptErrorWithStack::Init(const nsAString& message,
const nsAString& sourceName,
const nsAString& sourceLine,
uint32_t lineNumber,
uint32_t columnNumber,
uint32_t flags,
const char* category)
{
MOZ_CRASH("nsScriptErrorWithStack requires to be initialized with a document, by using InitWithWindowID");
}
NS_IMETHODIMP NS_IMETHODIMP
nsScriptErrorWithStack::GetStack(JS::MutableHandleValue aStack) { nsScriptErrorWithStack::GetStack(JS::MutableHandleValue aStack) {
aStack.setObjectOrNull(mStack); aStack.setObjectOrNull(mStack);

Просмотреть файл

@ -213,9 +213,9 @@ public:
int8_t CachedWritableByte(); int8_t CachedWritableByte();
void SetCachedWritableByte(int8_t); void SetCachedWritableByte(int8_t);
int8_t SideEffectFreeByte(); int8_t SideEffectFreeByte();
int8_t SetSideEffectFreeByte(int8_t); void SetSideEffectFreeByte(int8_t);
int8_t DomDependentByte(); int8_t DomDependentByte();
int8_t SetDomDependentByte(int8_t); void SetDomDependentByte(int8_t);
int8_t ConstantByte(); int8_t ConstantByte();
int8_t DeviceStateDependentByte(); int8_t DeviceStateDependentByte();
int8_t ReturnByteSideEffectFree(); int8_t ReturnByteSideEffectFree();
@ -828,7 +828,7 @@ public:
// Deprecated methods and attributes // Deprecated methods and attributes
int8_t DeprecatedAttribute(); int8_t DeprecatedAttribute();
int8_t SetDeprecatedAttribute(int8_t); void SetDeprecatedAttribute(int8_t);
int8_t DeprecatedMethod(); int8_t DeprecatedMethod();
int8_t DeprecatedMethodWithContext(JSContext*, const JS::Value&); int8_t DeprecatedMethodWithContext(JSContext*, const JS::Value&);
@ -841,9 +841,9 @@ public:
// Deprecated static methods and attributes // Deprecated static methods and attributes
static int8_t StaticDeprecatedAttribute(const GlobalObject&); static int8_t StaticDeprecatedAttribute(const GlobalObject&);
static int8_t SetStaticDeprecatedAttribute(const GlobalObject&, int8_t); static void SetStaticDeprecatedAttribute(const GlobalObject&, int8_t);
static int8_t StaticDeprecatedMethod(const GlobalObject&); static void StaticDeprecatedMethod(const GlobalObject&);
static int8_t StaticDeprecatedMethodWithContext(const GlobalObject&, const JS::Value&); static void StaticDeprecatedMethodWithContext(const GlobalObject&, const JS::Value&);
// Overload resolution tests // Overload resolution tests
bool Overload1(TestInterface&); bool Overload1(TestInterface&);

2
dom/cache/ReadStream.cpp поставляемый
Просмотреть файл

@ -611,7 +611,7 @@ ReadStream::Create(const CacheReadStream& aReadStream)
nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aReadStream.stream()); nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aReadStream.stream());
// Currently we expect all cache read streams to be blocking file streams. // Currently we expect all cache read streams to be blocking file streams.
#if !defined(RELEASE_OR_BETA) #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
if (stream) { if (stream) {
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(stream); nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(stream);
MOZ_DIAGNOSTIC_ASSERT(!asyncStream); MOZ_DIAGNOSTIC_ASSERT(!asyncStream);

Просмотреть файл

@ -5283,6 +5283,9 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement(); HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement();
int32_t displayWidth = video->VideoWidth(); int32_t displayWidth = video->VideoWidth();
int32_t displayHeight = video->VideoHeight(); int32_t displayHeight = video->VideoHeight();
if (displayWidth == 0 || displayHeight == 0) {
return;
}
aSw *= (double)imgSize.width / (double)displayWidth; aSw *= (double)imgSize.width / (double)displayWidth;
aSh *= (double)imgSize.height / (double)displayHeight; aSh *= (double)imgSize.height / (double)displayHeight;
} }

Просмотреть файл

@ -157,7 +157,7 @@ fuzzy-if(skiaContent,1,150) == clip-multiple-move-2.html clip-multiple-move-2-re
== stroketext-shadow.html stroketext-shadow-ref.html == stroketext-shadow.html stroketext-shadow-ref.html
# focus rings # focus rings
pref(canvas.focusring.enabled,true) skip-if(cocoaWidget) skip-if(winWidget) needs-focus == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html pref(canvas.focusring.enabled,true) skip-if(cocoaWidget) skip-if(winWidget) fuzzy-if(skiaContent&&!cocoaWidget&&!winWidget,1,2) needs-focus == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html
pref(canvas.customfocusring.enabled,true) skip-if(Android||cocoaWidget||winWidget) fuzzy-if(gtkWidget,64,410) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html pref(canvas.customfocusring.enabled,true) skip-if(Android||cocoaWidget||winWidget) fuzzy-if(gtkWidget,64,410) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html
# Check that captureStream() displays in a local video element # Check that captureStream() displays in a local video element

Просмотреть файл

@ -26,28 +26,6 @@ ClipboardEvent::ClipboardEvent(EventTarget* aOwner,
} }
} }
NS_INTERFACE_MAP_BEGIN(ClipboardEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMClipboardEvent)
NS_INTERFACE_MAP_END_INHERITING(Event)
NS_IMPL_ADDREF_INHERITED(ClipboardEvent, Event)
NS_IMPL_RELEASE_INHERITED(ClipboardEvent, Event)
nsresult
ClipboardEvent::InitClipboardEvent(const nsAString& aType,
bool aCanBubble,
bool aCancelable,
nsIDOMDataTransfer* aClipboardData)
{
nsCOMPtr<DataTransfer> clipboardData = do_QueryInterface(aClipboardData);
// Null clipboardData is OK
ErrorResult rv;
InitClipboardEvent(aType, aCanBubble, aCancelable, clipboardData);
return rv.StealNSResult();
}
void void
ClipboardEvent::InitClipboardEvent(const nsAString& aType, bool aCanBubble, ClipboardEvent::InitClipboardEvent(const nsAString& aType, bool aCanBubble,
bool aCancelable, bool aCancelable,
@ -90,13 +68,6 @@ ClipboardEvent::Constructor(const GlobalObject& aGlobal,
return e.forget(); return e.forget();
} }
NS_IMETHODIMP
ClipboardEvent::GetClipboardData(nsIDOMDataTransfer** aClipboardData)
{
NS_IF_ADDREF(*aClipboardData = GetClipboardData());
return NS_OK;
}
DataTransfer* DataTransfer*
ClipboardEvent::GetClipboardData() ClipboardEvent::GetClipboardData()
{ {

Просмотреть файл

@ -10,26 +10,19 @@
#include "mozilla/EventForwards.h" #include "mozilla/EventForwards.h"
#include "mozilla/dom/ClipboardEventBinding.h" #include "mozilla/dom/ClipboardEventBinding.h"
#include "mozilla/dom/Event.h" #include "mozilla/dom/Event.h"
#include "nsIDOMClipboardEvent.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class DataTransfer; class DataTransfer;
class ClipboardEvent : public Event, class ClipboardEvent : public Event
public nsIDOMClipboardEvent
{ {
public: public:
ClipboardEvent(EventTarget* aOwner, ClipboardEvent(EventTarget* aOwner,
nsPresContext* aPresContext, nsPresContext* aPresContext,
InternalClipboardEvent* aEvent); InternalClipboardEvent* aEvent);
NS_DECL_ISUPPORTS_INHERITED NS_INLINE_DECL_REFCOUNTING_INHERITED(ClipboardEvent, Event)
NS_DECL_NSIDOMCLIPBOARDEVENT
// Forward to base class
NS_FORWARD_TO_EVENT
virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
{ {

Просмотреть файл

@ -1750,7 +1750,8 @@ HTMLFormElement::GetActionURL(nsIURI** aActionURL,
0, // aLineNumber 0, // aLineNumber
0, // aColumnNumber 0, // aColumnNumber
nsIScriptError::warningFlag, "CSP", nsIScriptError::warningFlag, "CSP",
document->InnerWindowID()); document->InnerWindowID(),
!!document->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId);
} }
// //

Просмотреть файл

@ -433,13 +433,11 @@ void
HTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle, HTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType, nsAString& aType,
nsAString& aMedia, nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) bool* aIsAlternate)
{ {
aTitle.Truncate(); aTitle.Truncate();
aType.Truncate(); aType.Truncate();
aMedia.Truncate(); aMedia.Truncate();
*aIsScoped = false;
*aIsAlternate = false; *aIsAlternate = false;
nsAutoString rel; nsAutoString rel;

Просмотреть файл

@ -207,12 +207,13 @@ protected:
virtual ~HTMLLinkElement(); virtual ~HTMLLinkElement();
// nsStyleLinkElement // nsStyleLinkElement
virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) override; already_AddRefed<nsIURI>
virtual void GetStyleSheetInfo(nsAString& aTitle, GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) final;
nsAString& aType,
nsAString& aMedia, void GetStyleSheetInfo(nsAString& aTitle,
bool* aIsScoped, nsAString& aType,
bool* aIsAlternate) override; nsAString& aMedia,
bool* aIsAlternate) final;
protected: protected:
RefPtr<nsDOMTokenList> mRelList; RefPtr<nsDOMTokenList> mRelList;
}; };

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше