зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
e0cadccc1d
1
.hgtags
1
.hgtags
|
@ -161,3 +161,4 @@ c44fbdd5173548c9035256dda8fd3512f67118a8 FIREFOX_NIGHTLY_64_END
|
||||||
f4c23517cec8626038a915bfe3bc7c0e1f6af55d FIREFOX_BETA_67_BASE
|
f4c23517cec8626038a915bfe3bc7c0e1f6af55d FIREFOX_BETA_67_BASE
|
||||||
9421b477d67cfc4c9e03350cd554a9e6acc7f435 FIREFOX_NIGHTLY_67_END
|
9421b477d67cfc4c9e03350cd554a9e6acc7f435 FIREFOX_NIGHTLY_67_END
|
||||||
390914f7108f4f6065834d8983af9ac855cbf2df FIREFOX_BETA_68_BASE
|
390914f7108f4f6065834d8983af9ac855cbf2df FIREFOX_BETA_68_BASE
|
||||||
|
97dae745c1b3ef2292127ba1c4e90b1345c8f576 FIREFOX_NIGHTLY_68_END
|
||||||
|
|
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
||||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||||
# don't change CLOBBER for WebIDL changes any more.
|
# don't change CLOBBER for WebIDL changes any more.
|
||||||
|
|
||||||
Bug 1533481 - Update to ICU 64 requires clobber
|
Merge day clobber
|
|
@ -753,11 +753,6 @@ class ContentSessionStore {
|
||||||
this.restoreHistory(data);
|
this.restoreHistory(data);
|
||||||
break;
|
break;
|
||||||
case "SessionStore:restoreTabContent":
|
case "SessionStore:restoreTabContent":
|
||||||
if (data.isRemotenessUpdate) {
|
|
||||||
let histogram = Services.telemetry.getKeyedHistogramById("FX_TAB_REMOTE_NAVIGATION_DELAY_MS");
|
|
||||||
histogram.add("SessionStore:restoreTabContent",
|
|
||||||
Services.telemetry.msSystemNow() - data.requestTime);
|
|
||||||
}
|
|
||||||
this.restoreTabContent(data);
|
this.restoreTabContent(data);
|
||||||
break;
|
break;
|
||||||
case "SessionStore:resetRestore":
|
case "SessionStore:resetRestore":
|
||||||
|
|
|
@ -4310,8 +4310,7 @@ var SessionStoreInternal = {
|
||||||
browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent",
|
browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent",
|
||||||
{loadArguments, isRemotenessUpdate,
|
{loadArguments, isRemotenessUpdate,
|
||||||
reason: aOptions.restoreContentReason ||
|
reason: aOptions.restoreContentReason ||
|
||||||
RESTORE_TAB_CONTENT_REASON.SET_STATE,
|
RESTORE_TAB_CONTENT_REASON.SET_STATE});
|
||||||
requestTime: Services.telemetry.msSystemNow()});
|
|
||||||
|
|
||||||
// Focus the tab's content area.
|
// Focus the tab's content area.
|
||||||
if (aTab.selected && !window.isBlankPageURL(uri)) {
|
if (aTab.selected && !window.isBlankPageURL(uri)) {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
68.0a1
|
69.0a1
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
68.0a1
|
69.0a1
|
||||||
|
|
|
@ -10,4 +10,4 @@
|
||||||
# hardcoded milestones in the tree from these two files.
|
# hardcoded milestones in the tree from these two files.
|
||||||
#--------------------------------------------------------
|
#--------------------------------------------------------
|
||||||
|
|
||||||
68.0a1
|
69.0a1
|
||||||
|
|
|
@ -55,6 +55,7 @@ const THREE_PANE_ENABLED_PREF = "devtools.inspector.three-pane-enabled";
|
||||||
const THREE_PANE_ENABLED_SCALAR = "devtools.inspector.three_pane_enabled";
|
const THREE_PANE_ENABLED_SCALAR = "devtools.inspector.three_pane_enabled";
|
||||||
const THREE_PANE_CHROME_ENABLED_PREF = "devtools.inspector.chrome.three-pane-enabled";
|
const THREE_PANE_CHROME_ENABLED_PREF = "devtools.inspector.chrome.three-pane-enabled";
|
||||||
const TELEMETRY_EYEDROPPER_OPENED = "devtools.toolbar.eyedropper.opened";
|
const TELEMETRY_EYEDROPPER_OPENED = "devtools.toolbar.eyedropper.opened";
|
||||||
|
const TELEMETRY_SCALAR_NODE_SELECTION_COUNT = "devtools.inspector.node_selection_count";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an open instance of the Inspector for a tab.
|
* Represents an open instance of the Inspector for a tab.
|
||||||
|
@ -1299,6 +1300,7 @@ Inspector.prototype = {
|
||||||
executeSoon(() => {
|
executeSoon(() => {
|
||||||
try {
|
try {
|
||||||
selfUpdate(this.selection.nodeFront);
|
selfUpdate(this.selection.nodeFront);
|
||||||
|
this.telemetry.scalarAdd(TELEMETRY_SCALAR_NODE_SELECTION_COUNT, 1);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.error(ex);
|
console.error(ex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,6 @@ const ChromeUtils = require("ChromeUtils");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
|
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
|
||||||
const { E10SUtils } = require("resource://gre/modules/E10SUtils.jsm");
|
const { E10SUtils } = require("resource://gre/modules/E10SUtils.jsm");
|
||||||
const Telemetry = require("devtools/client/shared/telemetry");
|
|
||||||
|
|
||||||
const telemetry = new Telemetry();
|
|
||||||
|
|
||||||
function readInputStreamToString(stream) {
|
function readInputStreamToString(stream) {
|
||||||
return NetUtil.readInputStreamToString(stream, stream.available());
|
return NetUtil.readInputStreamToString(stream, stream.available());
|
||||||
|
@ -85,7 +82,6 @@ BrowserElementWebNavigation.prototype = {
|
||||||
triggeringPrincipal: E10SUtils.serializePrincipal(
|
triggeringPrincipal: E10SUtils.serializePrincipal(
|
||||||
triggeringPrincipal ||
|
triggeringPrincipal ||
|
||||||
Services.scriptSecurityManager.createNullPrincipal({})),
|
Services.scriptSecurityManager.createNullPrincipal({})),
|
||||||
requestTime: telemetry.msSystemNow(),
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "Animation.h"
|
#include "Animation.h"
|
||||||
|
|
||||||
#include "AnimationUtils.h"
|
#include "AnimationUtils.h"
|
||||||
|
#include "mozAutoDocUpdate.h"
|
||||||
#include "mozilla/dom/AnimationBinding.h"
|
#include "mozilla/dom/AnimationBinding.h"
|
||||||
#include "mozilla/dom/AnimationPlaybackEvent.h"
|
#include "mozilla/dom/AnimationPlaybackEvent.h"
|
||||||
#include "mozilla/dom/Document.h"
|
#include "mozilla/dom/Document.h"
|
||||||
|
@ -14,10 +16,13 @@
|
||||||
#include "mozilla/AnimationEventDispatcher.h"
|
#include "mozilla/AnimationEventDispatcher.h"
|
||||||
#include "mozilla/AnimationTarget.h"
|
#include "mozilla/AnimationTarget.h"
|
||||||
#include "mozilla/AutoRestore.h"
|
#include "mozilla/AutoRestore.h"
|
||||||
|
#include "mozilla/DeclarationBlock.h"
|
||||||
#include "mozilla/Maybe.h" // For Maybe
|
#include "mozilla/Maybe.h" // For Maybe
|
||||||
#include "mozilla/TypeTraits.h" // For std::forward<>
|
#include "mozilla/TypeTraits.h" // For std::forward<>
|
||||||
#include "nsAnimationManager.h" // For CSSAnimation
|
#include "nsAnimationManager.h" // For CSSAnimation
|
||||||
|
#include "nsComputedDOMStyle.h"
|
||||||
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
|
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
|
||||||
|
#include "nsDOMCSSAttrDeclaration.h" // For nsDOMCSSAttributeDeclaration
|
||||||
#include "nsThreadUtils.h" // For nsRunnableMethod and nsRevocableEventPtr
|
#include "nsThreadUtils.h" // For nsRunnableMethod and nsRevocableEventPtr
|
||||||
#include "nsTransitionManager.h" // For CSSTransition
|
#include "nsTransitionManager.h" // For CSSTransition
|
||||||
#include "PendingAnimationTracker.h" // For PendingAnimationTracker
|
#include "PendingAnimationTracker.h" // For PendingAnimationTracker
|
||||||
|
@ -168,6 +173,8 @@ void Animation::SetEffectNoUpdate(AnimationEffect* aEffect) {
|
||||||
ReschedulePendingTasks();
|
ReschedulePendingTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeScheduleReplacementCheck();
|
||||||
|
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,6 +601,124 @@ void Animation::Reverse(ErrorResult& aRv) {
|
||||||
// it here.
|
// it here.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::Persist() {
|
||||||
|
if (mReplaceState == AnimationReplaceState::Persisted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wasRemoved = mReplaceState == AnimationReplaceState::Removed;
|
||||||
|
|
||||||
|
mReplaceState = AnimationReplaceState::Persisted;
|
||||||
|
|
||||||
|
// If the animation is not (yet) removed, there should be no side effects of
|
||||||
|
// persisting it.
|
||||||
|
if (wasRemoved) {
|
||||||
|
UpdateEffect(PostRestyleMode::IfNeeded);
|
||||||
|
PostUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/web-animations/#dom-animation-commitstyles
|
||||||
|
void Animation::CommitStyles(ErrorResult& aRv) {
|
||||||
|
if (!mEffect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take an owning reference to the keyframe effect. This will ensure that
|
||||||
|
// this Animation and the target element remain alive after flushing style.
|
||||||
|
RefPtr<KeyframeEffect> keyframeEffect = mEffect->AsKeyframeEffect();
|
||||||
|
if (!keyframeEffect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe<NonOwningAnimationTarget> target = keyframeEffect->GetTarget();
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->mPseudoType != PseudoStyleType::NotPseudo) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check it is an element with a style attribute
|
||||||
|
nsCOMPtr<nsStyledElement> styledElement = do_QueryInterface(target->mElement);
|
||||||
|
if (!styledElement) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush style before checking if the target element is rendered since the
|
||||||
|
// result could depend on pending style changes.
|
||||||
|
if (Document* doc = target->mElement->GetComposedDoc()) {
|
||||||
|
doc->FlushPendingNotifications(FlushType::Style);
|
||||||
|
}
|
||||||
|
if (!target->mElement->IsRendered()) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsPresContext* presContext =
|
||||||
|
nsContentUtils::GetContextForContent(target->mElement);
|
||||||
|
if (!presContext) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the computed animation values
|
||||||
|
UniquePtr<RawServoAnimationValueMap> animationValues =
|
||||||
|
Servo_AnimationValueMap_Create().Consume();
|
||||||
|
if (!presContext->EffectCompositor()->ComposeServoAnimationRuleForEffect(
|
||||||
|
*keyframeEffect, CascadeLevel(), animationValues.get())) {
|
||||||
|
NS_WARNING("Failed to compose animation style to commit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calling SetCSSDeclaration will trigger attribute setting code.
|
||||||
|
// Start the update now so that the old rule doesn't get used
|
||||||
|
// between when we mutate the declaration and when we set the new
|
||||||
|
// rule.
|
||||||
|
mozAutoDocUpdate autoUpdate(target->mElement->OwnerDoc(), true);
|
||||||
|
|
||||||
|
// Get the inline style to append to
|
||||||
|
RefPtr<DeclarationBlock> declarationBlock;
|
||||||
|
if (auto* existing = target->mElement->GetInlineStyleDeclaration()) {
|
||||||
|
declarationBlock = existing->EnsureMutable();
|
||||||
|
} else {
|
||||||
|
declarationBlock = new DeclarationBlock();
|
||||||
|
declarationBlock->SetDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the callback
|
||||||
|
MutationClosureData closureData;
|
||||||
|
closureData.mClosure = nsDOMCSSAttributeDeclaration::MutationClosureFunction;
|
||||||
|
closureData.mElement = target->mElement;
|
||||||
|
DeclarationBlockMutationClosure beforeChangeClosure = {
|
||||||
|
nsDOMCSSAttributeDeclaration::MutationClosureFunction,
|
||||||
|
&closureData,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the animated styles
|
||||||
|
bool changed = false;
|
||||||
|
nsCSSPropertyIDSet properties = keyframeEffect->GetPropertySet();
|
||||||
|
for (nsCSSPropertyID property : properties) {
|
||||||
|
RefPtr<RawServoAnimationValue> computedValue =
|
||||||
|
Servo_AnimationValueMap_GetValue(animationValues.get(), property)
|
||||||
|
.Consume();
|
||||||
|
if (computedValue) {
|
||||||
|
changed |= Servo_DeclarationBlock_SetPropertyToAnimationValue(
|
||||||
|
declarationBlock->Raw(), computedValue, beforeChangeClosure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update inline style declaration
|
||||||
|
target->mElement->SetInlineStyleDeclaration(*declarationBlock, closureData);
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// JS wrappers for Animation interface:
|
// JS wrappers for Animation interface:
|
||||||
|
@ -650,7 +775,14 @@ void Animation::Tick() {
|
||||||
FinishPendingAt(mTimeline->GetCurrentTimeAsDuration().Value());
|
FinishPendingAt(mTimeline->GetCurrentTimeAsDuration().Value());
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Sync);
|
||||||
|
|
||||||
|
// Check for changes to whether or not this animation is replaceable.
|
||||||
|
bool isReplaceable = IsReplaceable();
|
||||||
|
if (isReplaceable && !mWasReplaceableAtLastTick) {
|
||||||
|
ScheduleReplacementCheck();
|
||||||
|
}
|
||||||
|
mWasReplaceableAtLastTick = isReplaceable;
|
||||||
|
|
||||||
if (!mEffect) {
|
if (!mEffect) {
|
||||||
return;
|
return;
|
||||||
|
@ -837,7 +969,8 @@ bool Animation::ShouldBeSynchronizedWithMainThread(
|
||||||
|
|
||||||
void Animation::UpdateRelevance() {
|
void Animation::UpdateRelevance() {
|
||||||
bool wasRelevant = mIsRelevant;
|
bool wasRelevant = mIsRelevant;
|
||||||
mIsRelevant = HasCurrentEffect() || IsInEffect();
|
mIsRelevant = mReplaceState != AnimationReplaceState::Removed &&
|
||||||
|
(HasCurrentEffect() || IsInEffect());
|
||||||
|
|
||||||
// Notify animation observers.
|
// Notify animation observers.
|
||||||
if (wasRelevant && !mIsRelevant) {
|
if (wasRelevant && !mIsRelevant) {
|
||||||
|
@ -847,6 +980,118 @@ void Animation::UpdateRelevance() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool IsMarkupAnimation(T* aAnimation) {
|
||||||
|
return aAnimation && aAnimation->IsTiedToMarkup();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/web-animations/#replaceable-animation
|
||||||
|
bool Animation::IsReplaceable() const {
|
||||||
|
// We never replace CSS animations or CSS transitions since they are managed
|
||||||
|
// by CSS.
|
||||||
|
if (IsMarkupAnimation(AsCSSAnimation()) ||
|
||||||
|
IsMarkupAnimation(AsCSSTransition())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only finished animations can be replaced.
|
||||||
|
if (PlayState() != AnimationPlayState::Finished) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Already removed animations cannot be replaced.
|
||||||
|
if (ReplaceState() == AnimationReplaceState::Removed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can only replace an animation if we know that, uninterfered, it would
|
||||||
|
// never start playing again. That excludes any animations on timelines that
|
||||||
|
// aren't monotonically increasing.
|
||||||
|
//
|
||||||
|
// If we don't have any timeline at all, then we can't be in the finished
|
||||||
|
// state (since we need both a resolved start time and current time for that)
|
||||||
|
// and will have already returned false above.
|
||||||
|
//
|
||||||
|
// (However, if it ever does become possible to be finished without a timeline
|
||||||
|
// then we will want to return false here since it probably suggests an
|
||||||
|
// animation being driven directly by script, in which case we can't assume
|
||||||
|
// anything about how they will behave.)
|
||||||
|
if (!GetTimeline() || !GetTimeline()->TracksWallclockTime()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the animation doesn't have an effect then we can't determine if it is
|
||||||
|
// filling or not so just leave it alone.
|
||||||
|
if (!GetEffect()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// At the time of writing we only know about KeyframeEffects. If we introduce
|
||||||
|
// other types of effects we will need to decide if they are replaceable or
|
||||||
|
// not.
|
||||||
|
MOZ_ASSERT(GetEffect()->AsKeyframeEffect(),
|
||||||
|
"Effect should be a keyframe effect");
|
||||||
|
|
||||||
|
// We only replace animations that are filling.
|
||||||
|
if (GetEffect()->GetComputedTiming().mProgress.IsNull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should only replace animations with a target element (since otherwise
|
||||||
|
// what other effects would we consider when determining if they are covered
|
||||||
|
// or not?).
|
||||||
|
if (!GetEffect()->AsKeyframeEffect()->GetTarget()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Animation::IsRemovable() const {
|
||||||
|
return ReplaceState() == AnimationReplaceState::Active && IsReplaceable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::ScheduleReplacementCheck() {
|
||||||
|
MOZ_ASSERT(
|
||||||
|
IsReplaceable(),
|
||||||
|
"Should only schedule a replacement check for a replaceable animation");
|
||||||
|
|
||||||
|
// If IsReplaceable() is true, the following should also hold
|
||||||
|
MOZ_ASSERT(GetEffect());
|
||||||
|
MOZ_ASSERT(GetEffect()->AsKeyframeEffect());
|
||||||
|
MOZ_ASSERT(GetEffect()->AsKeyframeEffect()->GetTarget());
|
||||||
|
|
||||||
|
Maybe<NonOwningAnimationTarget> target =
|
||||||
|
GetEffect()->AsKeyframeEffect()->GetTarget();
|
||||||
|
|
||||||
|
nsPresContext* presContext =
|
||||||
|
nsContentUtils::GetContextForContent(target->mElement);
|
||||||
|
if (presContext) {
|
||||||
|
presContext->EffectCompositor()->NoteElementForReducing(*target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::MaybeScheduleReplacementCheck() {
|
||||||
|
if (!IsReplaceable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScheduleReplacementCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::Remove() {
|
||||||
|
MOZ_ASSERT(IsRemovable(),
|
||||||
|
"Should not be trying to remove an effect that is not removable");
|
||||||
|
|
||||||
|
mReplaceState = AnimationReplaceState::Removed;
|
||||||
|
|
||||||
|
UpdateEffect(PostRestyleMode::IfNeeded);
|
||||||
|
PostUpdate();
|
||||||
|
|
||||||
|
QueuePlaybackEvent(NS_LITERAL_STRING("remove"),
|
||||||
|
GetTimelineCurrentTimeAsTimeStamp());
|
||||||
|
}
|
||||||
|
|
||||||
bool Animation::HasLowerCompositeOrderThan(const Animation& aOther) const {
|
bool Animation::HasLowerCompositeOrderThan(const Animation& aOther) const {
|
||||||
// 0. Object-equality case
|
// 0. Object-equality case
|
||||||
if (&aOther == this) {
|
if (&aOther == this) {
|
||||||
|
@ -989,11 +1234,27 @@ void Animation::ComposeStyle(RawServoAnimationValueMap& aComposeResult,
|
||||||
|
|
||||||
void Animation::NotifyEffectTimingUpdated() {
|
void Animation::NotifyEffectTimingUpdated() {
|
||||||
MOZ_ASSERT(mEffect,
|
MOZ_ASSERT(mEffect,
|
||||||
"We should only update timing effect when we have a target "
|
"We should only update effect timing when we have a target "
|
||||||
"effect");
|
"effect");
|
||||||
UpdateTiming(Animation::SeekFlag::NoSeek, Animation::SyncNotifyFlag::Async);
|
UpdateTiming(Animation::SeekFlag::NoSeek, Animation::SyncNotifyFlag::Async);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::NotifyEffectPropertiesUpdated() {
|
||||||
|
MOZ_ASSERT(mEffect,
|
||||||
|
"We should only update effect properties when we have a target "
|
||||||
|
"effect");
|
||||||
|
|
||||||
|
MaybeScheduleReplacementCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::NotifyEffectTargetUpdated() {
|
||||||
|
MOZ_ASSERT(mEffect,
|
||||||
|
"We should only update the effect target when we have a target "
|
||||||
|
"effect");
|
||||||
|
|
||||||
|
MaybeScheduleReplacementCheck();
|
||||||
|
}
|
||||||
|
|
||||||
void Animation::NotifyGeometricAnimationsStartingThisFrame() {
|
void Animation::NotifyGeometricAnimationsStartingThisFrame() {
|
||||||
if (!IsNewlyStarted() || !mEffect) {
|
if (!IsNewlyStarted() || !mEffect) {
|
||||||
return;
|
return;
|
||||||
|
@ -1179,7 +1440,7 @@ void Animation::ResumeAt(const TimeDuration& aReadyTime) {
|
||||||
|
|
||||||
mPendingState = PendingState::NotPending;
|
mPendingState = PendingState::NotPending;
|
||||||
|
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Sync);
|
||||||
|
|
||||||
// If we had a pending playback rate, we will have now applied it so we need
|
// If we had a pending playback rate, we will have now applied it so we need
|
||||||
// to notify observers.
|
// to notify observers.
|
||||||
|
@ -1503,7 +1764,7 @@ void Animation::QueuePlaybackEvent(const nsAString& aName,
|
||||||
|
|
||||||
AnimationPlaybackEventInit init;
|
AnimationPlaybackEventInit init;
|
||||||
|
|
||||||
if (aName.EqualsLiteral("finish")) {
|
if (aName.EqualsLiteral("finish") || aName.EqualsLiteral("remove")) {
|
||||||
init.mCurrentTime = GetCurrentTimeAsDouble();
|
init.mCurrentTime = GetCurrentTimeAsDouble();
|
||||||
}
|
}
|
||||||
if (mTimeline) {
|
if (mTimeline) {
|
||||||
|
|
|
@ -51,15 +51,7 @@ class Animation : public DOMEventTargetHelper,
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Animation(nsIGlobalObject* aGlobal)
|
explicit Animation(nsIGlobalObject* aGlobal)
|
||||||
: DOMEventTargetHelper(aGlobal),
|
: DOMEventTargetHelper(aGlobal), mAnimationIndex(sNextAnimationIndex++) {}
|
||||||
mPlaybackRate(1.0),
|
|
||||||
mAnimationIndex(sNextAnimationIndex++),
|
|
||||||
mCachedChildIndex(-1),
|
|
||||||
mPendingState(PendingState::NotPending),
|
|
||||||
mFinishedAtLastComposeStyle(false),
|
|
||||||
mIsRelevant(false),
|
|
||||||
mFinishedIsResolved(false),
|
|
||||||
mSyncWithGeometricAnimations(false) {}
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Animation, DOMEventTargetHelper)
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Animation, DOMEventTargetHelper)
|
||||||
|
@ -120,12 +112,14 @@ class Animation : public DOMEventTargetHelper,
|
||||||
|
|
||||||
bool Pending() const { return mPendingState != PendingState::NotPending; }
|
bool Pending() const { return mPendingState != PendingState::NotPending; }
|
||||||
virtual bool PendingFromJS() const { return Pending(); }
|
virtual bool PendingFromJS() const { return Pending(); }
|
||||||
|
AnimationReplaceState ReplaceState() const { return mReplaceState; }
|
||||||
|
|
||||||
virtual Promise* GetReady(ErrorResult& aRv);
|
virtual Promise* GetReady(ErrorResult& aRv);
|
||||||
Promise* GetFinished(ErrorResult& aRv);
|
Promise* GetFinished(ErrorResult& aRv);
|
||||||
|
|
||||||
IMPL_EVENT_HANDLER(finish);
|
IMPL_EVENT_HANDLER(finish);
|
||||||
IMPL_EVENT_HANDLER(cancel);
|
IMPL_EVENT_HANDLER(cancel);
|
||||||
|
IMPL_EVENT_HANDLER(remove);
|
||||||
|
|
||||||
void Cancel(PostRestyleMode aPostRestyle = PostRestyleMode::IfNeeded);
|
void Cancel(PostRestyleMode aPostRestyle = PostRestyleMode::IfNeeded);
|
||||||
|
|
||||||
|
@ -147,6 +141,9 @@ class Animation : public DOMEventTargetHelper,
|
||||||
void UpdatePlaybackRate(double aPlaybackRate);
|
void UpdatePlaybackRate(double aPlaybackRate);
|
||||||
void Reverse(ErrorResult& aRv);
|
void Reverse(ErrorResult& aRv);
|
||||||
|
|
||||||
|
void Persist();
|
||||||
|
void CommitStyles(ErrorResult& aRv);
|
||||||
|
|
||||||
bool IsRunningOnCompositor() const;
|
bool IsRunningOnCompositor() const;
|
||||||
|
|
||||||
virtual void Tick();
|
virtual void Tick();
|
||||||
|
@ -329,6 +326,25 @@ class Animation : public DOMEventTargetHelper,
|
||||||
bool IsRelevant() const { return mIsRelevant; }
|
bool IsRelevant() const { return mIsRelevant; }
|
||||||
void UpdateRelevance();
|
void UpdateRelevance();
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/web-animations-1/#replaceable-animation
|
||||||
|
bool IsReplaceable() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this Animation satisfies the requirements for being
|
||||||
|
* removed when it is replaced.
|
||||||
|
*
|
||||||
|
* Returning true does not imply this animation _should_ be removed.
|
||||||
|
* Determining that depends on the other effects in the same EffectSet to
|
||||||
|
* which this animation's effect, if any, contributes.
|
||||||
|
*/
|
||||||
|
bool IsRemovable() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make this animation's target effect no-longer part of the effect stack
|
||||||
|
* while preserving its timing information.
|
||||||
|
*/
|
||||||
|
void Remove();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this Animation has a lower composite order than aOther.
|
* Returns true if this Animation has a lower composite order than aOther.
|
||||||
*/
|
*/
|
||||||
|
@ -366,6 +382,8 @@ class Animation : public DOMEventTargetHelper,
|
||||||
const nsCSSPropertyIDSet& aPropertiesToSkip);
|
const nsCSSPropertyIDSet& aPropertiesToSkip);
|
||||||
|
|
||||||
void NotifyEffectTimingUpdated();
|
void NotifyEffectTimingUpdated();
|
||||||
|
void NotifyEffectPropertiesUpdated();
|
||||||
|
void NotifyEffectTargetUpdated();
|
||||||
void NotifyGeometricAnimationsStartingThisFrame();
|
void NotifyGeometricAnimationsStartingThisFrame();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -481,6 +499,9 @@ class Animation : public DOMEventTargetHelper,
|
||||||
return GetCurrentTimeForHoldTime(Nullable<TimeDuration>());
|
return GetCurrentTimeForHoldTime(Nullable<TimeDuration>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScheduleReplacementCheck();
|
||||||
|
void MaybeScheduleReplacementCheck();
|
||||||
|
|
||||||
// Earlier side of the elapsed time range reported in CSS Animations and CSS
|
// Earlier side of the elapsed time range reported in CSS Animations and CSS
|
||||||
// Transitions events.
|
// Transitions events.
|
||||||
//
|
//
|
||||||
|
@ -527,7 +548,7 @@ class Animation : public DOMEventTargetHelper,
|
||||||
Nullable<TimeDuration> mHoldTime; // Animation timescale
|
Nullable<TimeDuration> mHoldTime; // Animation timescale
|
||||||
Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
|
Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
|
||||||
Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
|
Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
|
||||||
double mPlaybackRate;
|
double mPlaybackRate = 1.0;
|
||||||
Maybe<double> mPendingPlaybackRate;
|
Maybe<double> mPendingPlaybackRate;
|
||||||
|
|
||||||
// A Promise that is replaced on each call to Play()
|
// A Promise that is replaced on each call to Play()
|
||||||
|
@ -554,7 +575,7 @@ class Animation : public DOMEventTargetHelper,
|
||||||
|
|
||||||
// While ordering Animation objects for event dispatch, the index of the
|
// While ordering Animation objects for event dispatch, the index of the
|
||||||
// target node in its parent may be cached in mCachedChildIndex.
|
// target node in its parent may be cached in mCachedChildIndex.
|
||||||
int32_t mCachedChildIndex;
|
int32_t mCachedChildIndex = -1;
|
||||||
|
|
||||||
// Indicates if the animation is in the pending state (and what state it is
|
// Indicates if the animation is in the pending state (and what state it is
|
||||||
// waiting to enter when it finished pending). We use this rather than
|
// waiting to enter when it finished pending). We use this rather than
|
||||||
|
@ -563,23 +584,28 @@ class Animation : public DOMEventTargetHelper,
|
||||||
// from the PendingAnimationTracker while it is waiting for the next tick
|
// from the PendingAnimationTracker while it is waiting for the next tick
|
||||||
// (see TriggerOnNextTick for details).
|
// (see TriggerOnNextTick for details).
|
||||||
enum class PendingState : uint8_t { NotPending, PlayPending, PausePending };
|
enum class PendingState : uint8_t { NotPending, PlayPending, PausePending };
|
||||||
PendingState mPendingState;
|
PendingState mPendingState = PendingState::NotPending;
|
||||||
|
|
||||||
|
// Handling of this animation's target effect when filling while finished.
|
||||||
|
AnimationReplaceState mReplaceState = AnimationReplaceState::Active;
|
||||||
|
|
||||||
|
bool mFinishedAtLastComposeStyle = false;
|
||||||
|
bool mWasReplaceableAtLastTick = false;
|
||||||
|
|
||||||
bool mFinishedAtLastComposeStyle;
|
|
||||||
// Indicates that the animation should be exposed in an element's
|
// Indicates that the animation should be exposed in an element's
|
||||||
// getAnimations() list.
|
// getAnimations() list.
|
||||||
bool mIsRelevant;
|
bool mIsRelevant = false;
|
||||||
|
|
||||||
// True if mFinished is resolved or would be resolved if mFinished has
|
// True if mFinished is resolved or would be resolved if mFinished has
|
||||||
// yet to be created. This is not set when mFinished is rejected since
|
// yet to be created. This is not set when mFinished is rejected since
|
||||||
// in that case mFinished is immediately reset to represent a new current
|
// in that case mFinished is immediately reset to represent a new current
|
||||||
// finished promise.
|
// finished promise.
|
||||||
bool mFinishedIsResolved;
|
bool mFinishedIsResolved = false;
|
||||||
|
|
||||||
// True if this animation was triggered at the same time as one or more
|
// True if this animation was triggered at the same time as one or more
|
||||||
// geometric animations and hence we should run any transform animations on
|
// geometric animations and hence we should run any transform animations on
|
||||||
// the main thread.
|
// the main thread.
|
||||||
bool mSyncWithGeometricAnimations;
|
bool mSyncWithGeometricAnimations = false;
|
||||||
|
|
||||||
RefPtr<MicroTaskRunnable> mFinishNotificationTask;
|
RefPtr<MicroTaskRunnable> mFinishNotificationTask;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#define mozilla_AnimationTarget_h
|
#define mozilla_AnimationTarget_h
|
||||||
|
|
||||||
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
|
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
|
||||||
|
#include "mozilla/HashFunctions.h" // For HashNumber, AddToHash
|
||||||
|
#include "mozilla/HashTable.h" // For DefaultHasher, PointerHasher
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
#include "nsCSSPseudoElements.h"
|
#include "nsCSSPseudoElements.h"
|
||||||
|
@ -69,6 +71,26 @@ inline void ImplCycleCollectionUnlink(Maybe<OwningAnimationTarget>& aTarget) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A DefaultHasher specialization for OwningAnimationTarget.
|
||||||
|
template <>
|
||||||
|
struct DefaultHasher<OwningAnimationTarget> {
|
||||||
|
using Key = OwningAnimationTarget;
|
||||||
|
using Lookup = OwningAnimationTarget;
|
||||||
|
using PtrHasher = PointerHasher<dom::Element*>;
|
||||||
|
|
||||||
|
static HashNumber hash(const Lookup& aLookup) {
|
||||||
|
return AddToHash(PtrHasher::hash(aLookup.mElement.get()),
|
||||||
|
static_cast<uint8_t>(aLookup.mPseudoType));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool match(const Key& aKey, const Lookup& aLookup) {
|
||||||
|
return PtrHasher::match(aKey.mElement.get(), aLookup.mElement.get()) &&
|
||||||
|
aKey.mPseudoType == aLookup.mPseudoType;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rekey(Key& aKey, Key&& aNewKey) { aKey = std::move(aNewKey); }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // mozilla_AnimationTarget_h
|
#endif // mozilla_AnimationTarget_h
|
||||||
|
|
|
@ -188,13 +188,6 @@ void DocumentTimeline::MostRecentRefreshTimeUpdated() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime) {
|
void DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime) {
|
||||||
// https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events,
|
|
||||||
// step2.
|
|
||||||
// Note that this should be done before nsAutoAnimationMutationBatch which is
|
|
||||||
// inside MostRecentRefreshTimeUpdated(). If PerformMicroTaskCheckpoint was
|
|
||||||
// called before nsAutoAnimationMutationBatch is destroyed, some mutation
|
|
||||||
// records might not be delivered in this checkpoint.
|
|
||||||
nsAutoMicroTask mt;
|
|
||||||
MostRecentRefreshTimeUpdated();
|
MostRecentRefreshTimeUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -394,6 +394,26 @@ class EffectCompositeOrderComparator {
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
static void ComposeSortedEffects(
|
||||||
|
const nsTArray<KeyframeEffect*>& aSortedEffects,
|
||||||
|
const EffectSet* aEffectSet, EffectCompositor::CascadeLevel aCascadeLevel,
|
||||||
|
RawServoAnimationValueMap* aAnimationValues) {
|
||||||
|
// If multiple animations affect the same property, animations with higher
|
||||||
|
// composite order (priority) override or add to animations with lower
|
||||||
|
// priority.
|
||||||
|
nsCSSPropertyIDSet propertiesToSkip;
|
||||||
|
if (aEffectSet) {
|
||||||
|
propertiesToSkip =
|
||||||
|
aCascadeLevel == EffectCompositor::CascadeLevel::Animations
|
||||||
|
? aEffectSet->PropertiesForAnimationsLevel().Inverse()
|
||||||
|
: aEffectSet->PropertiesForAnimationsLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (KeyframeEffect* effect : aSortedEffects) {
|
||||||
|
effect->GetAnimation()->ComposeStyle(*aAnimationValues, propertiesToSkip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool EffectCompositor::GetServoAnimationRule(
|
bool EffectCompositor::GetServoAnimationRule(
|
||||||
const dom::Element* aElement, PseudoStyleType aPseudoType,
|
const dom::Element* aElement, PseudoStyleType aPseudoType,
|
||||||
CascadeLevel aCascadeLevel, RawServoAnimationValueMap* aAnimationValues) {
|
CascadeLevel aCascadeLevel, RawServoAnimationValueMap* aAnimationValues) {
|
||||||
|
@ -417,16 +437,8 @@ bool EffectCompositor::GetServoAnimationRule(
|
||||||
}
|
}
|
||||||
sortedEffectList.Sort(EffectCompositeOrderComparator());
|
sortedEffectList.Sort(EffectCompositeOrderComparator());
|
||||||
|
|
||||||
// If multiple animations affect the same property, animations with higher
|
ComposeSortedEffects(sortedEffectList, effectSet, aCascadeLevel,
|
||||||
// composite order (priority) override or add or animations with lower
|
aAnimationValues);
|
||||||
// priority.
|
|
||||||
const nsCSSPropertyIDSet propertiesToSkip =
|
|
||||||
aCascadeLevel == CascadeLevel::Animations
|
|
||||||
? effectSet->PropertiesForAnimationsLevel().Inverse()
|
|
||||||
: effectSet->PropertiesForAnimationsLevel();
|
|
||||||
for (KeyframeEffect* effect : sortedEffectList) {
|
|
||||||
effect->GetAnimation()->ComposeStyle(*aAnimationValues, propertiesToSkip);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(effectSet == EffectSet::GetEffectSet(aElement, aPseudoType),
|
MOZ_ASSERT(effectSet == EffectSet::GetEffectSet(aElement, aPseudoType),
|
||||||
"EffectSet should not change while composing style");
|
"EffectSet should not change while composing style");
|
||||||
|
@ -434,6 +446,59 @@ bool EffectCompositor::GetServoAnimationRule(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EffectCompositor::ComposeServoAnimationRuleForEffect(
|
||||||
|
KeyframeEffect& aEffect, CascadeLevel aCascadeLevel,
|
||||||
|
RawServoAnimationValueMap* aAnimationValues) {
|
||||||
|
MOZ_ASSERT(aAnimationValues);
|
||||||
|
MOZ_ASSERT(mPresContext && mPresContext->IsDynamic(),
|
||||||
|
"Should not be in print preview");
|
||||||
|
|
||||||
|
Maybe<NonOwningAnimationTarget> target = aEffect.GetTarget();
|
||||||
|
if (!target) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't try to compose animations for elements in documents without a pres
|
||||||
|
// shell (e.g. XMLHttpRequest documents).
|
||||||
|
if (!nsContentUtils::GetPresShellForContent(target->mElement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServoAnimationRule is called as part of the regular style resolution
|
||||||
|
// where the cascade results are updated in the pre-traversal as needed.
|
||||||
|
// This function, however, is only called when committing styles so we
|
||||||
|
// need to ensure the cascade results are up-to-date manually.
|
||||||
|
EffectCompositor::MaybeUpdateCascadeResults(target->mElement,
|
||||||
|
target->mPseudoType);
|
||||||
|
|
||||||
|
EffectSet* effectSet =
|
||||||
|
EffectSet::GetEffectSet(target->mElement, target->mPseudoType);
|
||||||
|
|
||||||
|
// Get a list of effects sorted by composite order up to and including
|
||||||
|
// |aEffect|, even if it is not in the EffectSet.
|
||||||
|
auto comparator = EffectCompositeOrderComparator();
|
||||||
|
nsTArray<KeyframeEffect*> sortedEffectList(effectSet ? effectSet->Count() + 1
|
||||||
|
: 1);
|
||||||
|
if (effectSet) {
|
||||||
|
for (KeyframeEffect* effect : *effectSet) {
|
||||||
|
if (comparator.LessThan(effect, &aEffect)) {
|
||||||
|
sortedEffectList.AppendElement(effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortedEffectList.Sort(comparator);
|
||||||
|
}
|
||||||
|
sortedEffectList.AppendElement(&aEffect);
|
||||||
|
|
||||||
|
ComposeSortedEffects(sortedEffectList, effectSet, aCascadeLevel,
|
||||||
|
aAnimationValues);
|
||||||
|
|
||||||
|
MOZ_ASSERT(effectSet ==
|
||||||
|
EffectSet::GetEffectSet(target->mElement, target->mPseudoType),
|
||||||
|
"EffectSet should not change while composing style");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ dom::Element* EffectCompositor::GetElementToRestyle(
|
/* static */ dom::Element* EffectCompositor::GetElementToRestyle(
|
||||||
dom::Element* aElement, PseudoStyleType aPseudoType) {
|
dom::Element* aElement, PseudoStyleType aPseudoType) {
|
||||||
if (aPseudoType == PseudoStyleType::NotPseudo) {
|
if (aPseudoType == PseudoStyleType::NotPseudo) {
|
||||||
|
@ -862,4 +927,53 @@ bool EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags,
|
||||||
return foundElementsNeedingRestyle;
|
return foundElementsNeedingRestyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectCompositor::NoteElementForReducing(
|
||||||
|
const NonOwningAnimationTarget& aTarget) {
|
||||||
|
if (!StaticPrefs::dom_animations_api_autoremove_enabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unused << mElementsToReduce.put(
|
||||||
|
OwningAnimationTarget{aTarget.mElement, aTarget.mPseudoType});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReduceEffectSet(EffectSet& aEffectSet) {
|
||||||
|
// Get a list of effects sorted by composite order.
|
||||||
|
nsTArray<KeyframeEffect*> sortedEffectList(aEffectSet.Count());
|
||||||
|
for (KeyframeEffect* effect : aEffectSet) {
|
||||||
|
sortedEffectList.AppendElement(effect);
|
||||||
|
}
|
||||||
|
sortedEffectList.Sort(EffectCompositeOrderComparator());
|
||||||
|
|
||||||
|
nsCSSPropertyIDSet setProperties;
|
||||||
|
|
||||||
|
// Iterate in reverse
|
||||||
|
for (auto iter = sortedEffectList.rbegin(); iter != sortedEffectList.rend();
|
||||||
|
++iter) {
|
||||||
|
MOZ_ASSERT(*iter && (*iter)->GetAnimation(),
|
||||||
|
"Effect in an EffectSet should have an animation");
|
||||||
|
KeyframeEffect& effect = **iter;
|
||||||
|
Animation& animation = *effect.GetAnimation();
|
||||||
|
if (animation.IsRemovable() &&
|
||||||
|
effect.GetPropertySet().IsSubsetOf(setProperties)) {
|
||||||
|
animation.Remove();
|
||||||
|
} else if (animation.IsReplaceable()) {
|
||||||
|
setProperties |= effect.GetPropertySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectCompositor::ReduceAnimations() {
|
||||||
|
for (auto iter = mElementsToReduce.iter(); !iter.done(); iter.next()) {
|
||||||
|
const OwningAnimationTarget& target = iter.get();
|
||||||
|
EffectSet* effectSet =
|
||||||
|
EffectSet::GetEffectSet(target.mElement, target.mPseudoType);
|
||||||
|
if (effectSet) {
|
||||||
|
ReduceEffectSet(*effectSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mElementsToReduce.clear();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
#define mozilla_EffectCompositor_h
|
#define mozilla_EffectCompositor_h
|
||||||
|
|
||||||
#include "mozilla/AnimationPerformanceWarning.h"
|
#include "mozilla/AnimationPerformanceWarning.h"
|
||||||
|
#include "mozilla/AnimationTarget.h"
|
||||||
#include "mozilla/EnumeratedArray.h"
|
#include "mozilla/EnumeratedArray.h"
|
||||||
|
#include "mozilla/HashTable.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/OwningNonNull.h"
|
#include "mozilla/OwningNonNull.h"
|
||||||
#include "mozilla/PseudoElementHashEntry.h"
|
#include "mozilla/PseudoElementHashEntry.h"
|
||||||
|
@ -38,6 +40,7 @@ struct NonOwningAnimationTarget;
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class Animation;
|
class Animation;
|
||||||
class Element;
|
class Element;
|
||||||
|
class KeyframeEffect;
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
||||||
class EffectCompositor {
|
class EffectCompositor {
|
||||||
|
@ -116,8 +119,9 @@ class EffectCompositor {
|
||||||
dom::Element* aElement,
|
dom::Element* aElement,
|
||||||
PseudoStyleType aPseudoType);
|
PseudoStyleType aPseudoType);
|
||||||
|
|
||||||
// Get animation rule for stylo. This is an equivalent of GetAnimationRule
|
// Get the animation rule for the appropriate level of the cascade for
|
||||||
// and will be called from servo side.
|
// a (pseudo-)element. Called from the Servo side.
|
||||||
|
//
|
||||||
// The animation rule is stored in |RawServoAnimationValueMap|.
|
// The animation rule is stored in |RawServoAnimationValueMap|.
|
||||||
// We need to be careful while doing any modification because it may cause
|
// We need to be careful while doing any modification because it may cause
|
||||||
// some thread-safe issues.
|
// some thread-safe issues.
|
||||||
|
@ -126,6 +130,15 @@ class EffectCompositor {
|
||||||
CascadeLevel aCascadeLevel,
|
CascadeLevel aCascadeLevel,
|
||||||
RawServoAnimationValueMap* aAnimationValues);
|
RawServoAnimationValueMap* aAnimationValues);
|
||||||
|
|
||||||
|
// A variant on GetServoAnimationRule that composes all the effects for an
|
||||||
|
// element up to and including |aEffect|.
|
||||||
|
//
|
||||||
|
// Note that |aEffect| might not be in the EffectSet since we can use this for
|
||||||
|
// committing the computed style of a removed Animation.
|
||||||
|
bool ComposeServoAnimationRuleForEffect(
|
||||||
|
dom::KeyframeEffect& aEffect, CascadeLevel aCascadeLevel,
|
||||||
|
RawServoAnimationValueMap* aAnimationValues);
|
||||||
|
|
||||||
bool HasPendingStyleUpdates() const;
|
bool HasPendingStyleUpdates() const;
|
||||||
|
|
||||||
static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
|
static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
|
||||||
|
@ -199,6 +212,12 @@ class EffectCompositor {
|
||||||
// at aElement.
|
// at aElement.
|
||||||
bool PreTraverseInSubtree(ServoTraversalFlags aFlags, dom::Element* aRoot);
|
bool PreTraverseInSubtree(ServoTraversalFlags aFlags, dom::Element* aRoot);
|
||||||
|
|
||||||
|
// Record a (pseudo-)element that may have animations that can be removed.
|
||||||
|
void NoteElementForReducing(const NonOwningAnimationTarget& aTarget);
|
||||||
|
|
||||||
|
bool NeedsReducing() const { return !mElementsToReduce.empty(); }
|
||||||
|
void ReduceAnimations();
|
||||||
|
|
||||||
// Returns the target element for restyling.
|
// Returns the target element for restyling.
|
||||||
//
|
//
|
||||||
// If |aPseudoType| is ::after, ::before or ::marker, returns the generated
|
// If |aPseudoType| is ::after, ::before or ::marker, returns the generated
|
||||||
|
@ -239,6 +258,8 @@ class EffectCompositor {
|
||||||
mElementsToRestyle;
|
mElementsToRestyle;
|
||||||
|
|
||||||
bool mIsInPreTraverse = false;
|
bool mIsInPreTraverse = false;
|
||||||
|
|
||||||
|
HashSet<OwningAnimationTarget> mElementsToReduce;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -317,7 +317,7 @@ nsCSSPropertyIDSet KeyframeEffect::GetPropertiesForCompositor(
|
||||||
|
|
||||||
nsCSSPropertyIDSet properties;
|
nsCSSPropertyIDSet properties;
|
||||||
|
|
||||||
if (!IsInEffect() && !IsCurrent()) {
|
if (!mAnimation || !mAnimation->IsRelevant()) {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,14 +342,14 @@ nsCSSPropertyIDSet KeyframeEffect::GetPropertiesForCompositor(
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KeyframeEffect::HasAnimationOfPropertySet(
|
nsCSSPropertyIDSet KeyframeEffect::GetPropertySet() const {
|
||||||
const nsCSSPropertyIDSet& aPropertySet) const {
|
nsCSSPropertyIDSet result;
|
||||||
|
|
||||||
for (const AnimationProperty& property : mProperties) {
|
for (const AnimationProperty& property : mProperties) {
|
||||||
if (aPropertySet.HasProperty(property.mProperty)) {
|
result.AddProperty(property.mProperty);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -418,6 +418,10 @@ void KeyframeEffect::UpdateProperties(const ComputedStyle* aStyle) {
|
||||||
|
|
||||||
MarkCascadeNeedsUpdate();
|
MarkCascadeNeedsUpdate();
|
||||||
|
|
||||||
|
if (mAnimation) {
|
||||||
|
mAnimation->NotifyEffectPropertiesUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
RequestRestyle(EffectCompositor::RestyleType::Layer);
|
RequestRestyle(EffectCompositor::RestyleType::Layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,13 +579,10 @@ void KeyframeEffect::ComposeStyle(RawServoAnimationValueMap& aComposeResult,
|
||||||
if (HasPropertiesThatMightAffectOverflow()) {
|
if (HasPropertiesThatMightAffectOverflow()) {
|
||||||
nsPresContext* presContext =
|
nsPresContext* presContext =
|
||||||
nsContentUtils::GetContextForContent(mTarget->mElement);
|
nsContentUtils::GetContextForContent(mTarget->mElement);
|
||||||
if (presContext) {
|
|
||||||
TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
|
|
||||||
EffectSet* effectSet =
|
EffectSet* effectSet =
|
||||||
EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
|
EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
|
||||||
MOZ_ASSERT(effectSet,
|
if (presContext && effectSet) {
|
||||||
"ComposeStyle should only be called on an effect "
|
TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
|
||||||
"that is part of an effect set");
|
|
||||||
effectSet->UpdateLastOverflowAnimationSyncTime(now);
|
effectSet->UpdateLastOverflowAnimationSyncTime(now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -792,7 +793,9 @@ void KeyframeEffect::UpdateTargetRegistration() {
|
||||||
// something calls Animation::UpdateRelevance. Whenever our timing changes,
|
// something calls Animation::UpdateRelevance. Whenever our timing changes,
|
||||||
// we should be notifying our Animation before calling this, so
|
// we should be notifying our Animation before calling this, so
|
||||||
// Animation::IsRelevant() should be up-to-date by the time we get here.
|
// Animation::IsRelevant() should be up-to-date by the time we get here.
|
||||||
MOZ_ASSERT(isRelevant == IsCurrent() || IsInEffect(),
|
MOZ_ASSERT(isRelevant ==
|
||||||
|
((IsCurrent() || IsInEffect()) && mAnimation &&
|
||||||
|
mAnimation->ReplaceState() != AnimationReplaceState::Removed),
|
||||||
"Out of date Animation::IsRelevant value");
|
"Out of date Animation::IsRelevant value");
|
||||||
|
|
||||||
if (isRelevant && !mInEffectSet) {
|
if (isRelevant && !mInEffectSet) {
|
||||||
|
@ -999,6 +1002,10 @@ void KeyframeEffect::SetTarget(
|
||||||
mAnimation->ReschedulePendingTasks();
|
mAnimation->ReschedulePendingTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mAnimation) {
|
||||||
|
mAnimation->NotifyEffectTargetUpdated();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CreatePropertyValue(
|
static void CreatePropertyValue(
|
||||||
|
@ -1728,6 +1735,11 @@ bool KeyframeEffect::ContainsAnimatedScale(const nsIFrame* aFrame) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mAnimation ||
|
||||||
|
mAnimation->ReplaceState() == AnimationReplaceState::Removed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (const AnimationProperty& prop : mProperties) {
|
for (const AnimationProperty& prop : mProperties) {
|
||||||
if (prop.mProperty != eCSSProperty_transform &&
|
if (prop.mProperty != eCSSProperty_transform &&
|
||||||
prop.mProperty != eCSSProperty_scale &&
|
prop.mProperty != eCSSProperty_scale &&
|
||||||
|
|
|
@ -183,9 +183,15 @@ class KeyframeEffect : public AnimationEffect {
|
||||||
void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
|
void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
|
||||||
const ComputedStyle* aStyle);
|
const ComputedStyle* aStyle);
|
||||||
|
|
||||||
|
// Returns the set of properties affected by this effect regardless of
|
||||||
|
// whether any of these properties is overridden by an !important rule.
|
||||||
|
nsCSSPropertyIDSet GetPropertySet() const;
|
||||||
|
|
||||||
// Returns true if the effect includes a property in |aPropertySet| regardless
|
// Returns true if the effect includes a property in |aPropertySet| regardless
|
||||||
// of whether any property in the set is overridden by !important rule.
|
// of whether any property in the set is overridden by an !important rule.
|
||||||
bool HasAnimationOfPropertySet(const nsCSSPropertyIDSet& aPropertySet) const;
|
bool HasAnimationOfPropertySet(const nsCSSPropertyIDSet& aPropertySet) const {
|
||||||
|
return GetPropertySet().Intersects(aPropertySet);
|
||||||
|
}
|
||||||
|
|
||||||
// GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
|
// GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
|
||||||
// to a given CSS property if the effect includes the property and the
|
// to a given CSS property if the effect includes the property and the
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
prefs =
|
prefs =
|
||||||
|
dom.animations-api.autoremove.enabled=true
|
||||||
dom.animations-api.compositing.enabled=true
|
dom.animations-api.compositing.enabled=true
|
||||||
gfx.omta.background-color=true
|
gfx.omta.background-color=true
|
||||||
layout.css.individual-transform.enabled=true
|
layout.css.individual-transform.enabled=true
|
||||||
|
|
|
@ -578,5 +578,74 @@ promise_test(t => {
|
||||||
});
|
});
|
||||||
}, "tree_ordering: subtree");
|
}, "tree_ordering: subtree");
|
||||||
|
|
||||||
|
// Test that animations removed by auto-removal trigger an event
|
||||||
|
promise_test(async t => {
|
||||||
|
setupAsynchronousObserver(t, { observe: div, subtree: false });
|
||||||
|
|
||||||
|
// Start two animations such that one will be auto-removed
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 1 },
|
||||||
|
{ duration: 100 * MS_PER_SEC, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 1 },
|
||||||
|
{ duration: 100 * MS_PER_SEC, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wait for the MutationRecords corresponding to each addition.
|
||||||
|
await waitForNextFrame();
|
||||||
|
|
||||||
|
assert_records(
|
||||||
|
[
|
||||||
|
{ added: [animA], changed: [], removed: [] },
|
||||||
|
{ added: [animB], changed: [], removed: [] },
|
||||||
|
],
|
||||||
|
'records after animation start'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Finish the animations -- this should cause animA to be replaced, and
|
||||||
|
// automatically removed.
|
||||||
|
animA.finish();
|
||||||
|
animB.finish();
|
||||||
|
|
||||||
|
// Wait for the MutationRecords corresponding to the timing changes and the
|
||||||
|
// subsequent removal to be delivered.
|
||||||
|
await waitForNextFrame();
|
||||||
|
|
||||||
|
assert_records(
|
||||||
|
[
|
||||||
|
{ added: [], changed: [animA], removed: [] },
|
||||||
|
{ added: [], changed: [animB], removed: [] },
|
||||||
|
{ added: [], changed: [], removed: [animA] },
|
||||||
|
],
|
||||||
|
'records after finishing'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Restore animA.
|
||||||
|
animA.persist();
|
||||||
|
|
||||||
|
// Wait for the MutationRecord corresponding to the re-addition of animA.
|
||||||
|
await waitForNextFrame();
|
||||||
|
|
||||||
|
assert_records(
|
||||||
|
[{ added: [animA], changed: [], removed: [] }],
|
||||||
|
'records after persisting'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tidy up
|
||||||
|
animA.cancel();
|
||||||
|
animB.cancel();
|
||||||
|
|
||||||
|
await waitForNextFrame();
|
||||||
|
|
||||||
|
assert_records(
|
||||||
|
[
|
||||||
|
{ added: [], changed: [], removed: [animA] },
|
||||||
|
{ added: [], changed: [], removed: [animB] },
|
||||||
|
],
|
||||||
|
'records after tidying up end'
|
||||||
|
);
|
||||||
|
}, 'Animations automatically removed are reported');
|
||||||
|
|
||||||
runTest();
|
runTest();
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -14,6 +14,7 @@ support-files =
|
||||||
chrome/file_animate_xrays.html
|
chrome/file_animate_xrays.html
|
||||||
mozilla/xhr_doc.html
|
mozilla/xhr_doc.html
|
||||||
mozilla/file_deferred_start.html
|
mozilla/file_deferred_start.html
|
||||||
|
mozilla/file_disable_animations_api_autoremove.html
|
||||||
mozilla/file_disable_animations_api_compositing.html
|
mozilla/file_disable_animations_api_compositing.html
|
||||||
mozilla/file_disable_animations_api_get_animations.html
|
mozilla/file_disable_animations_api_get_animations.html
|
||||||
mozilla/file_disable_animations_api_implicit_keyframes.html
|
mozilla/file_disable_animations_api_implicit_keyframes.html
|
||||||
|
@ -32,6 +33,7 @@ skip-if = (verify && !debug && (os == 'mac'))
|
||||||
[mozilla/test_cubic_bezier_limits.html]
|
[mozilla/test_cubic_bezier_limits.html]
|
||||||
[mozilla/test_deferred_start.html]
|
[mozilla/test_deferred_start.html]
|
||||||
skip-if = (toolkit == 'android' && debug) || (os == 'win' && bits == 64) # Bug 1363957
|
skip-if = (toolkit == 'android' && debug) || (os == 'win' && bits == 64) # Bug 1363957
|
||||||
|
[mozilla/test_disable_animations_api_autoremove.html]
|
||||||
[mozilla/test_disable_animations_api_compositing.html]
|
[mozilla/test_disable_animations_api_compositing.html]
|
||||||
[mozilla/test_disable_animations_api_get_animations.html]
|
[mozilla/test_disable_animations_api_get_animations.html]
|
||||||
[mozilla/test_disable_animations_api_implicit_keyframes.html]
|
[mozilla/test_disable_animations_api_implicit_keyframes.html]
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<script src="../testcommon.js"></script>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = addDiv(t);
|
||||||
|
|
||||||
|
const animA = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
const animB = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
|
||||||
|
// This should be assert_not_own_property but our local copy of testharness.js
|
||||||
|
// is old.
|
||||||
|
assert_equals(
|
||||||
|
animA.replaceState,
|
||||||
|
undefined,
|
||||||
|
'Should not have a replaceState member'
|
||||||
|
);
|
||||||
|
|
||||||
|
animA.addEventListener(
|
||||||
|
'remove',
|
||||||
|
t.step_func(() => {
|
||||||
|
assert_unreached('Should not fire a remove event');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Allow a chance for the remove event to be fired
|
||||||
|
|
||||||
|
await animA.finished;
|
||||||
|
await waitForNextFrame();
|
||||||
|
}, 'Remove events should not be fired if the pref is not set');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = addDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 0.3, composite: 'add' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
assert_approx_equals(
|
||||||
|
parseFloat(getComputedStyle(div).opacity),
|
||||||
|
0.5,
|
||||||
|
0.0001,
|
||||||
|
'Covered animation should still contribute to effect stack when adding'
|
||||||
|
);
|
||||||
|
|
||||||
|
animB.cancel();
|
||||||
|
|
||||||
|
assert_approx_equals(
|
||||||
|
parseFloat(getComputedStyle(div).opacity),
|
||||||
|
0.2,
|
||||||
|
0.0001,
|
||||||
|
'Covered animation should still contribute to animated style when replacing'
|
||||||
|
);
|
||||||
|
}, 'Covered animations should still affect style if the pref is not set');
|
||||||
|
|
||||||
|
done();
|
||||||
|
</script>
|
||||||
|
</body>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<div id="log"></div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
setup({ explicit_done: true });
|
||||||
|
SpecialPowers.pushPrefEnv(
|
||||||
|
{ set: [['dom.animations-api.autoremove.enabled', false]] },
|
||||||
|
function() {
|
||||||
|
window.open('file_disable_animations_api_autoremove.html');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
|
@ -1407,6 +1407,14 @@ class Element : public FragmentOrElement {
|
||||||
return HasServoData() && Servo_Element_IsDisplayContents(this);
|
return HasServoData() && Servo_Element_IsDisplayContents(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://html.spec.whatwg.org/#being-rendered
|
||||||
|
*
|
||||||
|
* With a gotcha for display contents:
|
||||||
|
* https://github.com/whatwg/html/issues/1837
|
||||||
|
*/
|
||||||
|
bool IsRendered() const { return GetPrimaryFrame() || IsDisplayContents(); }
|
||||||
|
|
||||||
const nsAttrValue* GetParsedAttr(const nsAtom* aAttr) const {
|
const nsAttrValue* GetParsedAttr(const nsAtom* aAttr) const {
|
||||||
return mAttrs.GetAttr(aAttr);
|
return mAttrs.GetAttr(aAttr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,8 +346,8 @@ static nsresult PutToClipboard(
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsCopySupport::HTMLCopy(Selection* aSel, Document* aDoc,
|
nsresult nsCopySupport::EncodeDocumentWithContextAndPutToClipboard(
|
||||||
int16_t aClipboardID,
|
Selection* aSel, Document* aDoc, int16_t aClipboardID,
|
||||||
bool aWithRubyAnnotation) {
|
bool aWithRubyAnnotation) {
|
||||||
NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
|
NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
|
||||||
|
|
||||||
|
@ -915,8 +915,8 @@ bool nsCopySupport::FireClipboardEvent(EventMessage aEventMessage,
|
||||||
// selection is inside a same ruby container. But we really should
|
// selection is inside a same ruby container. But we really should
|
||||||
// expose the full functionality in browser. See bug 1130891.
|
// expose the full functionality in browser. See bug 1130891.
|
||||||
bool withRubyAnnotation = IsSelectionInsideRuby(sel);
|
bool withRubyAnnotation = IsSelectionInsideRuby(sel);
|
||||||
// call the copy code
|
nsresult rv = EncodeDocumentWithContextAndPutToClipboard(
|
||||||
nsresult rv = HTMLCopy(sel, doc, aClipboardType, withRubyAnnotation);
|
sel, doc, aClipboardType, withRubyAnnotation);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ class nsCopySupport {
|
||||||
/**
|
/**
|
||||||
* @param aDoc Needs to be not nullptr.
|
* @param aDoc Needs to be not nullptr.
|
||||||
*/
|
*/
|
||||||
static nsresult HTMLCopy(mozilla::dom::Selection* aSel,
|
static nsresult EncodeDocumentWithContextAndPutToClipboard(
|
||||||
mozilla::dom::Document* aDoc, int16_t aClipboardID,
|
mozilla::dom::Selection* aSel, mozilla::dom::Document* aDoc,
|
||||||
bool aWithRubyAnnotation);
|
int16_t aClipboardID, bool aWithRubyAnnotation);
|
||||||
|
|
||||||
// Get the selection, or entire document, in the format specified by the mime
|
// Get the selection, or entire document, in the format specified by the mime
|
||||||
// type (text/html or text/plain). If aSel is non-null, use it, otherwise get
|
// type (text/html or text/plain). If aSel is non-null, use it, otherwise get
|
||||||
|
@ -47,8 +47,7 @@ class nsCopySupport {
|
||||||
static nsresult ImageCopy(nsIImageLoadingContent* aImageElement,
|
static nsresult ImageCopy(nsIImageLoadingContent* aImageElement,
|
||||||
nsILoadContext* aLoadContext, int32_t aCopyFlags);
|
nsILoadContext* aLoadContext, int32_t aCopyFlags);
|
||||||
|
|
||||||
// Get the selection as a transferable. Similar to HTMLCopy except does
|
// Get the selection as a transferable.
|
||||||
// not deal with the clipboard.
|
|
||||||
// @param aSelection Can be nullptr.
|
// @param aSelection Can be nullptr.
|
||||||
// @param aDocument Needs to be not nullptr.
|
// @param aDocument Needs to be not nullptr.
|
||||||
// @param aTransferable Needs to be not nullptr.
|
// @param aTransferable Needs to be not nullptr.
|
||||||
|
|
|
@ -85,9 +85,7 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
|
||||||
|
|
||||||
nsresult FlushText(nsAString& aString, bool aForce);
|
nsresult FlushText(nsAString& aString, bool aForce);
|
||||||
|
|
||||||
bool IsVisibleNode(nsINode* aNode) {
|
bool IsInvisibleNodeAndShouldBeSkipped(nsINode& aNode) const {
|
||||||
MOZ_ASSERT(aNode, "null node");
|
|
||||||
|
|
||||||
if (mFlags & SkipInvisibleContent) {
|
if (mFlags & SkipInvisibleContent) {
|
||||||
// Treat the visibility of the ShadowRoot as if it were
|
// Treat the visibility of the ShadowRoot as if it were
|
||||||
// the host content.
|
// the host content.
|
||||||
|
@ -95,36 +93,39 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
|
||||||
// FIXME(emilio): I suspect instead of this a bunch of the GetParent()
|
// FIXME(emilio): I suspect instead of this a bunch of the GetParent()
|
||||||
// calls here should be doing GetFlattenedTreeParent, then this condition
|
// calls here should be doing GetFlattenedTreeParent, then this condition
|
||||||
// should be unreachable...
|
// should be unreachable...
|
||||||
if (ShadowRoot* shadowRoot = ShadowRoot::FromNode(aNode)) {
|
nsINode* node{&aNode};
|
||||||
aNode = shadowRoot->GetHost();
|
if (ShadowRoot* shadowRoot = ShadowRoot::FromNode(node)) {
|
||||||
|
node = shadowRoot->GetHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aNode->IsContent()) {
|
if (node->IsContent()) {
|
||||||
nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
|
nsIFrame* frame = node->AsContent()->GetPrimaryFrame();
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
if (aNode->IsElement() && aNode->AsElement()->IsDisplayContents()) {
|
if (node->IsElement() && node->AsElement()->IsDisplayContents()) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
if (aNode->IsText()) {
|
if (node->IsText()) {
|
||||||
// We have already checked that our parent is visible.
|
// We have already checked that our parent is visible.
|
||||||
//
|
//
|
||||||
// FIXME(emilio): Text not assigned to a <slot> in Shadow DOM should
|
// FIXME(emilio): Text not assigned to a <slot> in Shadow DOM should
|
||||||
// probably return false...
|
// probably return false...
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (aNode->IsHTMLElement(nsGkAtoms::rp)) {
|
|
||||||
// Ruby parentheses are part of ruby structure, hence
|
|
||||||
// shouldn't be stripped out even if it is not displayed.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool isVisible = frame->StyleVisibility()->IsVisible();
|
if (node->IsHTMLElement(nsGkAtoms::rp)) {
|
||||||
if (!isVisible && aNode->IsText()) return false;
|
// Ruby parentheses are part of ruby structure, hence
|
||||||
}
|
// shouldn't be stripped out even if it is not displayed.
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
bool isVisible = frame->StyleVisibility()->IsVisible();
|
||||||
|
if (!isVisible && node->IsText()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool IncludeInContext(nsINode* aNode);
|
virtual bool IncludeInContext(nsINode* aNode);
|
||||||
|
|
||||||
|
@ -349,7 +350,7 @@ nsresult nsDocumentEncoder::SerializeNodeStart(nsINode& aOriginalNode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsVisibleNode(&aOriginalNode)) {
|
if (IsInvisibleNodeAndShouldBeSkipped(aOriginalNode)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +412,7 @@ nsresult nsDocumentEncoder::SerializeNodeEnd(nsINode& aNode, nsAString& aStr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsVisibleNode(&aNode)) {
|
if (IsInvisibleNodeAndShouldBeSkipped(aNode)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,11 +430,12 @@ nsresult nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsVisibleNode(aNode)) return NS_OK;
|
NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
if (IsInvisibleNodeAndShouldBeSkipped(*aNode)) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(aNode, "aNode shouldn't be nullptr.");
|
|
||||||
FixupNodeDeterminer fixupNodeDeterminer{mNodeFixup, nullptr, *aNode};
|
FixupNodeDeterminer fixupNodeDeterminer{mNodeFixup, nullptr, *aNode};
|
||||||
nsINode* maybeFixedNode =
|
nsINode* maybeFixedNode =
|
||||||
&fixupNodeDeterminer.GetFixupNodeFallBackToOriginalNode();
|
&fixupNodeDeterminer.GetFixupNodeFallBackToOriginalNode();
|
||||||
|
@ -449,6 +451,8 @@ nsresult nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
if (!aDontSerializeRoot) {
|
if (!aDontSerializeRoot) {
|
||||||
int32_t endOffset = -1;
|
int32_t endOffset = -1;
|
||||||
if (aMaxLength > 0) {
|
if (aMaxLength > 0) {
|
||||||
|
@ -585,7 +589,9 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
||||||
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
if (!IsVisibleNode(aNode)) return NS_OK;
|
if (IsInvisibleNodeAndShouldBeSkipped(*aNode)) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
@ -788,11 +794,13 @@ nsresult nsDocumentEncoder::SerializeRangeToString(nsRange* aRange,
|
||||||
if (startContainer == endContainer && IsTextNode(startContainer)) {
|
if (startContainer == endContainer && IsTextNode(startContainer)) {
|
||||||
if (mFlags & SkipInvisibleContent) {
|
if (mFlags & SkipInvisibleContent) {
|
||||||
// Check that the parent is visible if we don't a frame.
|
// Check that the parent is visible if we don't a frame.
|
||||||
// IsVisibleNode() will do it when there's a frame.
|
// IsInvisibleNodeAndShouldBeSkipped() will do it when there's a frame.
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(startContainer);
|
nsCOMPtr<nsIContent> content = do_QueryInterface(startContainer);
|
||||||
if (content && !content->GetPrimaryFrame()) {
|
if (content && !content->GetPrimaryFrame()) {
|
||||||
nsIContent* parent = content->GetParent();
|
nsIContent* parent = content->GetParent();
|
||||||
if (!parent || !IsVisibleNode(parent)) return NS_OK;
|
if (!parent || IsInvisibleNodeAndShouldBeSkipped(*parent)) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rv = SerializeNodeStart(*startContainer, startOffset, endOffset,
|
rv = SerializeNodeStart(*startContainer, startOffset, endOffset,
|
||||||
|
@ -847,9 +855,9 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||||
aOutputString.Truncate();
|
aOutputString.Truncate();
|
||||||
|
|
||||||
nsString output;
|
nsString output;
|
||||||
static const size_t bufferSize = 2048;
|
static const size_t kStringBufferSizeInBytes = 2048;
|
||||||
if (!mCachedBuffer) {
|
if (!mCachedBuffer) {
|
||||||
mCachedBuffer = nsStringBuffer::Alloc(bufferSize).take();
|
mCachedBuffer = nsStringBuffer::Alloc(kStringBufferSizeInBytes).take();
|
||||||
if (NS_WARN_IF(!mCachedBuffer)) {
|
if (NS_WARN_IF(!mCachedBuffer)) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
@ -975,7 +983,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||||
bool setOutput = false;
|
bool setOutput = false;
|
||||||
// Try to cache the buffer.
|
// Try to cache the buffer.
|
||||||
if (mCachedBuffer) {
|
if (mCachedBuffer) {
|
||||||
if (mCachedBuffer->StorageSize() == bufferSize &&
|
if ((mCachedBuffer->StorageSize() == kStringBufferSizeInBytes) &&
|
||||||
!mCachedBuffer->IsReadonly()) {
|
!mCachedBuffer->IsReadonly()) {
|
||||||
mCachedBuffer->AddRef();
|
mCachedBuffer->AddRef();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -466,7 +466,7 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||||
MOZ_CAN_RUN_SCRIPT mozilla::dom::Element* GetParentFlexElement();
|
MOZ_CAN_RUN_SCRIPT mozilla::dom::Element* GetParentFlexElement();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether the node is an Element node
|
* Return whether the node is an Element node. Faster than using `NodeType()`.
|
||||||
*/
|
*/
|
||||||
bool IsElement() const { return GetBoolFlag(NodeIsElement); }
|
bool IsElement() const { return GetBoolFlag(NodeIsElement); }
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,9 @@ interface JSWindowActorChild {
|
||||||
[Throws]
|
[Throws]
|
||||||
readonly attribute BrowsingContext? browsingContext;
|
readonly attribute BrowsingContext? browsingContext;
|
||||||
|
|
||||||
|
[Throws]
|
||||||
|
readonly attribute nsIDocShell? docShell;
|
||||||
|
|
||||||
// NOTE: As this returns a window proxy, it may not be currently referencing
|
// NOTE: As this returns a window proxy, it may not be currently referencing
|
||||||
// the document associated with this JSWindowActor. Generally prefer using
|
// the document associated with this JSWindowActor. Generally prefer using
|
||||||
// `document`.
|
// `document`.
|
||||||
|
|
|
@ -76,7 +76,7 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
||||||
[test_bug563329.html]
|
[test_bug563329.html]
|
||||||
skip-if = true # Disabled due to timeouts.
|
skip-if = true # Disabled due to timeouts.
|
||||||
[test_bug574663.html]
|
[test_bug574663.html]
|
||||||
skip-if = (toolkit == 'android') || (os == 'win' && bits == 32 && !debug) || (os == 'linux' && !debug) #CRASH_DUMP, RANDOM, Bug 1523853
|
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
||||||
[test_bug591815.html]
|
[test_bug591815.html]
|
||||||
[test_bug593959.html]
|
[test_bug593959.html]
|
||||||
[test_bug603008.html]
|
[test_bug603008.html]
|
||||||
|
|
|
@ -63,7 +63,6 @@ function forceScrollAndWait(scrollbox, callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var kExtraEvents = 5;
|
|
||||||
var kDelta = 3;
|
var kDelta = 3;
|
||||||
|
|
||||||
function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum, callback) {
|
function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum, callback) {
|
||||||
|
@ -91,11 +90,9 @@ function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum, callback
|
||||||
scrollbox.addEventListener("wheel", onwheel);
|
scrollbox.addEventListener("wheel", onwheel);
|
||||||
|
|
||||||
synthesizeWheel(scrollbox, 10, 10, event, win);
|
synthesizeWheel(scrollbox, 10, 10, event, win);
|
||||||
// then 5 additional pixel scrolls
|
// then additional pixel scroll
|
||||||
event.lineOrPageDeltaY = 0;
|
event.lineOrPageDeltaY = 0;
|
||||||
for (let i = 1; i <= kExtraEvents; ++i) {
|
|
||||||
synthesizeWheel(scrollbox, 10, 10, event, win);
|
synthesizeWheel(scrollbox, 10, 10, event, win);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function runTest() {
|
function runTest() {
|
||||||
|
@ -147,7 +144,7 @@ function runTest() {
|
||||||
let postfix = isMomentum ? ", even after releasing the touchpad" : "";
|
let postfix = isMomentum ? ", even after releasing the touchpad" : "";
|
||||||
// Normal scroll: scroll
|
// Normal scroll: scroll
|
||||||
is(winUtils.fullZoom, zoomFactorBefore, "Normal scrolling shouldn't change zoom" + postfix);
|
is(winUtils.fullZoom, zoomFactorBefore, "Normal scrolling shouldn't change zoom" + postfix);
|
||||||
is(scrollbox.scrollTop, scrollTopBefore + kDelta * (kExtraEvents + 1),
|
is(scrollbox.scrollTop, scrollTopBefore + kDelta * 2,
|
||||||
"Normal scrolling should scroll" + postfix);
|
"Normal scrolling should scroll" + postfix);
|
||||||
} else {
|
} else {
|
||||||
if (!isMomentum) {
|
if (!isMomentum) {
|
||||||
|
@ -155,7 +152,7 @@ function runTest() {
|
||||||
is(scrollbox.scrollTop, scrollTopBefore, "Ctrl-scrolling shouldn't scroll while the user is touching the touchpad");
|
is(scrollbox.scrollTop, scrollTopBefore, "Ctrl-scrolling shouldn't scroll while the user is touching the touchpad");
|
||||||
} else {
|
} else {
|
||||||
is(winUtils.fullZoom, zoomFactorBefore, "Momentum scrolling shouldn't zoom, even when pressing Ctrl");
|
is(winUtils.fullZoom, zoomFactorBefore, "Momentum scrolling shouldn't zoom, even when pressing Ctrl");
|
||||||
is(scrollbox.scrollTop, scrollTopBefore + kDelta * (kExtraEvents + 1),
|
is(scrollbox.scrollTop, scrollTopBefore + kDelta * 2,
|
||||||
"Momentum scrolling should scroll, even when pressing Ctrl");
|
"Momentum scrolling should scroll, even when pressing Ctrl");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2653,14 +2653,6 @@ nsresult nsGenericHTMLElement::NewURIFromString(const nsAString& aURISpec,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/#being-rendered
|
|
||||||
//
|
|
||||||
// With a gotcha for display contents:
|
|
||||||
// https://github.com/whatwg/html/issues/3947
|
|
||||||
static bool IsRendered(const Element& aElement) {
|
|
||||||
return aElement.GetPrimaryFrame() || aElement.IsDisplayContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsGenericHTMLElement::GetInnerText(mozilla::dom::DOMString& aValue,
|
void nsGenericHTMLElement::GetInnerText(mozilla::dom::DOMString& aValue,
|
||||||
mozilla::ErrorResult& aError) {
|
mozilla::ErrorResult& aError) {
|
||||||
// innerText depends on layout. For example, white space processing is
|
// innerText depends on layout. For example, white space processing is
|
||||||
|
@ -2715,7 +2707,7 @@ void nsGenericHTMLElement::GetInnerText(mozilla::dom::DOMString& aValue,
|
||||||
doc->FlushPendingNotifications(FlushType::Layout);
|
doc->FlushPendingNotifications(FlushType::Layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsRendered(*this)) {
|
if (!IsRendered()) {
|
||||||
GetTextContentInternal(aValue, aError);
|
GetTextContentInternal(aValue, aError);
|
||||||
} else {
|
} else {
|
||||||
nsRange::GetInnerTextNoFlush(aValue, aError, this);
|
nsRange::GetInnerTextNoFlush(aValue, aError, this);
|
||||||
|
|
|
@ -106,6 +106,14 @@ BrowsingContext* JSWindowActorChild::GetBrowsingContext(ErrorResult& aRv) {
|
||||||
return mManager->BrowsingContext();
|
return mManager->BrowsingContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIDocShell* JSWindowActorChild::GetDocShell(ErrorResult& aRv) {
|
||||||
|
if (BrowsingContext* bc = GetBrowsingContext(aRv)) {
|
||||||
|
return bc->GetDocShell();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Nullable<WindowProxyHolder> JSWindowActorChild::GetContentWindow(
|
Nullable<WindowProxyHolder> JSWindowActorChild::GetContentWindow(
|
||||||
ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
if (BrowsingContext* bc = GetBrowsingContext(aRv)) {
|
if (BrowsingContext* bc = GetBrowsingContext(aRv)) {
|
||||||
|
|
|
@ -51,6 +51,7 @@ class JSWindowActorChild final : public JSWindowActor {
|
||||||
void AfterDestroy();
|
void AfterDestroy();
|
||||||
Document* GetDocument(ErrorResult& aRv);
|
Document* GetDocument(ErrorResult& aRv);
|
||||||
BrowsingContext* GetBrowsingContext(ErrorResult& aRv);
|
BrowsingContext* GetBrowsingContext(ErrorResult& aRv);
|
||||||
|
nsIDocShell* GetDocShell(ErrorResult& aRv);
|
||||||
Nullable<WindowProxyHolder> GetContentWindow(ErrorResult& aRv);
|
Nullable<WindowProxyHolder> GetContentWindow(ErrorResult& aRv);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -7,7 +7,5 @@ support-files =
|
||||||
[browser_domainPolicy.js]
|
[browser_domainPolicy.js]
|
||||||
[browser_memory_distribution_telemetry.js]
|
[browser_memory_distribution_telemetry.js]
|
||||||
skip-if = !e10 # This is an e10s only probe.
|
skip-if = !e10 # This is an e10s only probe.
|
||||||
[browser_remote_navigation_delay_telemetry.js]
|
|
||||||
skip-if = !e10s # This is an e10s only probe.
|
|
||||||
[browser_cancel_content_js.js]
|
[browser_cancel_content_js.js]
|
||||||
skip-if = !e10s # This is an e10s only probe.
|
skip-if = !e10s # This is an e10s only probe.
|
|
@ -1,48 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var session = ChromeUtils.import("resource://gre/modules/TelemetrySession.jsm", null);
|
|
||||||
|
|
||||||
add_task(async function test_memory_distribution() {
|
|
||||||
if (Services.prefs.getIntPref("dom.ipc.processCount", 1) < 2) {
|
|
||||||
ok(true, "Skip this test if e10s-multi is disabled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let canRecordExtended = Services.telemetry.canRecordExtended;
|
|
||||||
Services.telemetry.canRecordExtended = true;
|
|
||||||
registerCleanupFunction(() => Services.telemetry.canRecordExtended = canRecordExtended);
|
|
||||||
|
|
||||||
Services.telemetry.getSnapshotForKeyedHistograms("main", true /* clear */);
|
|
||||||
|
|
||||||
// Open a remote page in a new tab to trigger the WebNavigation:LoadURI.
|
|
||||||
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com");
|
|
||||||
ok(tab1.linkedBrowser.isRemoteBrowser, "|tab1| should have a remote browser.");
|
|
||||||
|
|
||||||
// Open a new tab with about:robots, so it ends up in the parent process with a non-remote browser.
|
|
||||||
let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:robots");
|
|
||||||
ok(!tab2.linkedBrowser.isRemoteBrowser, "|tab2| should have a non-remote browser.");
|
|
||||||
// Navigate the tab, so it will change remotness and it triggers the SessionStore:restoreTabContent case.
|
|
||||||
await BrowserTestUtils.loadURI(tab2.linkedBrowser, "http://example.com");
|
|
||||||
ok(tab2.linkedBrowser.isRemoteBrowser, "|tab2| should have a remote browser by now.");
|
|
||||||
|
|
||||||
// There is no good way to make sure that the parent received the histogram entries from the child processes.
|
|
||||||
// Let's stick to the ugly, spinning the event loop until we have a good approach (Bug 1357509).
|
|
||||||
await BrowserTestUtils.waitForCondition(() => {
|
|
||||||
let s = Services.telemetry.getSnapshotForKeyedHistograms("main", false).content.FX_TAB_REMOTE_NAVIGATION_DELAY_MS;
|
|
||||||
return s && "WebNavigation:LoadURI" in s && "SessionStore:restoreTabContent" in s;
|
|
||||||
});
|
|
||||||
|
|
||||||
let s = Services.telemetry.getSnapshotForKeyedHistograms("main", false).content.FX_TAB_REMOTE_NAVIGATION_DELAY_MS;
|
|
||||||
let restoreTabSnapshot = s["SessionStore:restoreTabContent"];
|
|
||||||
ok(restoreTabSnapshot.sum > 0, "Zero delay for the restoreTabContent case is unlikely.");
|
|
||||||
ok(restoreTabSnapshot.sum < 10000, "More than 10 seconds delay for the restoreTabContent case is unlikely.");
|
|
||||||
|
|
||||||
let loadURISnapshot = s["WebNavigation:LoadURI"];
|
|
||||||
ok(loadURISnapshot.sum > 0, "Zero delay for the LoadURI case is unlikely.");
|
|
||||||
ok(loadURISnapshot.sum < 10000, "More than 10 seconds delay for the LoadURI case is unlikely.");
|
|
||||||
|
|
||||||
Services.telemetry.getSnapshotForKeyedHistograms("main", true /* clear */);
|
|
||||||
|
|
||||||
BrowserTestUtils.removeTab(tab2);
|
|
||||||
BrowserTestUtils.removeTab(tab1);
|
|
||||||
});
|
|
|
@ -424,14 +424,16 @@ void cubeb_mock_stream_destroy(cubeb_stream* stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static char const* cubeb_mock_get_backend_id(cubeb* context) {
|
static char const* cubeb_mock_get_backend_id(cubeb* context) {
|
||||||
#if defined(XP_LINUX)
|
#if defined(XP_MACOSX)
|
||||||
return "pulse";
|
|
||||||
#elif defined(XP_MACOSX)
|
|
||||||
return "audiounit";
|
return "audiounit";
|
||||||
#elif defined(XP_WIN)
|
#elif defined(XP_WIN)
|
||||||
return "wasapi";
|
return "wasapi";
|
||||||
#elif defined(ANDROID)
|
#elif defined(ANDROID)
|
||||||
return "opensl";
|
return "opensl";
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
return "sndio";
|
||||||
|
#else
|
||||||
|
return "pulse";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -516,8 +516,8 @@ bool SMILCSSValueType::SetPropertyValues(const SMILValue& aValue,
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
for (const auto& value : wrapper->mServoValues) {
|
for (const auto& value : wrapper->mServoValues) {
|
||||||
changed |=
|
changed |= Servo_DeclarationBlock_SetPropertyToAnimationValue(aDecl.Raw(),
|
||||||
Servo_DeclarationBlock_SetPropertyToAnimationValue(aDecl.Raw(), value);
|
value, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
|
|
|
@ -12,7 +12,9 @@
|
||||||
|
|
||||||
enum AnimationPlayState { "idle", "running", "paused", "finished" };
|
enum AnimationPlayState { "idle", "running", "paused", "finished" };
|
||||||
|
|
||||||
[Constructor (optional AnimationEffect? effect = null,
|
enum AnimationReplaceState { "active", "removed", "persisted" };
|
||||||
|
|
||||||
|
[Constructor(optional AnimationEffect? effect = null,
|
||||||
optional AnimationTimeline? timeline)]
|
optional AnimationTimeline? timeline)]
|
||||||
interface Animation : EventTarget {
|
interface Animation : EventTarget {
|
||||||
attribute DOMString id;
|
attribute DOMString id;
|
||||||
|
@ -30,22 +32,30 @@ interface Animation : EventTarget {
|
||||||
readonly attribute AnimationPlayState playState;
|
readonly attribute AnimationPlayState playState;
|
||||||
[BinaryName="pendingFromJS"]
|
[BinaryName="pendingFromJS"]
|
||||||
readonly attribute boolean pending;
|
readonly attribute boolean pending;
|
||||||
|
[Pref="dom.animations-api.autoremove.enabled"]
|
||||||
|
readonly attribute AnimationReplaceState replaceState;
|
||||||
[Func="Document::IsWebAnimationsEnabled", Throws]
|
[Func="Document::IsWebAnimationsEnabled", Throws]
|
||||||
readonly attribute Promise<Animation> ready;
|
readonly attribute Promise<Animation> ready;
|
||||||
[Func="Document::IsWebAnimationsEnabled", Throws]
|
[Func="Document::IsWebAnimationsEnabled", Throws]
|
||||||
readonly attribute Promise<Animation> finished;
|
readonly attribute Promise<Animation> finished;
|
||||||
attribute EventHandler onfinish;
|
attribute EventHandler onfinish;
|
||||||
attribute EventHandler oncancel;
|
attribute EventHandler oncancel;
|
||||||
void cancel ();
|
[Pref="dom.animations-api.autoremove.enabled"]
|
||||||
|
attribute EventHandler onremove;
|
||||||
|
void cancel();
|
||||||
[Throws]
|
[Throws]
|
||||||
void finish ();
|
void finish();
|
||||||
[Throws, BinaryName="playFromJS"]
|
[Throws, BinaryName="playFromJS"]
|
||||||
void play ();
|
void play();
|
||||||
[Throws, BinaryName="pauseFromJS"]
|
[Throws, BinaryName="pauseFromJS"]
|
||||||
void pause ();
|
void pause();
|
||||||
void updatePlaybackRate (double playbackRate);
|
void updatePlaybackRate (double playbackRate);
|
||||||
[Throws]
|
[Throws]
|
||||||
void reverse ();
|
void reverse();
|
||||||
|
[Pref="dom.animations-api.autoremove.enabled"]
|
||||||
|
void persist();
|
||||||
|
[Pref="dom.animations-api.autoremove.enabled", Throws]
|
||||||
|
void commitStyles();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Non-standard extensions
|
// Non-standard extensions
|
||||||
|
|
|
@ -15,6 +15,6 @@ dictionary DocumentTimelineOptions {
|
||||||
};
|
};
|
||||||
|
|
||||||
[Func="Document::AreWebAnimationsTimelinesEnabled",
|
[Func="Document::AreWebAnimationsTimelinesEnabled",
|
||||||
Constructor (optional DocumentTimelineOptions options)]
|
Constructor(optional DocumentTimelineOptions options)]
|
||||||
interface DocumentTimeline : AnimationTimeline {
|
interface DocumentTimeline : AnimationTimeline {
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,18 +24,18 @@ dictionary KeyframeEffectOptions : EffectTiming {
|
||||||
// processing on the `keyframes` object.
|
// processing on the `keyframes` object.
|
||||||
[Func="Document::IsWebAnimationsEnabled",
|
[Func="Document::IsWebAnimationsEnabled",
|
||||||
RunConstructorInCallerCompartment,
|
RunConstructorInCallerCompartment,
|
||||||
Constructor ((Element or CSSPseudoElement)? target,
|
Constructor((Element or CSSPseudoElement)? target,
|
||||||
object? keyframes,
|
object? keyframes,
|
||||||
optional (unrestricted double or KeyframeEffectOptions) options),
|
optional (unrestricted double or KeyframeEffectOptions) options),
|
||||||
Constructor (KeyframeEffect source)]
|
Constructor(KeyframeEffect source)]
|
||||||
interface KeyframeEffect : AnimationEffect {
|
interface KeyframeEffect : AnimationEffect {
|
||||||
attribute (Element or CSSPseudoElement)? target;
|
attribute (Element or CSSPseudoElement)? target;
|
||||||
[Pref="dom.animations-api.compositing.enabled"]
|
[Pref="dom.animations-api.compositing.enabled"]
|
||||||
attribute IterationCompositeOperation iterationComposite;
|
attribute IterationCompositeOperation iterationComposite;
|
||||||
[Pref="dom.animations-api.compositing.enabled"]
|
[Pref="dom.animations-api.compositing.enabled"]
|
||||||
attribute CompositeOperation composite;
|
attribute CompositeOperation composite;
|
||||||
[Throws] sequence<object> getKeyframes ();
|
[Throws] sequence<object> getKeyframes();
|
||||||
[Throws] void setKeyframes (object? keyframes);
|
[Throws] void setKeyframes(object? keyframes);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Non-standard extensions
|
// Non-standard extensions
|
||||||
|
|
|
@ -260,7 +260,7 @@ class MOZ_RAII JS_PUBLIC_API AutoDebuggerJobQueueInterruption {
|
||||||
enum class PromiseRejectionHandlingState { Unhandled, Handled };
|
enum class PromiseRejectionHandlingState { Unhandled, Handled };
|
||||||
|
|
||||||
typedef void (*PromiseRejectionTrackerCallback)(
|
typedef void (*PromiseRejectionTrackerCallback)(
|
||||||
JSContext* cx, JS::HandleObject promise,
|
JSContext* cx, bool mutedErrors, JS::HandleObject promise,
|
||||||
JS::PromiseRejectionHandlingState state, void* data);
|
JS::PromiseRejectionHandlingState state, void* data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1137,7 +1137,7 @@ static bool TrackUnhandledRejections(JSContext* cx, JS::HandleObject promise,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ForwardingPromiseRejectionTrackerCallback(
|
static void ForwardingPromiseRejectionTrackerCallback(
|
||||||
JSContext* cx, JS::HandleObject promise,
|
JSContext* cx, bool mutedErrors, JS::HandleObject promise,
|
||||||
JS::PromiseRejectionHandlingState state, void* data) {
|
JS::PromiseRejectionHandlingState state, void* data) {
|
||||||
AutoReportException are(cx);
|
AutoReportException are(cx);
|
||||||
|
|
||||||
|
|
|
@ -637,9 +637,15 @@ void JSRuntime::addUnhandledRejectedPromise(JSContext* cx,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mutedErrors = false;
|
||||||
|
if (JSScript* script = cx->currentScript()) {
|
||||||
|
mutedErrors = script->mutedErrors();
|
||||||
|
}
|
||||||
|
|
||||||
void* data = cx->promiseRejectionTrackerCallbackData;
|
void* data = cx->promiseRejectionTrackerCallbackData;
|
||||||
cx->promiseRejectionTrackerCallback(
|
cx->promiseRejectionTrackerCallback(
|
||||||
cx, promise, JS::PromiseRejectionHandlingState::Unhandled, data);
|
cx, mutedErrors, promise, JS::PromiseRejectionHandlingState::Unhandled,
|
||||||
|
data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JSRuntime::removeUnhandledRejectedPromise(JSContext* cx,
|
void JSRuntime::removeUnhandledRejectedPromise(JSContext* cx,
|
||||||
|
@ -649,9 +655,15 @@ void JSRuntime::removeUnhandledRejectedPromise(JSContext* cx,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mutedErrors = false;
|
||||||
|
if (JSScript* script = cx->currentScript()) {
|
||||||
|
mutedErrors = script->mutedErrors();
|
||||||
|
}
|
||||||
|
|
||||||
void* data = cx->promiseRejectionTrackerCallbackData;
|
void* data = cx->promiseRejectionTrackerCallbackData;
|
||||||
cx->promiseRejectionTrackerCallback(
|
cx->promiseRejectionTrackerCallback(
|
||||||
cx, promise, JS::PromiseRejectionHandlingState::Handled, data);
|
cx, mutedErrors, promise, JS::PromiseRejectionHandlingState::Handled,
|
||||||
|
data);
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::non_crypto::XorShift128PlusRNG& JSRuntime::randomKeyGenerator() {
|
mozilla::non_crypto::XorShift128PlusRNG& JSRuntime::randomKeyGenerator() {
|
||||||
|
|
|
@ -225,6 +225,10 @@ static ContentMap& GetContentMap() {
|
||||||
template <typename TestType>
|
template <typename TestType>
|
||||||
static bool HasMatchingAnimations(EffectSet& aEffects, TestType&& aTest) {
|
static bool HasMatchingAnimations(EffectSet& aEffects, TestType&& aTest) {
|
||||||
for (KeyframeEffect* effect : aEffects) {
|
for (KeyframeEffect* effect : aEffects) {
|
||||||
|
if (!effect->GetAnimation() || !effect->GetAnimation()->IsRelevant()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (aTest(*effect, aEffects)) {
|
if (aTest(*effect, aEffects)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -263,8 +267,7 @@ bool nsLayoutUtils::HasAnimationOfPropertySet(
|
||||||
return HasMatchingAnimations(
|
return HasMatchingAnimations(
|
||||||
aFrame, aPropertySet,
|
aFrame, aPropertySet,
|
||||||
[&aPropertySet](KeyframeEffect& aEffect, const EffectSet&) {
|
[&aPropertySet](KeyframeEffect& aEffect, const EffectSet&) {
|
||||||
return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
|
return aEffect.HasAnimationOfPropertySet(aPropertySet);
|
||||||
aEffect.HasAnimationOfPropertySet(aPropertySet);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,8 +297,7 @@ bool nsLayoutUtils::HasAnimationOfPropertySet(
|
||||||
return HasMatchingAnimations(
|
return HasMatchingAnimations(
|
||||||
*aEffectSet,
|
*aEffectSet,
|
||||||
[&aPropertySet](KeyframeEffect& aEffect, const EffectSet& aEffectSet) {
|
[&aPropertySet](KeyframeEffect& aEffect, const EffectSet& aEffectSet) {
|
||||||
return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
|
return aEffect.HasAnimationOfPropertySet(aPropertySet);
|
||||||
aEffect.HasAnimationOfPropertySet(aPropertySet);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,8 +307,7 @@ bool nsLayoutUtils::HasEffectiveAnimation(
|
||||||
return HasMatchingAnimations(
|
return HasMatchingAnimations(
|
||||||
aFrame, aPropertySet,
|
aFrame, aPropertySet,
|
||||||
[&aPropertySet](KeyframeEffect& aEffect, const EffectSet& aEffectSet) {
|
[&aPropertySet](KeyframeEffect& aEffect, const EffectSet& aEffectSet) {
|
||||||
return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
|
return aEffect.HasEffectiveAnimationOfPropertySet(aPropertySet,
|
||||||
aEffect.HasEffectiveAnimationOfPropertySet(aPropertySet,
|
|
||||||
aEffectSet);
|
aEffectSet);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "nsComponentManagerUtils.h"
|
#include "nsComponentManagerUtils.h"
|
||||||
#include "mozilla/Logging.h"
|
#include "mozilla/Logging.h"
|
||||||
#include "mozilla/dom/Document.h"
|
#include "mozilla/dom/Document.h"
|
||||||
|
#include "mozilla/dom/DocumentInlines.h"
|
||||||
#include "nsIXULRuntime.h"
|
#include "nsIXULRuntime.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
@ -1747,6 +1748,16 @@ void nsRefreshDriver::CancelIdleRunnable(nsIRunnable* aRunnable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ReduceAnimations(Document* aDocument, void* aData) {
|
||||||
|
if (aDocument->GetPresContext() &&
|
||||||
|
aDocument->GetPresContext()->EffectCompositor()->NeedsReducing()) {
|
||||||
|
aDocument->GetPresContext()->EffectCompositor()->ReduceAnimations();
|
||||||
|
}
|
||||||
|
aDocument->EnumerateSubDocuments(ReduceAnimations, nullptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime) {
|
void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime) {
|
||||||
MOZ_ASSERT(!nsContentUtils::GetCurrentJSContext(),
|
MOZ_ASSERT(!nsContentUtils::GetCurrentJSContext(),
|
||||||
"Shouldn't have a JSContext on the stack");
|
"Shouldn't have a JSContext on the stack");
|
||||||
|
@ -1897,6 +1908,28 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Any animation timelines updated above may cause animations to queue
|
||||||
|
// Promise resolution microtasks. We shouldn't run these, however, until we
|
||||||
|
// have fully updated the animation state.
|
||||||
|
//
|
||||||
|
// As per the "update animations and send events" procedure[1], we should
|
||||||
|
// remove replaced animations and then run these microtasks before
|
||||||
|
// dispatching the corresponding animation events.
|
||||||
|
//
|
||||||
|
// [1]
|
||||||
|
// https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events
|
||||||
|
if (i == 1) {
|
||||||
|
nsAutoMicroTask mt;
|
||||||
|
ReduceAnimations(mPresContext->Document(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if running the microtask checkpoint caused the pres context to
|
||||||
|
// be destroyed.
|
||||||
|
if (i == 1 && (!mPresContext || !mPresContext->GetPresShell())) {
|
||||||
|
StopTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
// This is the FlushType::Style case.
|
// This is the FlushType::Style case.
|
||||||
|
|
||||||
|
|
|
@ -2747,8 +2747,8 @@ nsresult nsFrameSelection::UpdateSelectionCacheOnRepaintSelection(
|
||||||
nsCOMPtr<Document> aDoc = presShell->GetDocument();
|
nsCOMPtr<Document> aDoc = presShell->GetDocument();
|
||||||
|
|
||||||
if (aDoc && aSel && !aSel->IsCollapsed()) {
|
if (aDoc && aSel && !aSel->IsCollapsed()) {
|
||||||
return nsCopySupport::HTMLCopy(aSel, aDoc, nsIClipboard::kSelectionCache,
|
return nsCopySupport::EncodeDocumentWithContextAndPutToClipboard(
|
||||||
false);
|
aSel, aDoc, nsIClipboard::kSelectionCache, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -2762,8 +2762,9 @@ int16_t AutoCopyListener::sClipboardID = -1;
|
||||||
* What we do now:
|
* What we do now:
|
||||||
* On every selection change, we copy to the clipboard anew, creating a
|
* On every selection change, we copy to the clipboard anew, creating a
|
||||||
* HTML buffer, a transferable, an nsISupportsString and
|
* HTML buffer, a transferable, an nsISupportsString and
|
||||||
* a huge mess every time. This is basically what nsCopySupport::HTMLCopy()
|
* a huge mess every time. This is basically what
|
||||||
* does to move the selection into the clipboard for Edit->Copy.
|
* nsCopySupport::EncodeDocumentWithContextAndPutToClipboard() does to move the
|
||||||
|
* selection into the clipboard for Edit->Copy.
|
||||||
*
|
*
|
||||||
* What we should do, to make our end of the deal faster:
|
* What we should do, to make our end of the deal faster:
|
||||||
* Create a singleton transferable with our own magic converter. When selection
|
* Create a singleton transferable with our own magic converter. When selection
|
||||||
|
@ -2830,8 +2831,10 @@ void AutoCopyListener::OnSelectionChange(Document* aDocument,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the copy code.
|
|
||||||
DebugOnly<nsresult> rv =
|
DebugOnly<nsresult> rv =
|
||||||
nsCopySupport::HTMLCopy(&aSelection, aDocument, sClipboardID, false);
|
nsCopySupport::EncodeDocumentWithContextAndPutToClipboard(
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "nsCopySupport::HTMLCopy() failed");
|
&aSelection, aDocument, sClipboardID, false);
|
||||||
|
NS_WARNING_ASSERTION(
|
||||||
|
NS_SUCCEEDED(rv),
|
||||||
|
"nsCopySupport::EncodeDocumentWithContextAndPutToClipboard() failed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,8 +173,6 @@ SERVO_ARC_TYPE(ComputedStyle, mozilla::ComputedStyle)
|
||||||
|
|
||||||
// Other special cases.
|
// Other special cases.
|
||||||
|
|
||||||
// TODO(heycam): Handle these elsewhere.
|
|
||||||
struct RawServoAnimationValueTable;
|
struct RawServoAnimationValueTable;
|
||||||
struct RawServoAnimationValueMap;
|
|
||||||
|
|
||||||
#endif // mozilla_ServoBindingTypes_h
|
#endif // mozilla_ServoBindingTypes_h
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
// to just generate the forward declaration.
|
// to just generate the forward declaration.
|
||||||
|
|
||||||
SERVO_BOXED_TYPE(StyleSet, RawServoStyleSet)
|
SERVO_BOXED_TYPE(StyleSet, RawServoStyleSet)
|
||||||
|
SERVO_BOXED_TYPE(AnimationValueMap, RawServoAnimationValueMap)
|
||||||
SERVO_BOXED_TYPE(AuthorStyles, RawServoAuthorStyles)
|
SERVO_BOXED_TYPE(AuthorStyles, RawServoAuthorStyles)
|
||||||
SERVO_BOXED_TYPE(SelectorList, RawServoSelectorList)
|
SERVO_BOXED_TYPE(SelectorList, RawServoSelectorList)
|
||||||
SERVO_BOXED_TYPE(SharedMemoryBuilder, RawServoSharedMemoryBuilder)
|
SERVO_BOXED_TYPE(SharedMemoryBuilder, RawServoSharedMemoryBuilder)
|
||||||
|
|
|
@ -127,6 +127,19 @@ VARCACHE_PREF(
|
||||||
// DOM prefs
|
// DOM prefs
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Is support for automatically removing replaced filling animations enabled?
|
||||||
|
#ifdef RELEASE_OR_BETA
|
||||||
|
# define PREF_VALUE false
|
||||||
|
#else
|
||||||
|
# define PREF_VALUE true
|
||||||
|
#endif
|
||||||
|
VARCACHE_PREF(
|
||||||
|
"dom.animations-api.autoremove.enabled",
|
||||||
|
dom_animations_api_autoremove_enabled,
|
||||||
|
bool, PREF_VALUE
|
||||||
|
)
|
||||||
|
#undef PREF_VALUE
|
||||||
|
|
||||||
// Is support for composite operations from the Web Animations API enabled?
|
// Is support for composite operations from the Web Animations API enabled?
|
||||||
#ifdef RELEASE_OR_BETA
|
#ifdef RELEASE_OR_BETA
|
||||||
# define PREF_VALUE false
|
# define PREF_VALUE false
|
||||||
|
|
|
@ -1622,6 +1622,9 @@ pref("network.protocol-handler.external.hcp", false);
|
||||||
pref("network.protocol-handler.external.vbscript", false);
|
pref("network.protocol-handler.external.vbscript", false);
|
||||||
pref("network.protocol-handler.external.javascript", false);
|
pref("network.protocol-handler.external.javascript", false);
|
||||||
pref("network.protocol-handler.external.data", false);
|
pref("network.protocol-handler.external.data", false);
|
||||||
|
pref("network.protocol-handler.external.ie.http", false);
|
||||||
|
pref("network.protocol-handler.external.iehistory", false);
|
||||||
|
pref("network.protocol-handler.external.ierss", false);
|
||||||
pref("network.protocol-handler.external.ms-help", false);
|
pref("network.protocol-handler.external.ms-help", false);
|
||||||
pref("network.protocol-handler.external.res", false);
|
pref("network.protocol-handler.external.res", false);
|
||||||
pref("network.protocol-handler.external.shell", false);
|
pref("network.protocol-handler.external.shell", false);
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
#include "PKCS11ModuleDB.h"
|
#include "PKCS11ModuleDB.h"
|
||||||
|
|
||||||
#include "ScopedNSSTypes.h"
|
#include "ScopedNSSTypes.h"
|
||||||
#include "mozilla/Telemetry.h"
|
|
||||||
#include "nsCRTGlue.h"
|
|
||||||
#include "nsIMutableArray.h"
|
#include "nsIMutableArray.h"
|
||||||
#include "nsNSSCertHelper.h"
|
#include "nsNSSCertHelper.h"
|
||||||
#include "nsNSSComponent.h"
|
#include "nsNSSComponent.h"
|
||||||
|
@ -63,32 +61,6 @@ PKCS11ModuleDB::DeleteModule(const nsAString& aModuleName) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a PKCS#11 module, determines an appropriate name to identify it for the
|
|
||||||
// purposes of gathering telemetry. For 3rd party PKCS#11 modules, this should
|
|
||||||
// be the name of the dynamic library that implements the module. For built-in
|
|
||||||
// NSS modules, it will be the common name of the module.
|
|
||||||
// Because the result will be used as a telemetry scalar key (which must be less
|
|
||||||
// than 70 characters), this function will also truncate the result if it
|
|
||||||
// exceeds this limit. (Note that unfortunately telemetry doesn't expose a way
|
|
||||||
// to programmatically query the scalar key length limit, so we have to
|
|
||||||
// hard-code the value here.)
|
|
||||||
void GetModuleNameForTelemetry(/*in*/ const SECMODModule* module,
|
|
||||||
/*out*/ nsString& result) {
|
|
||||||
result.Truncate();
|
|
||||||
if (module->dllName) {
|
|
||||||
result.AssignASCII(module->dllName);
|
|
||||||
int32_t separatorIndex = result.RFind(FILE_PATH_SEPARATOR);
|
|
||||||
if (separatorIndex != kNotFound) {
|
|
||||||
result = Substring(result, separatorIndex + 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.AssignASCII(module->commonName);
|
|
||||||
}
|
|
||||||
if (result.Length() >= 70) {
|
|
||||||
result.Truncate(69);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a new PKCS11 module to the user's profile.
|
// Add a new PKCS11 module to the user's profile.
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
PKCS11ModuleDB::AddModule(const nsAString& aModuleName,
|
PKCS11ModuleDB::AddModule(const nsAString& aModuleName,
|
||||||
|
@ -131,23 +103,6 @@ PKCS11ModuleDB::AddModule(const nsAString& aModuleName,
|
||||||
if (srv != SECSuccess) {
|
if (srv != SECSuccess) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
UniqueSECMODModule module(SECMOD_FindModule(moduleNameNormalized.get()));
|
|
||||||
if (!module) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString scalarKey;
|
|
||||||
GetModuleNameForTelemetry(module.get(), scalarKey);
|
|
||||||
// Scalar keys must be between 0 and 70 characters (exclusive).
|
|
||||||
// GetModuleNameForTelemetry takes care of keys that are too long.
|
|
||||||
// If for some reason it couldn't come up with an appropriate name and
|
|
||||||
// returned an empty result, however, we need to not attempt to record this
|
|
||||||
// (it wouldn't give us anything useful anyway).
|
|
||||||
if (scalarKey.Length() > 0) {
|
|
||||||
Telemetry::ScalarSet(Telemetry::ScalarID::SECURITY_PKCS11_MODULES_LOADED,
|
|
||||||
scalarKey, true);
|
|
||||||
}
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
#include "nsIPKCS11ModuleDB.h"
|
#include "nsIPKCS11ModuleDB.h"
|
||||||
|
|
||||||
#include "nsString.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace psm {
|
namespace psm {
|
||||||
|
|
||||||
|
@ -31,9 +29,6 @@ class PKCS11ModuleDB : public nsIPKCS11ModuleDB {
|
||||||
virtual ~PKCS11ModuleDB() {}
|
virtual ~PKCS11ModuleDB() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
void GetModuleNameForTelemetry(/*in*/ const SECMODModule* module,
|
|
||||||
/*out*/ nsString& result);
|
|
||||||
|
|
||||||
} // namespace psm
|
} // namespace psm
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include "EnterpriseRoots.h"
|
#include "EnterpriseRoots.h"
|
||||||
#include "ExtendedValidation.h"
|
#include "ExtendedValidation.h"
|
||||||
#include "NSSCertDBTrustDomain.h"
|
#include "NSSCertDBTrustDomain.h"
|
||||||
#include "PKCS11ModuleDB.h"
|
|
||||||
#include "ScopedNSSTypes.h"
|
#include "ScopedNSSTypes.h"
|
||||||
#include "SharedSSLState.h"
|
#include "SharedSSLState.h"
|
||||||
#include "cert.h"
|
#include "cert.h"
|
||||||
|
@ -1793,28 +1792,6 @@ nsresult nsNSSComponent::InitializeNSS() {
|
||||||
Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
|
Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gather telemetry on any PKCS#11 modules we have loaded. Note that because
|
|
||||||
// we load the built-in root module asynchronously after this, the telemetry
|
|
||||||
// will not include it.
|
|
||||||
{ // Introduce scope for the AutoSECMODListReadLock.
|
|
||||||
AutoSECMODListReadLock lock;
|
|
||||||
for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
|
|
||||||
list = list->next) {
|
|
||||||
nsAutoString scalarKey;
|
|
||||||
GetModuleNameForTelemetry(list->module, scalarKey);
|
|
||||||
// Scalar keys must be between 0 and 70 characters (exclusive).
|
|
||||||
// GetModuleNameForTelemetry takes care of keys that are too long. If for
|
|
||||||
// some reason it couldn't come up with an appropriate name and returned
|
|
||||||
// an empty result, however, we need to not attempt to record this (it
|
|
||||||
// wouldn't give us anything useful anyway).
|
|
||||||
if (scalarKey.Length() > 0) {
|
|
||||||
Telemetry::ScalarSet(
|
|
||||||
Telemetry::ScalarID::SECURITY_PKCS11_MODULES_LOADED, scalarKey,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization done\n"));
|
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization done\n"));
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,40 +50,13 @@ function checkTestModuleExists() {
|
||||||
return testModule;
|
return testModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkModuleTelemetry(additionalExpectedModule = undefined) {
|
|
||||||
let expectedModules = [
|
|
||||||
"NSS Internal PKCS #11 Module",
|
|
||||||
];
|
|
||||||
if (additionalExpectedModule) {
|
|
||||||
expectedModules.push(additionalExpectedModule);
|
|
||||||
}
|
|
||||||
expectedModules.sort();
|
|
||||||
let telemetry = Services.telemetry.getSnapshotForKeyedScalars("main", false).parent;
|
|
||||||
let moduleTelemetry = telemetry["security.pkcs11_modules_loaded"];
|
|
||||||
let actualModules = [];
|
|
||||||
Object.keys(moduleTelemetry).forEach((key) => {
|
|
||||||
ok(moduleTelemetry[key], "each keyed scalar should be true");
|
|
||||||
actualModules.push(key);
|
|
||||||
});
|
|
||||||
actualModules.sort();
|
|
||||||
equal(actualModules.length, expectedModules.length,
|
|
||||||
"the number of actual and expected loaded modules should be the same");
|
|
||||||
for (let i in actualModules) {
|
|
||||||
equal(actualModules[i], expectedModules[i],
|
|
||||||
"actual and expected module names should match");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
function run_test() {
|
||||||
// Check that if we have never added the test module, that we don't find it
|
// Check that if we have never added the test module, that we don't find it
|
||||||
// in the module list.
|
// in the module list.
|
||||||
checkTestModuleNotPresent();
|
checkTestModuleNotPresent();
|
||||||
checkModuleTelemetry();
|
|
||||||
|
|
||||||
// Check that adding the test module makes it appear in the module list.
|
// Check that adding the test module makes it appear in the module list.
|
||||||
loadPKCS11TestModule(true);
|
loadPKCS11TestModule(true);
|
||||||
checkModuleTelemetry(
|
|
||||||
`${AppConstants.DLL_PREFIX}pkcs11testmodule${AppConstants.DLL_SUFFIX}`);
|
|
||||||
let testModule = checkTestModuleExists();
|
let testModule = checkTestModuleExists();
|
||||||
|
|
||||||
// Check that listing the slots for the test module works.
|
// Check that listing the slots for the test module works.
|
||||||
|
|
|
@ -8,7 +8,7 @@ for (let [key, val] of Object.entries({
|
||||||
|
|
||||||
// Don't manually modify this line, as it is automatically replaced on merge day
|
// Don't manually modify this line, as it is automatically replaced on merge day
|
||||||
// by the gecko_migration.py script.
|
// by the gecko_migration.py script.
|
||||||
WEAVE_VERSION: "1.70.0",
|
WEAVE_VERSION: "1.71.0",
|
||||||
|
|
||||||
// Sync Server API version that the client supports.
|
// Sync Server API version that the client supports.
|
||||||
SYNC_API_VERSION: "1.5",
|
SYNC_API_VERSION: "1.5",
|
||||||
|
|
|
@ -5,12 +5,22 @@
|
||||||
//! FFI implementations for types listed in ServoBoxedTypeList.h.
|
//! FFI implementations for types listed in ServoBoxedTypeList.h.
|
||||||
|
|
||||||
use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
|
use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
|
||||||
|
use crate::properties::animated_properties::AnimationValueMap;
|
||||||
use to_shmem::SharedMemoryBuilder;
|
use to_shmem::SharedMemoryBuilder;
|
||||||
|
|
||||||
// TODO(heycam): The FFI impls for most of the types in ServoBoxedTypeList.h are spread across
|
// TODO(heycam): The FFI impls for most of the types in ServoBoxedTypeList.h are spread across
|
||||||
// various files at the moment, but should probably all move here, and use macros to define
|
// various files at the moment, but should probably all move here, and use macros to define
|
||||||
// them more succinctly, like we do in arc_types.rs.
|
// them more succinctly, like we do in arc_types.rs.
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
unsafe impl HasFFI for AnimationValueMap {
|
||||||
|
type FFIType = crate::gecko_bindings::bindings::RawServoAnimationValueMap;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
unsafe impl HasSimpleFFI for AnimationValueMap {}
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
unsafe impl HasBoxFFI for AnimationValueMap {}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
unsafe impl HasFFI for SharedMemoryBuilder {
|
unsafe impl HasFFI for SharedMemoryBuilder {
|
||||||
type FFIType = crate::gecko_bindings::bindings::RawServoSharedMemoryBuilder;
|
type FFIType = crate::gecko_bindings::bindings::RawServoSharedMemoryBuilder;
|
||||||
|
|
|
@ -9,9 +9,7 @@
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
%>
|
%>
|
||||||
|
|
||||||
#[cfg(feature = "gecko")] use crate::gecko_bindings::structs::RawServoAnimationValueMap;
|
|
||||||
#[cfg(feature = "gecko")] use crate::gecko_bindings::structs::nsCSSPropertyID;
|
#[cfg(feature = "gecko")] use crate::gecko_bindings::structs::nsCSSPropertyID;
|
||||||
#[cfg(feature = "gecko")] use crate::gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI};
|
|
||||||
use itertools::{EitherOrBoth, Itertools};
|
use itertools::{EitherOrBoth, Itertools};
|
||||||
use crate::properties::{CSSWideKeyword, PropertyDeclaration};
|
use crate::properties::{CSSWideKeyword, PropertyDeclaration};
|
||||||
use crate::properties::longhands;
|
use crate::properties::longhands;
|
||||||
|
@ -190,13 +188,6 @@ impl AnimatedProperty {
|
||||||
/// composed for each TransitionProperty.
|
/// composed for each TransitionProperty.
|
||||||
pub type AnimationValueMap = FxHashMap<LonghandId, AnimationValue>;
|
pub type AnimationValueMap = FxHashMap<LonghandId, AnimationValue>;
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
unsafe impl HasFFI for AnimationValueMap {
|
|
||||||
type FFIType = RawServoAnimationValueMap;
|
|
||||||
}
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
unsafe impl HasSimpleFFI for AnimationValueMap {}
|
|
||||||
|
|
||||||
/// An enum to represent a single computed value belonging to an animated
|
/// An enum to represent a single computed value belonging to an animated
|
||||||
/// property in order to be interpolated with another one. When interpolating,
|
/// property in order to be interpolated with another one. When interpolating,
|
||||||
/// both values need to belong to the same property.
|
/// both values need to belong to the same property.
|
||||||
|
|
|
@ -2337,6 +2337,14 @@ impl SourcePropertyDeclaration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create one with a single PropertyDeclaration.
|
||||||
|
#[inline]
|
||||||
|
pub fn with_one(decl: PropertyDeclaration) -> Self {
|
||||||
|
let mut result = Self::new();
|
||||||
|
result.declarations.push(decl);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/// Similar to Vec::drain: leaves this empty when the return value is dropped.
|
/// Similar to Vec::drain: leaves this empty when the return value is dropped.
|
||||||
pub fn drain(&mut self) -> SourcePropertyDeclarationDrain {
|
pub fn drain(&mut self) -> SourcePropertyDeclarationDrain {
|
||||||
SourcePropertyDeclarationDrain {
|
SourcePropertyDeclarationDrain {
|
||||||
|
|
|
@ -101,7 +101,7 @@ use style::global_style_data::{GlobalStyleData, GLOBAL_STYLE_DATA, STYLE_THREAD_
|
||||||
use style::invalidation::element::restyle_hints::RestyleHint;
|
use style::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use style::media_queries::MediaList;
|
use style::media_queries::MediaList;
|
||||||
use style::parser::{self, Parse, ParserContext};
|
use style::parser::{self, Parse, ParserContext};
|
||||||
use style::properties::animated_properties::AnimationValue;
|
use style::properties::animated_properties::{AnimationValue, AnimationValueMap};
|
||||||
use style::properties::{parse_one_declaration_into, parse_style_attribute};
|
use style::properties::{parse_one_declaration_into, parse_style_attribute};
|
||||||
use style::properties::{ComputedValues, Importance, NonCustomPropertyId};
|
use style::properties::{ComputedValues, Importance, NonCustomPropertyId};
|
||||||
use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId};
|
use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId};
|
||||||
|
@ -913,6 +913,36 @@ fn resolve_rules_for_element_with_context<'a>(
|
||||||
.0
|
.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn Servo_AnimationValueMap_Create() -> Owned<structs::RawServoAnimationValueMap> {
|
||||||
|
Box::<AnimationValueMap>::default().into_ffi()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(value_map: *mut structs::RawServoAnimationValueMap) {
|
||||||
|
AnimationValueMap::drop_ffi(value_map)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn Servo_AnimationValueMap_GetValue(
|
||||||
|
raw_value_map: &mut structs::RawServoAnimationValueMap,
|
||||||
|
property_id: nsCSSPropertyID,
|
||||||
|
) -> Strong<RawServoAnimationValue> {
|
||||||
|
use style::properties::animated_properties::AnimationValueMap;
|
||||||
|
|
||||||
|
let property = match LonghandId::from_nscsspropertyid(property_id) {
|
||||||
|
Ok(longhand) => longhand,
|
||||||
|
Err(()) => return Strong::null(),
|
||||||
|
};
|
||||||
|
let value_map = AnimationValueMap::from_ffi_mut(raw_value_map);
|
||||||
|
|
||||||
|
value_map
|
||||||
|
.get(&property)
|
||||||
|
.map_or(Strong::null(), |value| {
|
||||||
|
Arc::new(value.clone()).into_strong()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
|
pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
|
||||||
raw_style_set: &RawServoStyleSet,
|
raw_style_set: &RawServoStyleSet,
|
||||||
|
@ -4091,6 +4121,28 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn set_property_to_declarations(
|
||||||
|
block: &RawServoDeclarationBlock,
|
||||||
|
parsed_declarations: &mut SourcePropertyDeclaration,
|
||||||
|
before_change_closure: DeclarationBlockMutationClosure,
|
||||||
|
importance: Importance,
|
||||||
|
) -> bool {
|
||||||
|
let mut updates = Default::default();
|
||||||
|
let will_change = read_locked_arc(block, |decls: &PropertyDeclarationBlock| {
|
||||||
|
decls.prepare_for_update(&parsed_declarations, importance, &mut updates)
|
||||||
|
});
|
||||||
|
if !will_change {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
before_change_closure.invoke();
|
||||||
|
write_locked_arc(block, |decls: &mut PropertyDeclarationBlock| {
|
||||||
|
decls.update(parsed_declarations.drain(), importance, &mut updates)
|
||||||
|
});
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn set_property(
|
fn set_property(
|
||||||
declarations: &RawServoDeclarationBlock,
|
declarations: &RawServoDeclarationBlock,
|
||||||
property_id: PropertyId,
|
property_id: PropertyId,
|
||||||
|
@ -4123,19 +4175,13 @@ fn set_property(
|
||||||
} else {
|
} else {
|
||||||
Importance::Normal
|
Importance::Normal
|
||||||
};
|
};
|
||||||
let mut updates = Default::default();
|
|
||||||
let will_change = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
|
|
||||||
decls.prepare_for_update(&source_declarations, importance, &mut updates)
|
|
||||||
});
|
|
||||||
if !will_change {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
before_change_closure.invoke();
|
set_property_to_declarations(
|
||||||
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
|
declarations,
|
||||||
decls.update(source_declarations.drain(), importance, &mut updates)
|
&mut source_declarations,
|
||||||
});
|
before_change_closure,
|
||||||
true
|
importance,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -4167,13 +4213,17 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
|
||||||
pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
|
pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
|
||||||
declarations: &RawServoDeclarationBlock,
|
declarations: &RawServoDeclarationBlock,
|
||||||
animation_value: &RawServoAnimationValue,
|
animation_value: &RawServoAnimationValue,
|
||||||
|
before_change_closure: DeclarationBlockMutationClosure,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
|
let mut source_declarations =
|
||||||
decls.push(
|
SourcePropertyDeclaration::with_one(AnimationValue::as_arc(&animation_value).uncompute());
|
||||||
AnimationValue::as_arc(&animation_value).uncompute(),
|
|
||||||
|
set_property_to_declarations(
|
||||||
|
declarations,
|
||||||
|
&mut source_declarations,
|
||||||
|
before_change_closure,
|
||||||
Importance::Normal,
|
Importance::Normal,
|
||||||
)
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -21,16 +21,12 @@ job-template:
|
||||||
attributes:
|
attributes:
|
||||||
artifact_prefix: public
|
artifact_prefix: public
|
||||||
artifact_map:
|
artifact_map:
|
||||||
by-project:
|
by-release-type:
|
||||||
|
beta|release.*|esr.*:
|
||||||
|
by-platform:
|
||||||
|
android.*: taskcluster/taskgraph/manifests/fennec_candidates_checksums.yml
|
||||||
|
default: taskcluster/taskgraph/manifests/firefox_candidates_checksums.yml
|
||||||
default:
|
default:
|
||||||
by-platform:
|
by-platform:
|
||||||
android.*: taskcluster/taskgraph/manifests/fennec_nightly_checksums.yml
|
android.*: taskcluster/taskgraph/manifests/fennec_nightly_checksums.yml
|
||||||
default: taskcluster/taskgraph/manifests/firefox_nightly_checksums.yml
|
default: taskcluster/taskgraph/manifests/firefox_nightly_checksums.yml
|
||||||
mozilla-beta:
|
|
||||||
by-platform:
|
|
||||||
android.*: taskcluster/taskgraph/manifests/fennec_candidates_checksums.yml
|
|
||||||
default: taskcluster/taskgraph/manifests/firefox_candidates_checksums.yml
|
|
||||||
mozilla-release:
|
|
||||||
by-platform:
|
|
||||||
android.*: taskcluster/taskgraph/manifests/fennec_candidates_checksums.yml
|
|
||||||
default: taskcluster/taskgraph/manifests/firefox_candidates_checksums.yml
|
|
||||||
|
|
|
@ -57,7 +57,6 @@ job-template:
|
||||||
shipping-phase: promote
|
shipping-phase: promote
|
||||||
attributes:
|
attributes:
|
||||||
artifact_map:
|
artifact_map:
|
||||||
by-project:
|
by-release-type:
|
||||||
|
beta|release.*|esr.*: taskcluster/taskgraph/manifests/firefox_candidates.yml
|
||||||
default: taskcluster/taskgraph/manifests/firefox_nightly.yml
|
default: taskcluster/taskgraph/manifests/firefox_nightly.yml
|
||||||
mozilla-beta: taskcluster/taskgraph/manifests/firefox_candidates.yml
|
|
||||||
mozilla-release: taskcluster/taskgraph/manifests/firefox_candidates.yml
|
|
||||||
|
|
|
@ -41,7 +41,6 @@ job-template:
|
||||||
shipping-phase: promote
|
shipping-phase: promote
|
||||||
attributes:
|
attributes:
|
||||||
artifact_map:
|
artifact_map:
|
||||||
by-project:
|
by-release-type:
|
||||||
mozilla-release: taskcluster/taskgraph/manifests/fennec_candidates.yml
|
beta|release.*|esr.*: taskcluster/taskgraph/manifests/fennec_candidates.yml
|
||||||
mozilla-beta: taskcluster/taskgraph/manifests/fennec_candidates.yml
|
|
||||||
default: taskcluster/taskgraph/manifests/fennec_nightly.yml
|
default: taskcluster/taskgraph/manifests/fennec_nightly.yml
|
||||||
|
|
|
@ -269,7 +269,7 @@ win32-shippable/opt:
|
||||||
by-release-type:
|
by-release-type:
|
||||||
nightly: true
|
nightly: true
|
||||||
beta: true
|
beta: true
|
||||||
release: true
|
release.*: true
|
||||||
esr.*: false
|
esr.*: false
|
||||||
default:
|
default:
|
||||||
by-project:
|
by-project:
|
||||||
|
@ -832,7 +832,7 @@ win32-devedition-nightly/opt:
|
||||||
by-release-type:
|
by-release-type:
|
||||||
nightly: true
|
nightly: true
|
||||||
beta: true
|
beta: true
|
||||||
release: true
|
release.*: true
|
||||||
default:
|
default:
|
||||||
by-project:
|
by-project:
|
||||||
# browser/confvars.sh looks for nightly-try
|
# browser/confvars.sh looks for nightly-try
|
||||||
|
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
- releases/bouncer_firefox_beta.py
|
- releases/bouncer_firefox_beta.py
|
||||||
release:
|
release:
|
||||||
- releases/bouncer_firefox_release.py
|
- releases/bouncer_firefox_release.py
|
||||||
esr60:
|
esr.*:
|
||||||
- releases/bouncer_firefox_esr.py
|
- releases/bouncer_firefox_esr.py
|
||||||
default:
|
default:
|
||||||
- releases/bouncer_firefox_beta.py
|
- releases/bouncer_firefox_beta.py
|
||||||
|
@ -51,6 +51,7 @@ jobs:
|
||||||
mozilla-beta: LATEST_FIREFOX_RELEASED_DEVEL_VERSION
|
mozilla-beta: LATEST_FIREFOX_RELEASED_DEVEL_VERSION
|
||||||
mozilla-release: LATEST_FIREFOX_VERSION
|
mozilla-release: LATEST_FIREFOX_VERSION
|
||||||
mozilla-esr60: FIREFOX_ESR
|
mozilla-esr60: FIREFOX_ESR
|
||||||
|
mozilla-esr68: FIREFOX_ESR_NEXT
|
||||||
default: LATEST_FIREFOX_DEVEL_VERSION
|
default: LATEST_FIREFOX_DEVEL_VERSION
|
||||||
products-url: https://product-details.mozilla.org/1.0/firefox_versions.json
|
products-url: https://product-details.mozilla.org/1.0/firefox_versions.json
|
||||||
treeherder:
|
treeherder:
|
||||||
|
|
|
@ -34,12 +34,14 @@ jobs:
|
||||||
beta: [32]
|
beta: [32]
|
||||||
release: [145]
|
release: [145]
|
||||||
esr60: [806]
|
esr60: [806]
|
||||||
|
esr68: [882]
|
||||||
default: []
|
default: []
|
||||||
staging:
|
staging:
|
||||||
by-release-type:
|
by-release-type:
|
||||||
beta: [32]
|
beta: [32]
|
||||||
release: [145]
|
release: [145]
|
||||||
esr60: [806]
|
esr60: [806]
|
||||||
|
esr68: [875]
|
||||||
default: []
|
default: []
|
||||||
treeherder:
|
treeherder:
|
||||||
platform: firefox-release/opt
|
platform: firefox-release/opt
|
||||||
|
@ -50,10 +52,13 @@ jobs:
|
||||||
description: Schedule Firefox publishing in balrog (bz2)
|
description: Schedule Firefox publishing in balrog (bz2)
|
||||||
name: release-firefox_schedule_publishing_in_balrog-bz2
|
name: release-firefox_schedule_publishing_in_balrog-bz2
|
||||||
shipping-product: firefox
|
shipping-product: firefox
|
||||||
run-on-releases: [esr60]
|
run-on-releases: [esr60, esr68]
|
||||||
worker:
|
worker:
|
||||||
product: firefox
|
product: firefox
|
||||||
publish-rules: [521]
|
publish-rules:
|
||||||
|
by-release-type:
|
||||||
|
esr60: [521]
|
||||||
|
default: []
|
||||||
blob-suffix: -bz2
|
blob-suffix: -bz2
|
||||||
treeherder:
|
treeherder:
|
||||||
platform: firefox-release/opt
|
platform: firefox-release/opt
|
||||||
|
|
|
@ -39,12 +39,13 @@ jobs:
|
||||||
by-release-type:
|
by-release-type:
|
||||||
beta: ["beta", "beta-localtest", "beta-cdntest"]
|
beta: ["beta", "beta-localtest", "beta-cdntest"]
|
||||||
release(-rc)?: ["release", "release-localtest", "release-cdntest"]
|
release(-rc)?: ["release", "release-localtest", "release-cdntest"]
|
||||||
esr60: ["esr", "esr-localtest", "esr-cdntest"]
|
esr.*: ["esr", "esr-localtest", "esr-cdntest", "esr-localtest-next", "esr-cdntest-next"]
|
||||||
default: []
|
default: []
|
||||||
rules-to-update:
|
rules-to-update:
|
||||||
by-release-type:
|
by-release-type:
|
||||||
beta: ["firefox-beta-cdntest", "firefox-beta-localtest"]
|
beta: ["firefox-beta-cdntest", "firefox-beta-localtest"]
|
||||||
release(-rc)?: ["firefox-release-cdntest", "firefox-release-localtest"]
|
release(-rc)?: ["firefox-release-cdntest", "firefox-release-localtest"]
|
||||||
|
esr68: ["firefox-esr68-cdntest", "firefox-esr68-localtest"]
|
||||||
esr60: ["firefox-esr60-cdntest", "firefox-esr60-localtest"]
|
esr60: ["firefox-esr60-cdntest", "firefox-esr60-localtest"]
|
||||||
default: []
|
default: []
|
||||||
platforms: ["linux", "linux64", "macosx64", "win32", "win64", "win64-aarch64"]
|
platforms: ["linux", "linux64", "macosx64", "win32", "win64", "win64-aarch64"]
|
||||||
|
@ -58,11 +59,14 @@ jobs:
|
||||||
name: submit-toplevel-firefox-release-to-balrog-bz2
|
name: submit-toplevel-firefox-release-to-balrog-bz2
|
||||||
description: Submit toplevel Firefox release to balrog
|
description: Submit toplevel Firefox release to balrog
|
||||||
shipping-product: firefox
|
shipping-product: firefox
|
||||||
run-on-releases: [esr60]
|
run-on-releases: [esr60, esr68]
|
||||||
worker:
|
worker:
|
||||||
product: firefox
|
product: firefox
|
||||||
channel-names: ["esr", "esr-localtest", "esr-cdntest"]
|
channel-names: ["esr", "esr-localtest", "esr-cdntest", "esr-localtest-next", "esr-cdntest-next"]
|
||||||
rules-to-update: ["esr52-cdntest", "esr52-localtest"]
|
rules-to-update:
|
||||||
|
by-release-type:
|
||||||
|
esr68: ["esr52-cdntest-next", "esr52-localtest-next"]
|
||||||
|
esr60: ["esr52-cdntest", "esr52-localtest"]
|
||||||
platforms: ["linux", "linux64", "macosx64", "win32", "win64"]
|
platforms: ["linux", "linux64", "macosx64", "win32", "win64"]
|
||||||
blob-suffix: -bz2
|
blob-suffix: -bz2
|
||||||
complete-mar-filename-pattern: '%s-%s.bz2.complete.mar'
|
complete-mar-filename-pattern: '%s-%s.bz2.complete.mar'
|
||||||
|
|
|
@ -79,6 +79,10 @@ jobs:
|
||||||
firefox-esr-latest-ssl: installer-ssl
|
firefox-esr-latest-ssl: installer-ssl
|
||||||
firefox-esr-latest: installer
|
firefox-esr-latest: installer
|
||||||
firefox-esr-msi-latest-ssl: msi
|
firefox-esr-msi-latest-ssl: msi
|
||||||
|
mozilla-esr68:
|
||||||
|
firefox-esr-next-latest-ssl: installer-ssl
|
||||||
|
firefox-esr-next-latest: installer
|
||||||
|
firefox-esr-next-msi-latest-ssl: msi
|
||||||
birch:
|
birch:
|
||||||
firefox-latest-ssl: installer-ssl
|
firefox-latest-ssl: installer-ssl
|
||||||
firefox-latest: installer
|
firefox-latest: installer
|
||||||
|
|
|
@ -57,7 +57,7 @@ jobs:
|
||||||
- releases/bouncer_firefox_beta.py
|
- releases/bouncer_firefox_beta.py
|
||||||
release:
|
release:
|
||||||
- releases/bouncer_firefox_release.py
|
- releases/bouncer_firefox_release.py
|
||||||
esr60:
|
esr.*:
|
||||||
- releases/bouncer_firefox_esr.py
|
- releases/bouncer_firefox_esr.py
|
||||||
default:
|
default:
|
||||||
- releases/bouncer_firefox_beta.py
|
- releases/bouncer_firefox_beta.py
|
||||||
|
|
|
@ -52,11 +52,11 @@ jobs:
|
||||||
firefox:
|
firefox:
|
||||||
bouncer-platforms: ['linux', 'linux64', 'osx', 'win', 'win64', 'win64-aarch64']
|
bouncer-platforms: ['linux', 'linux64', 'osx', 'win', 'win64', 'win64-aarch64']
|
||||||
bouncer-products:
|
bouncer-products:
|
||||||
by-project:
|
by-release-type:
|
||||||
default: ['complete-mar', 'installer', 'installer-ssl', 'partial-mar', 'stub-installer', 'msi']
|
default: ['complete-mar', 'installer', 'installer-ssl', 'partial-mar', 'stub-installer', 'msi']
|
||||||
|
esr68: ['complete-mar', 'complete-mar-bz2', 'installer', 'installer-ssl', 'partial-mar', 'msi']
|
||||||
# No stub installer in esr60
|
# No stub installer in esr60
|
||||||
mozilla-esr60: ['complete-mar', 'complete-mar-bz2', 'installer', 'installer-ssl', 'partial-mar']
|
esr60: ['complete-mar', 'complete-mar-bz2', 'installer', 'installer-ssl', 'partial-mar']
|
||||||
jamun: ['complete-mar', 'complete-mar-bz2', 'installer', 'installer-ssl', 'partial-mar']
|
|
||||||
shipping-product: firefox
|
shipping-product: firefox
|
||||||
treeherder:
|
treeherder:
|
||||||
platform: firefox-release/opt
|
platform: firefox-release/opt
|
||||||
|
|
|
@ -59,7 +59,7 @@ jobs:
|
||||||
firefox:
|
firefox:
|
||||||
shipping-product: firefox
|
shipping-product: firefox
|
||||||
attributes:
|
attributes:
|
||||||
build_platform: linux64-snap-shippable
|
build_platform: linux64-shippable
|
||||||
build_type: opt
|
build_type: opt
|
||||||
treeherder:
|
treeherder:
|
||||||
symbol: Snap(r)
|
symbol: Snap(r)
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
# 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/.
|
||||||
|
---
|
||||||
|
loader: taskgraph.loader.transform:loader
|
||||||
|
|
||||||
|
transforms:
|
||||||
|
- taskgraph.transforms.release:run_on_releases
|
||||||
|
- taskgraph.transforms.update_verify_config:transforms
|
||||||
|
- taskgraph.transforms.job:transforms
|
||||||
|
- taskgraph.transforms.task:transforms
|
||||||
|
|
||||||
|
job-defaults:
|
||||||
|
name: update-verify-config-next
|
||||||
|
run-on-projects: [] # to make sure this never runs as part of CI
|
||||||
|
run-on-releases: [esr68]
|
||||||
|
shipping-phase: promote
|
||||||
|
worker-type: b-linux
|
||||||
|
worker:
|
||||||
|
docker-image:
|
||||||
|
in-tree: "update-verify"
|
||||||
|
max-run-time: 3600
|
||||||
|
artifacts:
|
||||||
|
- name: public/build/update-verify.cfg
|
||||||
|
path: /builds/worker/checkouts/gecko/update-verify.cfg
|
||||||
|
type: file
|
||||||
|
run:
|
||||||
|
sparse-profile: mozharness
|
||||||
|
treeherder:
|
||||||
|
symbol: UVCnext
|
||||||
|
kind: test
|
||||||
|
tier: 1
|
||||||
|
extra:
|
||||||
|
app-name: browser
|
||||||
|
branch-prefix: mozilla
|
||||||
|
archive-prefix:
|
||||||
|
by-release-level:
|
||||||
|
staging: "http://ftp.stage.mozaws.net/pub"
|
||||||
|
production: "https://archive.mozilla.org/pub"
|
||||||
|
previous-archive-prefix:
|
||||||
|
by-release-level:
|
||||||
|
staging: "https://archive.mozilla.org/pub"
|
||||||
|
production: null
|
||||||
|
aus-server:
|
||||||
|
by-release-level:
|
||||||
|
staging: "https://stage.balrog.nonprod.cloudops.mozgcp.net"
|
||||||
|
production: "https://aus5.mozilla.org"
|
||||||
|
override-certs:
|
||||||
|
by-release-level:
|
||||||
|
staging: dep
|
||||||
|
production: null
|
||||||
|
updater-platform: linux-x86_64
|
||||||
|
product: firefox
|
||||||
|
channel: "esr-localtest-next"
|
||||||
|
include-version: esr68-next
|
||||||
|
last-watershed: "52.0esr"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
firefox-next-linux:
|
||||||
|
shipping-product: firefox
|
||||||
|
treeherder:
|
||||||
|
platform: linux32-shippable/opt
|
||||||
|
attributes:
|
||||||
|
build_platform: linux-shippable
|
||||||
|
extra:
|
||||||
|
platform: linux-i686
|
||||||
|
firefox-next-linux64:
|
||||||
|
shipping-product: firefox
|
||||||
|
treeherder:
|
||||||
|
platform: linux64-shippable/opt
|
||||||
|
attributes:
|
||||||
|
build_platform: linux64-shippable
|
||||||
|
extra:
|
||||||
|
platform: linux-x86_64
|
||||||
|
firefox-next-macosx64:
|
||||||
|
shipping-product: firefox
|
||||||
|
treeherder:
|
||||||
|
platform: osx-shippable/opt
|
||||||
|
attributes:
|
||||||
|
build_platform: macosx64-shippable
|
||||||
|
extra:
|
||||||
|
platform: mac
|
||||||
|
firefox-next-win32:
|
||||||
|
shipping-product: firefox
|
||||||
|
treeherder:
|
||||||
|
platform: windows2012-32-shippable/opt
|
||||||
|
attributes:
|
||||||
|
build_platform: win32-shippable
|
||||||
|
extra:
|
||||||
|
platform: win32
|
||||||
|
firefox-next-win64:
|
||||||
|
shipping-product: firefox
|
||||||
|
treeherder:
|
||||||
|
platform: windows2012-64-shippable/opt
|
||||||
|
attributes:
|
||||||
|
build_platform: win64-shippable
|
||||||
|
extra:
|
||||||
|
platform: win64
|
|
@ -70,6 +70,7 @@ job-defaults:
|
||||||
win64-aarch64.*: "67.0"
|
win64-aarch64.*: "67.0"
|
||||||
default: null
|
default: null
|
||||||
esr60: "52.0esr"
|
esr60: "52.0esr"
|
||||||
|
esr68: "68.0esr"
|
||||||
default: "default"
|
default: "default"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
# 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/.
|
||||||
|
---
|
||||||
|
loader: taskgraph.loader.transform:loader
|
||||||
|
|
||||||
|
kind-dependencies:
|
||||||
|
- post-balrog-dummy
|
||||||
|
- post-beetmover-dummy
|
||||||
|
- release-balrog-submit-toplevel
|
||||||
|
- release-update-verify-config-next
|
||||||
|
|
||||||
|
transforms:
|
||||||
|
- taskgraph.transforms.release:run_on_releases
|
||||||
|
- taskgraph.transforms.release_deps:transforms
|
||||||
|
- taskgraph.transforms.update_verify:transforms
|
||||||
|
- taskgraph.transforms.job:transforms
|
||||||
|
- taskgraph.transforms.task:transforms
|
||||||
|
|
||||||
|
job-defaults:
|
||||||
|
name: update-verify-next
|
||||||
|
run-on-projects: [] # to make sure this never runs as part of CI
|
||||||
|
run-on-releases: [esr68]
|
||||||
|
shipping-phase: promote
|
||||||
|
worker-type: b-linux
|
||||||
|
worker:
|
||||||
|
artifacts:
|
||||||
|
- name: 'public/build/diff-summary.log'
|
||||||
|
path: '/builds/worker/tools/release/updates/diff-summary.log'
|
||||||
|
type: file
|
||||||
|
docker-image:
|
||||||
|
in-tree: "update-verify"
|
||||||
|
max-run-time: 7200
|
||||||
|
retry-exit-status:
|
||||||
|
- 255
|
||||||
|
env:
|
||||||
|
CHANNEL: "esr-localtest-next"
|
||||||
|
treeherder:
|
||||||
|
symbol: UV(UVnext)
|
||||||
|
kind: test
|
||||||
|
extra:
|
||||||
|
chunks: 12
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
firefox-next-linux64:
|
||||||
|
description: linux64 esr-next update verify
|
||||||
|
shipping-product: firefox
|
||||||
|
attributes:
|
||||||
|
build_platform: linux64-shippable
|
||||||
|
|
||||||
|
firefox-next-linux:
|
||||||
|
description: linux esr-next update verify
|
||||||
|
shipping-product: firefox
|
||||||
|
attributes:
|
||||||
|
build_platform: linux-shippable
|
||||||
|
|
||||||
|
firefox-next-win64:
|
||||||
|
description: win64 esr-next update verify
|
||||||
|
shipping-product: firefox
|
||||||
|
attributes:
|
||||||
|
build_platform: win64-shippable
|
||||||
|
|
||||||
|
firefox-next-win32:
|
||||||
|
description: win32 esr-next update verify
|
||||||
|
shipping-product: firefox
|
||||||
|
attributes:
|
||||||
|
build_platform: win32-shippable
|
||||||
|
|
||||||
|
firefox-next-macosx64:
|
||||||
|
description: macosx64 esr-next update verify
|
||||||
|
shipping-product: firefox
|
||||||
|
attributes:
|
||||||
|
build_platform: macosx64-shippable
|
|
@ -63,7 +63,7 @@ job-template:
|
||||||
- repackage/win64_signed.py
|
- repackage/win64_signed.py
|
||||||
package-formats:
|
package-formats:
|
||||||
by-release-type:
|
by-release-type:
|
||||||
esr60:
|
esr(60|68):
|
||||||
by-build-platform:
|
by-build-platform:
|
||||||
linux.*: [mar, mar-bz2]
|
linux.*: [mar, mar-bz2]
|
||||||
linux4\b.*: [mar, mar-bz2]
|
linux4\b.*: [mar, mar-bz2]
|
||||||
|
|
|
@ -73,7 +73,7 @@ job-template:
|
||||||
- repackage/win64_signed.py
|
- repackage/win64_signed.py
|
||||||
package-formats:
|
package-formats:
|
||||||
by-release-type:
|
by-release-type:
|
||||||
esr60:
|
esr(60|68):
|
||||||
by-build-platform:
|
by-build-platform:
|
||||||
linux.*: [mar, mar-bz2]
|
linux.*: [mar, mar-bz2]
|
||||||
linux4\b.*: [mar, mar-bz2]
|
linux4\b.*: [mar, mar-bz2]
|
||||||
|
|
|
@ -46,10 +46,10 @@
|
||||||
},
|
},
|
||||||
"arrow": {
|
"arrow": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:3397e5448952e18e1295bf047014659effa5ae8da6a5371d37ff0ddc46fa6872",
|
"sha256:002f2315cf4c8404de737c42860441732d339bbc57fee584e2027520e055ecc1",
|
||||||
"sha256:6f54d9f016c0b7811fac9fb8c2c7fa7421d80c54dbdd75ffb12913c55db60b8a"
|
"sha256:82dd5e13b733787d4eb0fef42d1ee1a99136dc1d65178f70373b3678b3181bfc"
|
||||||
],
|
],
|
||||||
"version": "==0.13.1"
|
"version": "==0.13.2"
|
||||||
},
|
},
|
||||||
"asn1crypto": {
|
"asn1crypto": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -74,11 +74,11 @@
|
||||||
},
|
},
|
||||||
"awscli": {
|
"awscli": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:b7a6e758a7d2e7230e4e21acab9f80db2fd31248333ca8575b4538a5c43ebd2c",
|
"sha256:34e7ee2bd912e6613ac064099c13e2114722d508fc35e01fd0dfc3be41ddd92c",
|
||||||
"sha256:fae8839c4ddf6e7fb49543beec8d9659afd60e2fa23481ee723390f0a3a7d0f7"
|
"sha256:f73c11e6726a5ca25df3399762fae7f6882c71e097dc622d0e4743c9f8e84526"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.16.156"
|
"version": "==1.16.161"
|
||||||
},
|
},
|
||||||
"backports.lzma": {
|
"backports.lzma": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -88,10 +88,10 @@
|
||||||
},
|
},
|
||||||
"botocore": {
|
"botocore": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1517c52eaa3056d0e81f9a81b580d7f28440e7e1523d10a8acc8160c56be7113",
|
"sha256:5e4774c106bb02f8e4639818c2f8157b8ec114a76e481e17cd3fe6955206e088",
|
||||||
"sha256:19d9d56fcf4f16ffea8a929bbf3c72db3458b6c1f306c04031f3166759cd62ac"
|
"sha256:cfc667e7888aad09ead8f7e32129ea90aa5c7f602531094954bf6305db74aac4"
|
||||||
],
|
],
|
||||||
"version": "==1.12.146"
|
"version": "==1.12.151"
|
||||||
},
|
},
|
||||||
"certifi": {
|
"certifi": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -370,11 +370,11 @@
|
||||||
},
|
},
|
||||||
"requests": {
|
"requests": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
|
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
|
||||||
"sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"
|
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==2.21.0"
|
"version": "==2.22.0"
|
||||||
},
|
},
|
||||||
"rsa": {
|
"rsa": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -392,11 +392,11 @@
|
||||||
},
|
},
|
||||||
"scriptworker": {
|
"scriptworker": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:44b19ef0ddfe14309ddb035e4f6e82da8d9eb3d7c3de8ed82ee74a75beefb767",
|
"sha256:836181e36befcd74bb6b9457fd9336d8efa1350e77c285f0dc32bdb0ef6e4270",
|
||||||
"sha256:4b7bd567c8b511f1a87c68ac541c94b730d6f307ad86bb0af279ac30ef5867e9"
|
"sha256:d858c4e0dae3305dec3683458d2e879752b0a3645e9f95278b717d53d45c2809"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==23.0.4"
|
"version": "==23.0.5"
|
||||||
},
|
},
|
||||||
"sh": {
|
"sh": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
|
|
@ -367,11 +367,14 @@ Publishes signed langpacks to archive.mozilla.org
|
||||||
release-update-verify
|
release-update-verify
|
||||||
---------------------
|
---------------------
|
||||||
Verifies the contents and package of release update MARs.
|
Verifies the contents and package of release update MARs.
|
||||||
|
|
||||||
release-secondary-update-verify
|
release-secondary-update-verify
|
||||||
-------------------------------
|
-------------------------------
|
||||||
Verifies the contents and package of release update MARs.
|
Verifies the contents and package of release update MARs.
|
||||||
|
|
||||||
|
release-update-verify-next
|
||||||
|
--------------------------
|
||||||
|
Verifies the contents and package of release and updare MARs from the previous ESR release.
|
||||||
|
|
||||||
release-update-verify-config
|
release-update-verify-config
|
||||||
----------------------------
|
----------------------------
|
||||||
Creates configs for release-update-verify tasks
|
Creates configs for release-update-verify tasks
|
||||||
|
@ -380,6 +383,10 @@ release-secondary-update-verify-config
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
Creates configs for release-secondary-update-verify tasks
|
Creates configs for release-secondary-update-verify tasks
|
||||||
|
|
||||||
|
release-update-verify-config-next
|
||||||
|
---------------------------------
|
||||||
|
Creates configs for release-update-verify-next tasks
|
||||||
|
|
||||||
release-updates-builder
|
release-updates-builder
|
||||||
-----------------------
|
-----------------------
|
||||||
Top level Balrog blob submission & patcher/update verify config updates.
|
Top level Balrog blob submission & patcher/update verify config updates.
|
||||||
|
|
|
@ -332,7 +332,7 @@ mapping:
|
||||||
checksums_path: ${path_platform}/${locale}/Firefox Setup ${version}.msi
|
checksums_path: ${path_platform}/${locale}/Firefox Setup ${version}.msi
|
||||||
target.complete.mar:
|
target.complete.mar:
|
||||||
<<: *default
|
<<: *default
|
||||||
description: "The main installer we ship our mobile products baked within"
|
description: "Complete MAR to serve as updates"
|
||||||
all_locales: true
|
all_locales: true
|
||||||
from:
|
from:
|
||||||
- mar-signing
|
- mar-signing
|
||||||
|
@ -341,6 +341,18 @@ mapping:
|
||||||
update_balrog_manifest: true
|
update_balrog_manifest: true
|
||||||
destinations:
|
destinations:
|
||||||
- ${version}-candidates/build${build_number}/update/${path_platform}
|
- ${version}-candidates/build${build_number}/update/${path_platform}
|
||||||
|
target.bz2.complete.mar:
|
||||||
|
<<: *default
|
||||||
|
description: "Complete MAR with bz2 compression and SHA1 signing to serve as updates"
|
||||||
|
all_locales: true
|
||||||
|
from:
|
||||||
|
- mar-signing
|
||||||
|
pretty_name: firefox-${version}.bz2.complete.mar
|
||||||
|
checksums_path: update/${path_platform}/${locale}/firefox-${version}.bz2.complete.mar
|
||||||
|
update_balrog_manifest: true
|
||||||
|
balrog_format: bz2
|
||||||
|
destinations:
|
||||||
|
- ${version}-candidates/build${build_number}/update/${path_platform}
|
||||||
${partial}:
|
${partial}:
|
||||||
<<: *default
|
<<: *default
|
||||||
description: "Partials MAR files to serve as updates"
|
description: "Partials MAR files to serve as updates"
|
||||||
|
|
|
@ -315,7 +315,7 @@ def make_task_worker(config, jobs):
|
||||||
signing_task_ref = "<" + str(signing_task) + ">"
|
signing_task_ref = "<" + str(signing_task) + ">"
|
||||||
build_task_ref = "<" + str(build_task) + ">"
|
build_task_ref = "<" + str(build_task) + ">"
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
||||||
config, job, platform, locale
|
config, job, platform, locale
|
||||||
)
|
)
|
||||||
|
@ -329,7 +329,7 @@ def make_task_worker(config, jobs):
|
||||||
'upstream-artifacts': upstream_artifacts,
|
'upstream-artifacts': upstream_artifacts,
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
worker['artifact-map'] = generate_beetmover_artifact_map(
|
worker['artifact-map'] = generate_beetmover_artifact_map(
|
||||||
config, job, platform=platform, locale=locale)
|
config, job, platform=platform, locale=locale)
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ def make_beetmover_checksums_worker(config, jobs):
|
||||||
'release-properties': craft_release_properties(config, job),
|
'release-properties': craft_release_properties(config, job),
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
||||||
config, job, platform, locale
|
config, job, platform, locale
|
||||||
)
|
)
|
||||||
|
|
|
@ -138,7 +138,7 @@ def make_beetmover_checksums_worker(config, jobs):
|
||||||
'release-properties': craft_release_properties(config, job),
|
'release-properties': craft_release_properties(config, job),
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
||||||
config, job, platform, locales
|
config, job, platform, locales
|
||||||
)
|
)
|
||||||
|
|
|
@ -358,7 +358,7 @@ def make_task_worker(config, jobs):
|
||||||
locale = job["attributes"].get("locale")
|
locale = job["attributes"].get("locale")
|
||||||
platform = job["attributes"]["build_platform"]
|
platform = job["attributes"]["build_platform"]
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
||||||
config, job, platform, locale)
|
config, job, platform, locale)
|
||||||
else:
|
else:
|
||||||
|
@ -373,7 +373,7 @@ def make_task_worker(config, jobs):
|
||||||
'upstream-artifacts': upstream_artifacts,
|
'upstream-artifacts': upstream_artifacts,
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
worker['artifact-map'] = generate_beetmover_artifact_map(
|
worker['artifact-map'] = generate_beetmover_artifact_map(
|
||||||
config, job, platform=platform, locale=locale)
|
config, job, platform=platform, locale=locale)
|
||||||
|
|
||||||
|
@ -412,7 +412,7 @@ def make_partials_artifacts(config, jobs):
|
||||||
partials_info = get_partials_info_from_params(
|
partials_info = get_partials_info_from_params(
|
||||||
config.params.get('release_history'), balrog_platform, locale)
|
config.params.get('release_history'), balrog_platform, locale)
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
job['worker']['artifact-map'].extend(
|
job['worker']['artifact-map'].extend(
|
||||||
generate_beetmover_partials_artifact_map(
|
generate_beetmover_partials_artifact_map(
|
||||||
config, job, partials_info, platform=platform, locale=locale))
|
config, job, partials_info, platform=platform, locale=locale))
|
||||||
|
|
|
@ -137,7 +137,7 @@ def make_beetmover_checksums_worker(config, jobs):
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"Beetmover checksums must have a beetmover and signing dependency!")
|
"Beetmover checksums must have a beetmover and signing dependency!")
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
upstream_artifacts = generate_beetmover_upstream_artifacts(config,
|
upstream_artifacts = generate_beetmover_upstream_artifacts(config,
|
||||||
job, platform, locale)
|
job, platform, locale)
|
||||||
else:
|
else:
|
||||||
|
@ -149,7 +149,7 @@ def make_beetmover_checksums_worker(config, jobs):
|
||||||
'upstream-artifacts': upstream_artifacts,
|
'upstream-artifacts': upstream_artifacts,
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
worker['artifact-map'] = generate_beetmover_artifact_map(
|
worker['artifact-map'] = generate_beetmover_artifact_map(
|
||||||
config, job, platform=platform)
|
config, job, platform=platform)
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,8 @@ def make_task_worker(config, jobs):
|
||||||
**{'release-level': config.params.release_level()}
|
**{'release-level': config.params.release_level()}
|
||||||
)
|
)
|
||||||
resolve_keyed_by(
|
resolve_keyed_by(
|
||||||
job, 'bouncer-products', item_name=job['name'], project=config.params['project']
|
job, 'bouncer-products', item_name=job['name'],
|
||||||
|
**{'release-type': config.params['release_type']}
|
||||||
)
|
)
|
||||||
|
|
||||||
# No need to filter out ja-JP-mac, we need to upload both; but we do
|
# No need to filter out ja-JP-mac, we need to upload both; but we do
|
||||||
|
|
|
@ -125,7 +125,7 @@ def make_task_worker(config, jobs):
|
||||||
|
|
||||||
platform = job["attributes"]["build_platform"]
|
platform = job["attributes"]["build_platform"]
|
||||||
locale = job["attributes"]["chunk_locales"]
|
locale = job["attributes"]["chunk_locales"]
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
||||||
config, job, platform, locale,
|
config, job, platform, locale,
|
||||||
)
|
)
|
||||||
|
@ -139,7 +139,7 @@ def make_task_worker(config, jobs):
|
||||||
'upstream-artifacts': upstream_artifacts,
|
'upstream-artifacts': upstream_artifacts,
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
job['worker']['artifact-map'] = generate_beetmover_artifact_map(
|
job['worker']['artifact-map'] = generate_beetmover_artifact_map(
|
||||||
config, job, platform=platform, locale=locale)
|
config, job, platform=platform, locale=locale)
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ def _change_platform_data(config, platform_job, platform):
|
||||||
platform_job['worker']['release-properties']['platform'] = platform
|
platform_job['worker']['release-properties']['platform'] = platform
|
||||||
|
|
||||||
# amend artifactMap entries as well
|
# amend artifactMap entries as well
|
||||||
if should_use_artifact_map(backup_platform, config.params['project']):
|
if should_use_artifact_map(backup_platform):
|
||||||
platform_mapping = {
|
platform_mapping = {
|
||||||
'linux64': 'linux-x86_64',
|
'linux64': 'linux-x86_64',
|
||||||
'linux': 'linux-i686',
|
'linux': 'linux-i686',
|
||||||
|
|
|
@ -156,7 +156,7 @@ def make_task_worker(config, jobs):
|
||||||
|
|
||||||
platform = job["attributes"]["build_platform"]
|
platform = job["attributes"]["build_platform"]
|
||||||
# Works with Firefox/Devedition. Commented for migration.
|
# Works with Firefox/Devedition. Commented for migration.
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
upstream_artifacts = generate_beetmover_upstream_artifacts(
|
||||||
config, job, platform=None, locale=None
|
config, job, platform=None, locale=None
|
||||||
)
|
)
|
||||||
|
@ -168,7 +168,7 @@ def make_task_worker(config, jobs):
|
||||||
worker['upstream-artifacts'] = upstream_artifacts
|
worker['upstream-artifacts'] = upstream_artifacts
|
||||||
|
|
||||||
# Works with Firefox/Devedition. Commented for migration.
|
# Works with Firefox/Devedition. Commented for migration.
|
||||||
if should_use_artifact_map(platform, config.params['project']):
|
if should_use_artifact_map(platform):
|
||||||
worker['artifact-map'] = generate_beetmover_artifact_map(
|
worker['artifact-map'] = generate_beetmover_artifact_map(
|
||||||
config, job, platform=platform)
|
config, job, platform=platform)
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ transforms = TransformSequence()
|
||||||
def add_command(config, tasks):
|
def add_command(config, tasks):
|
||||||
config_tasks = {}
|
config_tasks = {}
|
||||||
for dep in config.kind_dependencies_tasks:
|
for dep in config.kind_dependencies_tasks:
|
||||||
if 'update-verify-config' in dep.kind:
|
if 'update-verify-config' in dep.kind or 'update-verify-next-config' in dep.kind:
|
||||||
config_tasks[dep.name] = dep
|
config_tasks[dep.name] = dep
|
||||||
|
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
|
|
|
@ -33,6 +33,8 @@ INCLUDE_VERSION_REGEXES = {
|
||||||
"devedition_hack": r"'^((?!58\.0b1$)\d+\.\d+(b\d+)?)$'",
|
"devedition_hack": r"'^((?!58\.0b1$)\d+\.\d+(b\d+)?)$'",
|
||||||
# Same as nonbeta, except for the esr suffix
|
# Same as nonbeta, except for the esr suffix
|
||||||
"esr": r"'^\d+\.\d+(\.\d+)?esr$'",
|
"esr": r"'^\d+\.\d+(\.\d+)?esr$'",
|
||||||
|
# Previous esr versions, for update testing before we update users to esr68
|
||||||
|
"esr68-next": r"'^(52|60)+\.\d+(\.\d+)?esr$'",
|
||||||
}
|
}
|
||||||
|
|
||||||
MAR_CHANNEL_ID_OVERRIDE_REGEXES = {
|
MAR_CHANNEL_ID_OVERRIDE_REGEXES = {
|
||||||
|
|
|
@ -427,8 +427,10 @@ def generate_beetmover_upstream_artifacts(config, job, platform, locale=None, de
|
||||||
resolve_keyed_by(
|
resolve_keyed_by(
|
||||||
job, 'attributes.artifact_map',
|
job, 'attributes.artifact_map',
|
||||||
'artifact map',
|
'artifact map',
|
||||||
project=config.params['project'],
|
**{
|
||||||
platform=platform
|
'release-type': config.params['release_type'],
|
||||||
|
'platform': platform,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
map_config = deepcopy(cached_load_yaml(job['attributes']['artifact_map']))
|
map_config = deepcopy(cached_load_yaml(job['attributes']['artifact_map']))
|
||||||
upstream_artifacts = list()
|
upstream_artifacts = list()
|
||||||
|
@ -469,6 +471,11 @@ def generate_beetmover_upstream_artifacts(config, job, platform, locale=None, de
|
||||||
filename,
|
filename,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
if getattr(job['dependencies'][dep], 'release_artifacts', None):
|
||||||
|
paths = [
|
||||||
|
path for path in paths
|
||||||
|
if path in job['dependencies'][dep].release_artifacts]
|
||||||
|
|
||||||
if not paths:
|
if not paths:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -556,8 +563,10 @@ def generate_beetmover_artifact_map(config, job, **kwargs):
|
||||||
resolve_keyed_by(
|
resolve_keyed_by(
|
||||||
job, 'attributes.artifact_map',
|
job, 'attributes.artifact_map',
|
||||||
'artifact map',
|
'artifact map',
|
||||||
project=config.params['project'],
|
**{
|
||||||
platform=platform
|
'release-type': config.params['release_type'],
|
||||||
|
'platform': platform,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
map_config = deepcopy(cached_load_yaml(job['attributes']['artifact_map']))
|
map_config = deepcopy(cached_load_yaml(job['attributes']['artifact_map']))
|
||||||
base_artifact_prefix = map_config.get('base_artifact_prefix', get_artifact_prefix(job))
|
base_artifact_prefix = map_config.get('base_artifact_prefix', get_artifact_prefix(job))
|
||||||
|
@ -697,8 +706,10 @@ def generate_beetmover_partials_artifact_map(config, job, partials_info, **kwarg
|
||||||
resolve_keyed_by(
|
resolve_keyed_by(
|
||||||
job, 'attributes.artifact_map',
|
job, 'attributes.artifact_map',
|
||||||
'artifact map',
|
'artifact map',
|
||||||
project=config.params['project'],
|
**{
|
||||||
platform=platform
|
'release-type': config.params['release_type'],
|
||||||
|
'platform': platform,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
map_config = deepcopy(cached_load_yaml(job['attributes']['artifact_map']))
|
map_config = deepcopy(cached_load_yaml(job['attributes']['artifact_map']))
|
||||||
base_artifact_prefix = map_config.get('base_artifact_prefix', get_artifact_prefix(job))
|
base_artifact_prefix = map_config.get('base_artifact_prefix', get_artifact_prefix(job))
|
||||||
|
@ -811,48 +822,10 @@ def generate_beetmover_partials_artifact_map(config, job, partials_info, **kwarg
|
||||||
return artifacts
|
return artifacts
|
||||||
|
|
||||||
|
|
||||||
# should_use_artifact_map {{{
|
def should_use_artifact_map(platform):
|
||||||
def should_use_artifact_map(platform, project):
|
|
||||||
"""Return True if this task uses the beetmover artifact map.
|
"""Return True if this task uses the beetmover artifact map.
|
||||||
|
|
||||||
This function exists solely for the beetmover artifact map
|
This function exists solely for the beetmover artifact map
|
||||||
migration.
|
migration.
|
||||||
"""
|
"""
|
||||||
if 'linux64-snap-shippable' in platform:
|
return 'devedition' not in platform
|
||||||
# Snap has never been implemented outside of declarative artifacts. We need to use
|
|
||||||
# declarative artifacts no matter the branch we're on
|
|
||||||
return True
|
|
||||||
|
|
||||||
# FIXME: once we're ready to switch fully to declarative artifacts on other
|
|
||||||
# branches, we can expand this; for now, Fennec is rolled-out to all
|
|
||||||
# release branches, while Firefox only to mozilla-central
|
|
||||||
platforms = [
|
|
||||||
'android',
|
|
||||||
'fennec'
|
|
||||||
]
|
|
||||||
projects = ['mozilla-central', 'mozilla-beta', 'mozilla-release']
|
|
||||||
if any([pl in platform for pl in platforms]) and any([pj == project for pj in projects]):
|
|
||||||
return True
|
|
||||||
|
|
||||||
platforms = [
|
|
||||||
'linux', # needed for beetmover-langpacks-checksums
|
|
||||||
'linux64', # which inherit amended platform from their beetmover counterpart
|
|
||||||
'win32',
|
|
||||||
'win64',
|
|
||||||
'macosx64',
|
|
||||||
'linux-shippable',
|
|
||||||
'linux64-shippable',
|
|
||||||
'macosx64-shippable',
|
|
||||||
'win32-shippable',
|
|
||||||
'win64-shippable',
|
|
||||||
'win64-aarch64-shippable',
|
|
||||||
'win64-asan-reporter-nightly',
|
|
||||||
'linux64-asan-reporter-nightly',
|
|
||||||
'firefox-source',
|
|
||||||
'firefox-release',
|
|
||||||
]
|
|
||||||
projects = ['mozilla-central', 'mozilla-beta', 'mozilla-release']
|
|
||||||
if any([pl == platform for pl in platforms]) and any([pj == project for pj in projects]):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
|
@ -91,8 +91,8 @@ def cli(runner_class=MarionetteTestRunner, parser_class=MarionetteArguments,
|
||||||
failed = harness_instance.run()
|
failed = harness_instance.run()
|
||||||
if failed > 0:
|
if failed > 0:
|
||||||
sys.exit(10)
|
sys.exit(10)
|
||||||
except Exception:
|
except Exception as e:
|
||||||
logger.error('Failure during harness execution', exc_info=True)
|
logger.error(e.message, exc_info=True)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,18 @@ config = {
|
||||||
"win64",
|
"win64",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"complete-mar-bz2": {
|
||||||
|
"product-name": "Firefox-%(version)s-Complete-bz2",
|
||||||
|
"check_uptake": True,
|
||||||
|
"platforms": [
|
||||||
|
"linux",
|
||||||
|
"linux64",
|
||||||
|
"osx",
|
||||||
|
"win",
|
||||||
|
"win64",
|
||||||
|
"win64-aarch64",
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"partials": {
|
"partials": {
|
||||||
"releases-dir": {
|
"releases-dir": {
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[disallow-crossorigin.html]
|
|
||||||
expected: ERROR
|
|
||||||
[Promise rejection event should be muted for cross-origin non-CORS script]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
prefs: [dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true, layout.css.step-position-jump.enabled:true]
|
prefs: [dom.animations-api.autoremove.enabled:true, dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true, layout.css.step-position-jump.enabled:true]
|
||||||
|
|
|
@ -162,6 +162,24 @@ async_test(function(t) {
|
||||||
p = Promise.all([Promise.reject(e)]);
|
p = Promise.all([Promise.reject(e)]);
|
||||||
}, 'unhandledrejection: from Promise.reject, indirected through Promise.all');
|
}, 'unhandledrejection: from Promise.reject, indirected through Promise.all');
|
||||||
|
|
||||||
|
async_test(function(t) {
|
||||||
|
var p;
|
||||||
|
|
||||||
|
var unhandled = function(ev) {
|
||||||
|
if (ev.promise === p) {
|
||||||
|
t.step(function() {
|
||||||
|
assert_equals(ev.reason.name, 'InvalidStateError');
|
||||||
|
assert_equals(ev.promise, p);
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addEventListener('unhandledrejection', unhandled);
|
||||||
|
ensureCleanup(t, unhandled);
|
||||||
|
|
||||||
|
p = createImageBitmap(new Blob());
|
||||||
|
}, 'unhandledrejection: from createImageBitmap which is UA triggered');
|
||||||
|
|
||||||
//
|
//
|
||||||
// Negative unhandledrejection/rejectionhandled tests with immediate attachment
|
// Negative unhandledrejection/rejectionhandled tests with immediate attachment
|
||||||
//
|
//
|
||||||
|
@ -270,6 +288,16 @@ async_test(function(t) {
|
||||||
}, 'no unhandledrejection/rejectionhandled: all inside a queued task, a rejection handler attached synchronously to ' +
|
}, 'no unhandledrejection/rejectionhandled: all inside a queued task, a rejection handler attached synchronously to ' +
|
||||||
'a promise created from returning a Promise.reject-created promise in a fulfillment handler');
|
'a promise created from returning a Promise.reject-created promise in a fulfillment handler');
|
||||||
|
|
||||||
|
async_test(function(t) {
|
||||||
|
var p;
|
||||||
|
|
||||||
|
onUnhandledFail(t, function() { return p; });
|
||||||
|
|
||||||
|
var unreached = t.unreached_func('promise should not be fulfilled');
|
||||||
|
p = createImageBitmap(new Blob()).then(unreached, function() {});
|
||||||
|
}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise created from ' +
|
||||||
|
'createImageBitmap');
|
||||||
|
|
||||||
//
|
//
|
||||||
// Negative unhandledrejection/rejectionhandled tests with microtask-delayed attachment
|
// Negative unhandledrejection/rejectionhandled tests with microtask-delayed attachment
|
||||||
//
|
//
|
||||||
|
@ -659,6 +687,43 @@ async_test(function(t) {
|
||||||
}, 10);
|
}, 10);
|
||||||
}, 'delayed handling: delaying handling by setTimeout(,10) will cause both events to fire');
|
}, 'delayed handling: delaying handling by setTimeout(,10) will cause both events to fire');
|
||||||
|
|
||||||
|
async_test(function(t) {
|
||||||
|
var unhandledPromises = [];
|
||||||
|
var unhandledReasons = [];
|
||||||
|
var p;
|
||||||
|
|
||||||
|
var unhandled = function(ev) {
|
||||||
|
if (ev.promise === p) {
|
||||||
|
t.step(function() {
|
||||||
|
unhandledPromises.push(ev.promise);
|
||||||
|
unhandledReasons.push(ev.reason.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var handled = function(ev) {
|
||||||
|
if (ev.promise === p) {
|
||||||
|
t.step(function() {
|
||||||
|
assert_array_equals(unhandledPromises, [p]);
|
||||||
|
assert_array_equals(unhandledReasons, ['InvalidStateError']);
|
||||||
|
assert_equals(ev.promise, p);
|
||||||
|
assert_equals(ev.reason.name, 'InvalidStateError');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addEventListener('unhandledrejection', unhandled);
|
||||||
|
addEventListener('rejectionhandled', handled);
|
||||||
|
ensureCleanup(t, unhandled, handled);
|
||||||
|
|
||||||
|
p = createImageBitmap(new Blob());
|
||||||
|
setTimeout(function() {
|
||||||
|
var unreached = t.unreached_func('promise should not be fulfilled');
|
||||||
|
p.then(unreached, function(reason) {
|
||||||
|
assert_equals(reason.name, 'InvalidStateError');
|
||||||
|
setTimeout(function() { t.done(); }, 10);
|
||||||
|
});
|
||||||
|
}, 10);
|
||||||
|
}, 'delayed handling: delaying handling rejected promise created from createImageBitmap will cause both events to fire');
|
||||||
|
|
||||||
//
|
//
|
||||||
// Miscellaneous tests about integration with the rest of the platform
|
// Miscellaneous tests about integration with the rest of the platform
|
||||||
//
|
//
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>The effect value of a keyframe effect: Overlapping keyframes</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/web-animations/#the-effect-value-of-a-keyframe-animation-effect">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="../../testcommon.js"></script>
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function assert_opacity_value(opacity, expected, description) {
|
||||||
|
return assert_approx_equals(
|
||||||
|
parseFloat(opacity),
|
||||||
|
expected,
|
||||||
|
0.0001,
|
||||||
|
description
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 0.3 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
assert_equals(animA.replaceState, 'removed');
|
||||||
|
assert_equals(animB.replaceState, 'active');
|
||||||
|
|
||||||
|
// animA is now removed so if we cancel animB, we should go back to the
|
||||||
|
// underlying value
|
||||||
|
animB.cancel();
|
||||||
|
assert_opacity_value(
|
||||||
|
getComputedStyle(div).opacity,
|
||||||
|
0.1,
|
||||||
|
'Opacity should be the un-animated value'
|
||||||
|
);
|
||||||
|
}, 'Removed animations do not contribute to animated style');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 0.3, composite: 'add' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
assert_equals(animA.replaceState, 'removed');
|
||||||
|
assert_equals(animB.replaceState, 'active');
|
||||||
|
|
||||||
|
// animA has been removed so the final result should be 0.1 + 0.3 = 0.4.
|
||||||
|
// (If animA were not removed it would be 0.2 + 0.3 = 0.5.)
|
||||||
|
assert_opacity_value(
|
||||||
|
getComputedStyle(div).opacity,
|
||||||
|
0.4,
|
||||||
|
'Opacity value should not include the removed animation'
|
||||||
|
);
|
||||||
|
}, 'Removed animations do not contribute to the effect stack');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 0.3 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
animA.persist();
|
||||||
|
|
||||||
|
animB.cancel();
|
||||||
|
assert_opacity_value(
|
||||||
|
getComputedStyle(div).opacity,
|
||||||
|
0.2,
|
||||||
|
"Opacity should be the persisted animation's value"
|
||||||
|
);
|
||||||
|
}, 'Persisted animations contribute to animated style');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 0.3, composite: 'add' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
assert_opacity_value(
|
||||||
|
getComputedStyle(div).opacity,
|
||||||
|
0.4,
|
||||||
|
'Opacity value should NOT include the contribution of the removed animation'
|
||||||
|
);
|
||||||
|
|
||||||
|
animA.persist();
|
||||||
|
|
||||||
|
assert_opacity_value(
|
||||||
|
getComputedStyle(div).opacity,
|
||||||
|
0.5,
|
||||||
|
'Opacity value should include the contribution of the persisted animation'
|
||||||
|
);
|
||||||
|
}, 'Persisted animations contribute to the effect stack');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Persist the animation before it finishes (and before it would otherwise be
|
||||||
|
// removed).
|
||||||
|
animA.persist();
|
||||||
|
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 0.3, composite: 'add' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
assert_opacity_value(
|
||||||
|
getComputedStyle(div).opacity,
|
||||||
|
0.5,
|
||||||
|
'Opacity value should include the contribution of the persisted animation'
|
||||||
|
);
|
||||||
|
}, 'Animations persisted before they would be removed contribute to the'
|
||||||
|
+ ' effect stack');
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
|
@ -209,6 +209,28 @@ test(t => {
|
||||||
}, 'Returns animations based on dynamic changes to individual'
|
}, 'Returns animations based on dynamic changes to individual'
|
||||||
+ ' animations\' current time');
|
+ ' animations\' current time');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
|
||||||
|
const animA = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
const animB = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
assert_array_equals(div.getAnimations(), [animB]);
|
||||||
|
}, 'Does not return an animation that has been removed');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
|
||||||
|
const animA = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
const animB = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
animA.persist();
|
||||||
|
|
||||||
|
assert_array_equals(div.getAnimations(), [animA, animB]);
|
||||||
|
}, 'Returns an animation that has been persisted');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
const div = createDiv(t);
|
const div = createDiv(t);
|
||||||
const watcher = EventWatcher(t, div, 'transitionrun');
|
const watcher = EventWatcher(t, div, 'transitionrun');
|
||||||
|
|
|
@ -0,0 +1,389 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>Animation.commitStyles</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/web-animations/#dom-animation-commitstyles">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="../../testcommon.js"></script>
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function assert_numeric_style_equals(opacity, expected, description) {
|
||||||
|
return assert_approx_equals(
|
||||||
|
parseFloat(opacity),
|
||||||
|
expected,
|
||||||
|
0.0001,
|
||||||
|
description
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animation = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
animation.finish();
|
||||||
|
|
||||||
|
animation.commitStyles();
|
||||||
|
|
||||||
|
// Cancel the animation so we can inspect the underlying style
|
||||||
|
animation.cancel();
|
||||||
|
|
||||||
|
assert_numeric_style_equals(getComputedStyle(div).opacity, 0.2);
|
||||||
|
}, 'Commits styles');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 0.3 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
animB.cancel();
|
||||||
|
|
||||||
|
animA.commitStyles();
|
||||||
|
|
||||||
|
assert_numeric_style_equals(getComputedStyle(div).opacity, 0.2);
|
||||||
|
}, 'Commits styles for an animation that has been removed');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.margin = '10px';
|
||||||
|
|
||||||
|
const animation = div.animate(
|
||||||
|
{ margin: '20px' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
animation.finish();
|
||||||
|
|
||||||
|
animation.commitStyles();
|
||||||
|
|
||||||
|
animation.cancel();
|
||||||
|
|
||||||
|
assert_equals(div.style.marginLeft, '20px');
|
||||||
|
}, 'Commits shorthand styles');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.marginLeft = '10px';
|
||||||
|
|
||||||
|
const animation = div.animate(
|
||||||
|
{ marginInlineStart: '20px' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
animation.finish();
|
||||||
|
|
||||||
|
animation.commitStyles();
|
||||||
|
|
||||||
|
animation.cancel();
|
||||||
|
|
||||||
|
assert_equals(div.style.marginLeft, '20px');
|
||||||
|
}, 'Commits logical properties');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.marginLeft = '10px';
|
||||||
|
|
||||||
|
const animation = div.animate({ opacity: [0.2, 0.7] }, 1000);
|
||||||
|
animation.currentTime = 500;
|
||||||
|
animation.commitStyles();
|
||||||
|
animation.cancel();
|
||||||
|
|
||||||
|
assert_numeric_style_equals(getComputedStyle(div).opacity, 0.45);
|
||||||
|
}, 'Commits values calculated mid-interval');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.setProperty('--target', '0.5');
|
||||||
|
|
||||||
|
const animation = div.animate(
|
||||||
|
{ opacity: 'var(--target)' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
animation.finish();
|
||||||
|
animation.commitStyles();
|
||||||
|
animation.cancel();
|
||||||
|
|
||||||
|
assert_numeric_style_equals(getComputedStyle(div).opacity, 0.5);
|
||||||
|
|
||||||
|
// Changes to the variable should have no effect
|
||||||
|
div.style.setProperty('--target', '1');
|
||||||
|
|
||||||
|
assert_numeric_style_equals(getComputedStyle(div).opacity, 0.5);
|
||||||
|
}, 'Commits variables as their computed values');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.fontSize = '10px';
|
||||||
|
|
||||||
|
const animation = div.animate(
|
||||||
|
{ width: '10em' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
animation.finish();
|
||||||
|
animation.commitStyles();
|
||||||
|
animation.cancel();
|
||||||
|
|
||||||
|
assert_numeric_style_equals(getComputedStyle(div).width, 100);
|
||||||
|
|
||||||
|
// Changes to the font-size should have no effect
|
||||||
|
div.style.fontSize = '20px';
|
||||||
|
|
||||||
|
assert_numeric_style_equals(getComputedStyle(div).width, 100);
|
||||||
|
}, 'Commits em units as pixel values');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: '0.2' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: '0.2', composite: 'add' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animC = div.animate(
|
||||||
|
{ opacity: '0.3', composite: 'add' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
animA.persist();
|
||||||
|
animB.persist();
|
||||||
|
|
||||||
|
await animB.finished;
|
||||||
|
|
||||||
|
// The values above have been chosen such that various error conditions
|
||||||
|
// produce results that all differ from the desired result:
|
||||||
|
//
|
||||||
|
// Expected result:
|
||||||
|
//
|
||||||
|
// animA + animB = 0.4
|
||||||
|
//
|
||||||
|
// Likely error results:
|
||||||
|
//
|
||||||
|
// <underlying> = 0.1
|
||||||
|
// (Commit didn't work at all)
|
||||||
|
//
|
||||||
|
// animB = 0.2
|
||||||
|
// (Didn't add at all when resolving)
|
||||||
|
//
|
||||||
|
// <underlying> + animB = 0.3
|
||||||
|
// (Added to the underlying value instead of lower-priority animations when
|
||||||
|
// resolving)
|
||||||
|
//
|
||||||
|
// <underlying> + animA + animB = 0.5
|
||||||
|
// (Didn't respect the composite mode of lower-priority animations)
|
||||||
|
//
|
||||||
|
// animA + animB + animC = 0.7
|
||||||
|
// (Resolved the whole stack, not just up to the target effect)
|
||||||
|
//
|
||||||
|
|
||||||
|
animB.commitStyles();
|
||||||
|
|
||||||
|
animA.cancel();
|
||||||
|
animB.cancel();
|
||||||
|
animC.cancel();
|
||||||
|
|
||||||
|
assert_numeric_style_equals(getComputedStyle(div).opacity, 0.4);
|
||||||
|
}, 'Commits the intermediate value of an animation in the middle of stack');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
// Setup animation
|
||||||
|
const animation = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
animation.finish();
|
||||||
|
|
||||||
|
// Setup observer
|
||||||
|
const mutationRecords = [];
|
||||||
|
const observer = new MutationObserver(mutations => {
|
||||||
|
mutationRecords.push(...mutations);
|
||||||
|
});
|
||||||
|
observer.observe(div, { attributes: true, attributeOldValue: true });
|
||||||
|
|
||||||
|
animation.commitStyles();
|
||||||
|
|
||||||
|
// Wait for mutation records to be dispatched
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
|
assert_equals(mutationRecords.length, 1, 'Should have one mutation record');
|
||||||
|
|
||||||
|
const mutation = mutationRecords[0];
|
||||||
|
assert_equals(mutation.type, 'attributes');
|
||||||
|
assert_equals(mutation.oldValue, 'opacity: 0.1;');
|
||||||
|
|
||||||
|
observer.disconnect();
|
||||||
|
}, 'Triggers mutation observers when updating style');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
div.style.opacity = '0.2';
|
||||||
|
|
||||||
|
// Setup animation
|
||||||
|
const animation = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
animation.finish();
|
||||||
|
|
||||||
|
// Setup observer
|
||||||
|
const mutationRecords = [];
|
||||||
|
const observer = new MutationObserver(mutations => {
|
||||||
|
mutationRecords.push(...mutations);
|
||||||
|
});
|
||||||
|
observer.observe(div, { attributes: true });
|
||||||
|
|
||||||
|
animation.commitStyles();
|
||||||
|
|
||||||
|
// Wait for mutation records to be dispatched
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
|
assert_equals(mutationRecords.length, 0, 'Should have no mutation records');
|
||||||
|
|
||||||
|
observer.disconnect();
|
||||||
|
}, 'Does NOT trigger mutation observers when the change to style is redundant');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const pseudo = getPseudoElement(t, 'before');
|
||||||
|
const animation = pseudo.animate(
|
||||||
|
{ opacity: 0 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_throws('NoModificationAllowedError', () => {
|
||||||
|
animation.commitStyles();
|
||||||
|
});
|
||||||
|
}, 'Throws if the target element is a pseudo element');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const animation = createDiv(t).animate(
|
||||||
|
{ opacity: 0 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
const nonStyleElement
|
||||||
|
= document.createElementNS('http://example.org/test', 'test');
|
||||||
|
document.body.appendChild(nonStyleElement);
|
||||||
|
animation.effect.target = nonStyleElement;
|
||||||
|
|
||||||
|
assert_throws('NoModificationAllowedError', () => {
|
||||||
|
animation.commitStyles();
|
||||||
|
});
|
||||||
|
|
||||||
|
nonStyleElement.remove();
|
||||||
|
}, 'Throws if the target element is not something with a style attribute');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
const animation = div.animate(
|
||||||
|
{ opacity: 0 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
div.style.display = 'none';
|
||||||
|
|
||||||
|
assert_throws('InvalidStateError', () => {
|
||||||
|
animation.commitStyles();
|
||||||
|
});
|
||||||
|
}, 'Throws if the target effect is display:none');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const container = createDiv(t);
|
||||||
|
const div = createDiv(t);
|
||||||
|
container.append(div);
|
||||||
|
|
||||||
|
const animation = div.animate(
|
||||||
|
{ opacity: 0 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
container.style.display = 'none';
|
||||||
|
|
||||||
|
assert_throws('InvalidStateError', () => {
|
||||||
|
animation.commitStyles();
|
||||||
|
});
|
||||||
|
}, "Throws if the target effect's ancestor is display:none");
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const container = createDiv(t);
|
||||||
|
const div = createDiv(t);
|
||||||
|
container.append(div);
|
||||||
|
|
||||||
|
const animation = div.animate(
|
||||||
|
{ opacity: 0 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
container.style.display = 'contents';
|
||||||
|
|
||||||
|
// Should NOT throw
|
||||||
|
animation.commitStyles();
|
||||||
|
}, 'Treats display:contents as rendered');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const container = createDiv(t);
|
||||||
|
const div = createDiv(t);
|
||||||
|
container.append(div);
|
||||||
|
|
||||||
|
const animation = div.animate(
|
||||||
|
{ opacity: 0 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
div.style.display = 'contents';
|
||||||
|
container.style.display = 'none';
|
||||||
|
|
||||||
|
assert_throws('InvalidStateError', () => {
|
||||||
|
animation.commitStyles();
|
||||||
|
});
|
||||||
|
}, 'Treats display:contents in a display:none subtree as not rendered');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
const animation = div.animate(
|
||||||
|
{ opacity: 0 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
div.remove();
|
||||||
|
|
||||||
|
assert_throws('InvalidStateError', () => {
|
||||||
|
animation.commitStyles();
|
||||||
|
});
|
||||||
|
}, 'Throws if the target effect is disconnected');
|
||||||
|
|
||||||
|
test(t => {
|
||||||
|
const pseudo = getPseudoElement(t, 'before');
|
||||||
|
const animation = pseudo.animate(
|
||||||
|
{ opacity: 0 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
pseudo.element.remove();
|
||||||
|
|
||||||
|
assert_throws('NoModificationAllowedError', () => {
|
||||||
|
animation.commitStyles();
|
||||||
|
});
|
||||||
|
}, 'Checks the pseudo element condition before the not rendered condition');
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>Animation.persist</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/web-animations/#dom-animation-persist">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="../../testcommon.js"></script>
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
|
||||||
|
const animA = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
const animB = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
|
||||||
|
animA.onremove = t.step_func_done(() => {
|
||||||
|
assert_equals(animA.replaceState, 'removed');
|
||||||
|
animA.persist();
|
||||||
|
assert_equals(animA.replaceState, 'persisted');
|
||||||
|
});
|
||||||
|
}, 'Allows an animation to be persisted after being removed');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = createDiv(t);
|
||||||
|
|
||||||
|
const animA = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
const animB = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
|
||||||
|
animA.persist();
|
||||||
|
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
assert_equals(animA.replaceState, 'persisted');
|
||||||
|
}, 'Allows an animation to be persisted before being removed');
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
|
@ -11,8 +11,8 @@
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// Test that each property defined in the Animation interface does not produce
|
// Test that each property defined in the Animation interface behaves as
|
||||||
// style change events.
|
// expected with regards to whether or not it produces style change events.
|
||||||
//
|
//
|
||||||
// There are two types of tests:
|
// There are two types of tests:
|
||||||
//
|
//
|
||||||
|
@ -29,8 +29,9 @@
|
||||||
// (b) An object with the following format:
|
// (b) An object with the following format:
|
||||||
//
|
//
|
||||||
// {
|
// {
|
||||||
// setup: elem => { /* return Animation */ }
|
// setup: elem => { /* return Animation */ },
|
||||||
// test: animation => { /* play |animation| */ }
|
// test: animation => { /* play |animation| */ },
|
||||||
|
// shouldFlush: boolean /* optional, defaults to false */
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// If the latter form is used, the setup function should return an Animation
|
// If the latter form is used, the setup function should return an Animation
|
||||||
|
@ -56,15 +57,17 @@
|
||||||
// animation, but simply needs to get/set the property under test.
|
// animation, but simply needs to get/set the property under test.
|
||||||
|
|
||||||
const PlayAnimationTest = testFuncOrObj => {
|
const PlayAnimationTest = testFuncOrObj => {
|
||||||
let test, setup;
|
let test, setup, shouldFlush;
|
||||||
|
|
||||||
if (typeof testFuncOrObj === 'function') {
|
if (typeof testFuncOrObj === 'function') {
|
||||||
test = testFuncOrObj;
|
test = testFuncOrObj;
|
||||||
|
shouldFlush = false;
|
||||||
} else {
|
} else {
|
||||||
test = testFuncOrObj.test;
|
test = testFuncOrObj.test;
|
||||||
if (typeof testFuncOrObj.setup === 'function') {
|
if (typeof testFuncOrObj.setup === 'function') {
|
||||||
setup = testFuncOrObj.setup;
|
setup = testFuncOrObj.setup;
|
||||||
}
|
}
|
||||||
|
shouldFlush = !!testFuncOrObj.shouldFlush;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!setup) {
|
if (!setup) {
|
||||||
|
@ -74,11 +77,11 @@ const PlayAnimationTest = testFuncOrObj => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { test, setup };
|
return { test, setup, shouldFlush };
|
||||||
};
|
};
|
||||||
|
|
||||||
const UsePropertyTest = testFuncOrObj => {
|
const UsePropertyTest = testFuncOrObj => {
|
||||||
const { setup, test } = PlayAnimationTest(testFuncOrObj);
|
const { setup, test, shouldFlush } = PlayAnimationTest(testFuncOrObj);
|
||||||
|
|
||||||
let coveringAnimation;
|
let coveringAnimation;
|
||||||
return {
|
return {
|
||||||
|
@ -93,6 +96,7 @@ const UsePropertyTest = testFuncOrObj => {
|
||||||
test(animation);
|
test(animation);
|
||||||
coveringAnimation.play();
|
coveringAnimation.play();
|
||||||
},
|
},
|
||||||
|
shouldFlush,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -160,6 +164,7 @@ const tests = {
|
||||||
}),
|
}),
|
||||||
playState: UsePropertyTest(animation => animation.playState),
|
playState: UsePropertyTest(animation => animation.playState),
|
||||||
pending: UsePropertyTest(animation => animation.pending),
|
pending: UsePropertyTest(animation => animation.pending),
|
||||||
|
replaceState: UsePropertyTest(animation => animation.replaceState),
|
||||||
ready: UsePropertyTest(animation => animation.ready),
|
ready: UsePropertyTest(animation => animation.ready),
|
||||||
finished: UsePropertyTest(animation => {
|
finished: UsePropertyTest(animation => {
|
||||||
// Get the finished Promise
|
// Get the finished Promise
|
||||||
|
@ -172,6 +177,13 @@ const tests = {
|
||||||
// Set the onfinish menber
|
// Set the onfinish menber
|
||||||
animation.onfinish = () => {};
|
animation.onfinish = () => {};
|
||||||
}),
|
}),
|
||||||
|
onremove: UsePropertyTest(animation => {
|
||||||
|
// Get the onremove member
|
||||||
|
animation.onremove;
|
||||||
|
|
||||||
|
// Set the onremove menber
|
||||||
|
animation.onremove = () => {};
|
||||||
|
}),
|
||||||
oncancel: UsePropertyTest(animation => {
|
oncancel: UsePropertyTest(animation => {
|
||||||
// Get the oncancel member
|
// Get the oncancel member
|
||||||
animation.oncancel;
|
animation.oncancel;
|
||||||
|
@ -225,6 +237,51 @@ const tests = {
|
||||||
animation.reverse();
|
animation.reverse();
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
persist: PlayAnimationTest({
|
||||||
|
setup: async elem => {
|
||||||
|
// Create an animation whose replaceState is 'removed'.
|
||||||
|
const animA = elem.animate(
|
||||||
|
{ opacity: 1 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = elem.animate(
|
||||||
|
{ opacity: 1 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
await animA.finished;
|
||||||
|
animB.cancel();
|
||||||
|
|
||||||
|
return animA;
|
||||||
|
},
|
||||||
|
test: animation => {
|
||||||
|
animation.persist();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
commitStyles: PlayAnimationTest({
|
||||||
|
setup: async elem => {
|
||||||
|
// Create an animation whose replaceState is 'removed'.
|
||||||
|
const animA = elem.animate(
|
||||||
|
// It's important to use opacity of '1' here otherwise we'll create a
|
||||||
|
// transition due to updating the specified style whereas the transition
|
||||||
|
// we want to detect is the one from flushing due to calling
|
||||||
|
// commitStyles.
|
||||||
|
{ opacity: 1 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = elem.animate(
|
||||||
|
{ opacity: 1 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
await animA.finished;
|
||||||
|
animB.cancel();
|
||||||
|
|
||||||
|
return animA;
|
||||||
|
},
|
||||||
|
test: animation => {
|
||||||
|
animation.commitStyles();
|
||||||
|
},
|
||||||
|
shouldFlush: true,
|
||||||
|
}),
|
||||||
get ['Animation constructor']() {
|
get ['Animation constructor']() {
|
||||||
let originalElem;
|
let originalElem;
|
||||||
return UsePropertyTest({
|
return UsePropertyTest({
|
||||||
|
@ -266,7 +323,7 @@ test(() => {
|
||||||
for (const key of properties) {
|
for (const key of properties) {
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
assert_own_property(tests, key, `Should have a test for '${key}' property`);
|
assert_own_property(tests, key, `Should have a test for '${key}' property`);
|
||||||
const { setup, test } = tests[key];
|
const { setup, test, shouldFlush } = tests[key];
|
||||||
|
|
||||||
// Setup target element
|
// Setup target element
|
||||||
const div = createDiv(t);
|
const div = createDiv(t);
|
||||||
|
@ -276,7 +333,7 @@ for (const key of properties) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup animation
|
// Setup animation
|
||||||
const animation = setup(div);
|
const animation = await setup(div);
|
||||||
|
|
||||||
// Setup transition start point
|
// Setup transition start point
|
||||||
div.style.transition = 'opacity 100s';
|
div.style.transition = 'opacity 100s';
|
||||||
|
@ -291,17 +348,24 @@ for (const key of properties) {
|
||||||
// If the test function produced a style change event it will have triggered
|
// If the test function produced a style change event it will have triggered
|
||||||
// a transition.
|
// a transition.
|
||||||
|
|
||||||
// Wait for the animation to start and then for at least one animation
|
// Wait for the animation to start and then for at least two animation
|
||||||
// frame to give the transitionrun event a chance to be dispatched.
|
// frames to give the transitionrun event a chance to be dispatched.
|
||||||
assert_true(
|
assert_true(
|
||||||
typeof animation.ready !== 'undefined',
|
typeof animation.ready !== 'undefined',
|
||||||
'Should have a valid animation to wait on'
|
'Should have a valid animation to wait on'
|
||||||
);
|
);
|
||||||
await animation.ready;
|
await animation.ready;
|
||||||
await waitForAnimationFrames(1);
|
await waitForAnimationFrames(2);
|
||||||
|
|
||||||
assert_false(gotTransition, 'A transition should NOT have been triggered');
|
if (shouldFlush) {
|
||||||
}, `Animation.${key} does NOT trigger a style change event`);
|
assert_true(gotTransition, 'A transition should have been triggered');
|
||||||
|
} else {
|
||||||
|
assert_false(
|
||||||
|
gotTransition,
|
||||||
|
'A transition should NOT have been triggered'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, `Animation.${key} produces expected style change events`);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче