Merge autoland to mozilla-central. a=merge

This commit is contained in:
Gurzau Raul 2019-05-20 16:42:23 +03:00
Родитель 866936d99a 36731b4fb2
Коммит ce435076fa
105 изменённых файлов: 3111 добавлений и 519 удалений

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

@ -753,11 +753,6 @@ class ContentSessionStore {
this.restoreHistory(data);
break;
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);
break;
case "SessionStore:resetRestore":

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

@ -4310,8 +4310,7 @@ var SessionStoreInternal = {
browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent",
{loadArguments, isRemotenessUpdate,
reason: aOptions.restoreContentReason ||
RESTORE_TAB_CONTENT_REASON.SET_STATE,
requestTime: Services.telemetry.msSystemNow()});
RESTORE_TAB_CONTENT_REASON.SET_STATE});
// Focus the tab's content area.
if (aTab.selected && !window.isBlankPageURL(uri)) {

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

@ -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_CHROME_ENABLED_PREF = "devtools.inspector.chrome.three-pane-enabled";
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.
@ -1299,6 +1300,7 @@ Inspector.prototype = {
executeSoon(() => {
try {
selfUpdate(this.selection.nodeFront);
this.telemetry.scalarAdd(TELEMETRY_SCALAR_NODE_SELECTION_COUNT, 1);
} catch (ex) {
console.error(ex);
}

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

@ -9,9 +9,6 @@ const ChromeUtils = require("ChromeUtils");
const Services = require("Services");
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
const { E10SUtils } = require("resource://gre/modules/E10SUtils.jsm");
const Telemetry = require("devtools/client/shared/telemetry");
const telemetry = new Telemetry();
function readInputStreamToString(stream) {
return NetUtil.readInputStreamToString(stream, stream.available());
@ -85,7 +82,6 @@ BrowserElementWebNavigation.prototype = {
triggeringPrincipal: E10SUtils.serializePrincipal(
triggeringPrincipal ||
Services.scriptSecurityManager.createNullPrincipal({})),
requestTime: telemetry.msSystemNow(),
});
},

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

@ -5,7 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Animation.h"
#include "AnimationUtils.h"
#include "mozAutoDocUpdate.h"
#include "mozilla/dom/AnimationBinding.h"
#include "mozilla/dom/AnimationPlaybackEvent.h"
#include "mozilla/dom/Document.h"
@ -14,10 +16,13 @@
#include "mozilla/AnimationEventDispatcher.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/DeclarationBlock.h"
#include "mozilla/Maybe.h" // For Maybe
#include "mozilla/TypeTraits.h" // For std::forward<>
#include "nsAnimationManager.h" // For CSSAnimation
#include "nsComputedDOMStyle.h"
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
#include "nsDOMCSSAttrDeclaration.h" // For nsDOMCSSAttributeDeclaration
#include "nsThreadUtils.h" // For nsRunnableMethod and nsRevocableEventPtr
#include "nsTransitionManager.h" // For CSSTransition
#include "PendingAnimationTracker.h" // For PendingAnimationTracker
@ -168,6 +173,8 @@ void Animation::SetEffectNoUpdate(AnimationEffect* aEffect) {
ReschedulePendingTasks();
}
MaybeScheduleReplacementCheck();
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
}
@ -594,6 +601,124 @@ void Animation::Reverse(ErrorResult& aRv) {
// 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:
@ -650,7 +775,14 @@ void Animation::Tick() {
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) {
return;
@ -837,7 +969,8 @@ bool Animation::ShouldBeSynchronizedWithMainThread(
void Animation::UpdateRelevance() {
bool wasRelevant = mIsRelevant;
mIsRelevant = HasCurrentEffect() || IsInEffect();
mIsRelevant = mReplaceState != AnimationReplaceState::Removed &&
(HasCurrentEffect() || IsInEffect());
// Notify animation observers.
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 {
// 0. Object-equality case
if (&aOther == this) {
@ -989,11 +1234,27 @@ void Animation::ComposeStyle(RawServoAnimationValueMap& aComposeResult,
void Animation::NotifyEffectTimingUpdated() {
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");
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() {
if (!IsNewlyStarted() || !mEffect) {
return;
@ -1179,7 +1440,7 @@ void Animation::ResumeAt(const TimeDuration& aReadyTime) {
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
// to notify observers.
@ -1503,7 +1764,7 @@ void Animation::QueuePlaybackEvent(const nsAString& aName,
AnimationPlaybackEventInit init;
if (aName.EqualsLiteral("finish")) {
if (aName.EqualsLiteral("finish") || aName.EqualsLiteral("remove")) {
init.mCurrentTime = GetCurrentTimeAsDouble();
}
if (mTimeline) {

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

@ -51,15 +51,7 @@ class Animation : public DOMEventTargetHelper,
public:
explicit Animation(nsIGlobalObject* aGlobal)
: DOMEventTargetHelper(aGlobal),
mPlaybackRate(1.0),
mAnimationIndex(sNextAnimationIndex++),
mCachedChildIndex(-1),
mPendingState(PendingState::NotPending),
mFinishedAtLastComposeStyle(false),
mIsRelevant(false),
mFinishedIsResolved(false),
mSyncWithGeometricAnimations(false) {}
: DOMEventTargetHelper(aGlobal), mAnimationIndex(sNextAnimationIndex++) {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Animation, DOMEventTargetHelper)
@ -120,12 +112,14 @@ class Animation : public DOMEventTargetHelper,
bool Pending() const { return mPendingState != PendingState::NotPending; }
virtual bool PendingFromJS() const { return Pending(); }
AnimationReplaceState ReplaceState() const { return mReplaceState; }
virtual Promise* GetReady(ErrorResult& aRv);
Promise* GetFinished(ErrorResult& aRv);
IMPL_EVENT_HANDLER(finish);
IMPL_EVENT_HANDLER(cancel);
IMPL_EVENT_HANDLER(remove);
void Cancel(PostRestyleMode aPostRestyle = PostRestyleMode::IfNeeded);
@ -147,6 +141,9 @@ class Animation : public DOMEventTargetHelper,
void UpdatePlaybackRate(double aPlaybackRate);
void Reverse(ErrorResult& aRv);
void Persist();
void CommitStyles(ErrorResult& aRv);
bool IsRunningOnCompositor() const;
virtual void Tick();
@ -329,6 +326,25 @@ class Animation : public DOMEventTargetHelper,
bool IsRelevant() const { return mIsRelevant; }
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.
*/
@ -366,6 +382,8 @@ class Animation : public DOMEventTargetHelper,
const nsCSSPropertyIDSet& aPropertiesToSkip);
void NotifyEffectTimingUpdated();
void NotifyEffectPropertiesUpdated();
void NotifyEffectTargetUpdated();
void NotifyGeometricAnimationsStartingThisFrame();
/**
@ -481,6 +499,9 @@ class Animation : public DOMEventTargetHelper,
return GetCurrentTimeForHoldTime(Nullable<TimeDuration>());
}
void ScheduleReplacementCheck();
void MaybeScheduleReplacementCheck();
// Earlier side of the elapsed time range reported in CSS Animations and CSS
// Transitions events.
//
@ -527,7 +548,7 @@ class Animation : public DOMEventTargetHelper,
Nullable<TimeDuration> mHoldTime; // Animation timescale
Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
double mPlaybackRate;
double mPlaybackRate = 1.0;
Maybe<double> mPendingPlaybackRate;
// 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
// 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
// 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
// (see TriggerOnNextTick for details).
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
// getAnimations() list.
bool mIsRelevant;
bool mIsRelevant = false;
// 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
// in that case mFinished is immediately reset to represent a new current
// finished promise.
bool mFinishedIsResolved;
bool mFinishedIsResolved = false;
// 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
// the main thread.
bool mSyncWithGeometricAnimations;
bool mSyncWithGeometricAnimations = false;
RefPtr<MicroTaskRunnable> mFinishNotificationTask;

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

@ -8,6 +8,8 @@
#define mozilla_AnimationTarget_h
#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/RefPtr.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
#endif // mozilla_AnimationTarget_h

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

@ -188,13 +188,6 @@ void DocumentTimeline::MostRecentRefreshTimeUpdated() {
}
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();
}

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

@ -394,6 +394,26 @@ class EffectCompositeOrderComparator {
};
} // 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(
const dom::Element* aElement, PseudoStyleType aPseudoType,
CascadeLevel aCascadeLevel, RawServoAnimationValueMap* aAnimationValues) {
@ -417,16 +437,8 @@ bool EffectCompositor::GetServoAnimationRule(
}
sortedEffectList.Sort(EffectCompositeOrderComparator());
// If multiple animations affect the same property, animations with higher
// composite order (priority) override or add or animations with lower
// priority.
const nsCSSPropertyIDSet propertiesToSkip =
aCascadeLevel == CascadeLevel::Animations
? effectSet->PropertiesForAnimationsLevel().Inverse()
: effectSet->PropertiesForAnimationsLevel();
for (KeyframeEffect* effect : sortedEffectList) {
effect->GetAnimation()->ComposeStyle(*aAnimationValues, propertiesToSkip);
}
ComposeSortedEffects(sortedEffectList, effectSet, aCascadeLevel,
aAnimationValues);
MOZ_ASSERT(effectSet == EffectSet::GetEffectSet(aElement, aPseudoType),
"EffectSet should not change while composing style");
@ -434,6 +446,59 @@ bool EffectCompositor::GetServoAnimationRule(
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(
dom::Element* aElement, PseudoStyleType aPseudoType) {
if (aPseudoType == PseudoStyleType::NotPseudo) {
@ -862,4 +927,53 @@ bool EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags,
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

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

@ -8,7 +8,9 @@
#define mozilla_EffectCompositor_h
#include "mozilla/AnimationPerformanceWarning.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/HashTable.h"
#include "mozilla/Maybe.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/PseudoElementHashEntry.h"
@ -38,6 +40,7 @@ struct NonOwningAnimationTarget;
namespace dom {
class Animation;
class Element;
class KeyframeEffect;
} // namespace dom
class EffectCompositor {
@ -116,8 +119,9 @@ class EffectCompositor {
dom::Element* aElement,
PseudoStyleType aPseudoType);
// Get animation rule for stylo. This is an equivalent of GetAnimationRule
// and will be called from servo side.
// Get the animation rule for the appropriate level of the cascade for
// a (pseudo-)element. Called from the Servo side.
//
// The animation rule is stored in |RawServoAnimationValueMap|.
// We need to be careful while doing any modification because it may cause
// some thread-safe issues.
@ -126,6 +130,15 @@ class EffectCompositor {
CascadeLevel aCascadeLevel,
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;
static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
@ -199,6 +212,12 @@ class EffectCompositor {
// at aElement.
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.
//
// If |aPseudoType| is ::after, ::before or ::marker, returns the generated
@ -239,6 +258,8 @@ class EffectCompositor {
mElementsToRestyle;
bool mIsInPreTraverse = false;
HashSet<OwningAnimationTarget> mElementsToReduce;
};
} // namespace mozilla

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

@ -317,7 +317,7 @@ nsCSSPropertyIDSet KeyframeEffect::GetPropertiesForCompositor(
nsCSSPropertyIDSet properties;
if (!IsInEffect() && !IsCurrent()) {
if (!mAnimation || !mAnimation->IsRelevant()) {
return properties;
}
@ -342,14 +342,14 @@ nsCSSPropertyIDSet KeyframeEffect::GetPropertiesForCompositor(
return properties;
}
bool KeyframeEffect::HasAnimationOfPropertySet(
const nsCSSPropertyIDSet& aPropertySet) const {
nsCSSPropertyIDSet KeyframeEffect::GetPropertySet() const {
nsCSSPropertyIDSet result;
for (const AnimationProperty& property : mProperties) {
if (aPropertySet.HasProperty(property.mProperty)) {
return true;
result.AddProperty(property.mProperty);
}
}
return false;
return result;
}
#ifdef DEBUG
@ -418,6 +418,10 @@ void KeyframeEffect::UpdateProperties(const ComputedStyle* aStyle) {
MarkCascadeNeedsUpdate();
if (mAnimation) {
mAnimation->NotifyEffectPropertiesUpdated();
}
RequestRestyle(EffectCompositor::RestyleType::Layer);
}
@ -575,13 +579,10 @@ void KeyframeEffect::ComposeStyle(RawServoAnimationValueMap& aComposeResult,
if (HasPropertiesThatMightAffectOverflow()) {
nsPresContext* presContext =
nsContentUtils::GetContextForContent(mTarget->mElement);
if (presContext) {
TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
EffectSet* effectSet =
EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
MOZ_ASSERT(effectSet,
"ComposeStyle should only be called on an effect "
"that is part of an effect set");
if (presContext && effectSet) {
TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
effectSet->UpdateLastOverflowAnimationSyncTime(now);
}
}
@ -792,7 +793,9 @@ void KeyframeEffect::UpdateTargetRegistration() {
// something calls Animation::UpdateRelevance. Whenever our timing changes,
// we should be notifying our Animation before calling this, so
// 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");
if (isRelevant && !mInEffectSet) {
@ -999,6 +1002,10 @@ void KeyframeEffect::SetTarget(
mAnimation->ReschedulePendingTasks();
}
}
if (mAnimation) {
mAnimation->NotifyEffectTargetUpdated();
}
}
static void CreatePropertyValue(
@ -1728,6 +1735,11 @@ bool KeyframeEffect::ContainsAnimatedScale(const nsIFrame* aFrame) const {
return false;
}
if (!mAnimation ||
mAnimation->ReplaceState() == AnimationReplaceState::Removed) {
return false;
}
for (const AnimationProperty& prop : mProperties) {
if (prop.mProperty != eCSSProperty_transform &&
prop.mProperty != eCSSProperty_scale &&

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

@ -183,9 +183,15 @@ class KeyframeEffect : public AnimationEffect {
void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
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
// of whether any property in the set is overridden by !important rule.
bool HasAnimationOfPropertySet(const nsCSSPropertyIDSet& aPropertySet) const;
// of whether any property in the set is overridden by an !important rule.
bool HasAnimationOfPropertySet(const nsCSSPropertyIDSet& aPropertySet) const {
return GetPropertySet().Intersects(aPropertySet);
}
// GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
// to a given CSS property if the effect includes the property and the

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

@ -1,5 +1,6 @@
[DEFAULT]
prefs =
dom.animations-api.autoremove.enabled=true
dom.animations-api.compositing.enabled=true
gfx.omta.background-color=true
layout.css.individual-transform.enabled=true

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

@ -578,5 +578,74 @@ promise_test(t => {
});
}, "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();
</script>

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

@ -14,6 +14,7 @@ support-files =
chrome/file_animate_xrays.html
mozilla/xhr_doc.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_get_animations.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_deferred_start.html]
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_get_animations.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);
}
/*
* 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 {
return mAttrs.GetAttr(aAttr);
}

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

@ -346,8 +346,8 @@ static nsresult PutToClipboard(
return rv;
}
nsresult nsCopySupport::HTMLCopy(Selection* aSel, Document* aDoc,
int16_t aClipboardID,
nsresult nsCopySupport::EncodeDocumentWithContextAndPutToClipboard(
Selection* aSel, Document* aDoc, int16_t aClipboardID,
bool aWithRubyAnnotation) {
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
// expose the full functionality in browser. See bug 1130891.
bool withRubyAnnotation = IsSelectionInsideRuby(sel);
// call the copy code
nsresult rv = HTMLCopy(sel, doc, aClipboardType, withRubyAnnotation);
nsresult rv = EncodeDocumentWithContextAndPutToClipboard(
sel, doc, aClipboardType, withRubyAnnotation);
if (NS_FAILED(rv)) {
return false;
}

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

@ -33,9 +33,9 @@ class nsCopySupport {
/**
* @param aDoc Needs to be not nullptr.
*/
static nsresult HTMLCopy(mozilla::dom::Selection* aSel,
mozilla::dom::Document* aDoc, int16_t aClipboardID,
bool aWithRubyAnnotation);
static nsresult EncodeDocumentWithContextAndPutToClipboard(
mozilla::dom::Selection* aSel, mozilla::dom::Document* aDoc,
int16_t aClipboardID, bool aWithRubyAnnotation);
// 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
@ -47,8 +47,7 @@ class nsCopySupport {
static nsresult ImageCopy(nsIImageLoadingContent* aImageElement,
nsILoadContext* aLoadContext, int32_t aCopyFlags);
// Get the selection as a transferable. Similar to HTMLCopy except does
// not deal with the clipboard.
// Get the selection as a transferable.
// @param aSelection Can be nullptr.
// @param aDocument 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);
bool IsVisibleNode(nsINode* aNode) {
MOZ_ASSERT(aNode, "null node");
bool IsInvisibleNodeAndShouldBeSkipped(nsINode& aNode) const {
if (mFlags & SkipInvisibleContent) {
// Treat the visibility of the ShadowRoot as if it were
// the host content.
@ -95,36 +93,39 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
// FIXME(emilio): I suspect instead of this a bunch of the GetParent()
// calls here should be doing GetFlattenedTreeParent, then this condition
// should be unreachable...
if (ShadowRoot* shadowRoot = ShadowRoot::FromNode(aNode)) {
aNode = shadowRoot->GetHost();
nsINode* node{&aNode};
if (ShadowRoot* shadowRoot = ShadowRoot::FromNode(node)) {
node = shadowRoot->GetHost();
}
if (aNode->IsContent()) {
nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
if (node->IsContent()) {
nsIFrame* frame = node->AsContent()->GetPrimaryFrame();
if (!frame) {
if (aNode->IsElement() && aNode->AsElement()->IsDisplayContents()) {
return true;
if (node->IsElement() && node->AsElement()->IsDisplayContents()) {
return false;
}
if (aNode->IsText()) {
if (node->IsText()) {
// We have already checked that our parent is visible.
//
// FIXME(emilio): Text not assigned to a <slot> in Shadow DOM should
// 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;
}
bool isVisible = frame->StyleVisibility()->IsVisible();
if (!isVisible && aNode->IsText()) return false;
}
if (node->IsHTMLElement(nsGkAtoms::rp)) {
// Ruby parentheses are part of ruby structure, hence
// shouldn't be stripped out even if it is not displayed.
return false;
}
return true;
}
bool isVisible = frame->StyleVisibility()->IsVisible();
if (!isVisible && node->IsText()) {
return true;
}
}
}
return false;
}
virtual bool IncludeInContext(nsINode* aNode);
@ -349,7 +350,7 @@ nsresult nsDocumentEncoder::SerializeNodeStart(nsINode& aOriginalNode,
}
}
if (!IsVisibleNode(&aOriginalNode)) {
if (IsInvisibleNodeAndShouldBeSkipped(aOriginalNode)) {
return NS_OK;
}
@ -411,7 +412,7 @@ nsresult nsDocumentEncoder::SerializeNodeEnd(nsINode& aNode, nsAString& aStr) {
}
}
if (!IsVisibleNode(&aNode)) {
if (IsInvisibleNodeAndShouldBeSkipped(aNode)) {
return NS_OK;
}
@ -429,11 +430,12 @@ nsresult nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
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};
nsINode* maybeFixedNode =
&fixupNodeDeterminer.GetFixupNodeFallBackToOriginalNode();
@ -449,6 +451,8 @@ nsresult nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
}
}
nsresult rv = NS_OK;
if (!aDontSerializeRoot) {
int32_t endOffset = -1;
if (aMaxLength > 0) {
@ -585,7 +589,9 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
if (!IsVisibleNode(aNode)) return NS_OK;
if (IsInvisibleNodeAndShouldBeSkipped(*aNode)) {
return NS_OK;
}
nsresult rv = NS_OK;
@ -788,11 +794,13 @@ nsresult nsDocumentEncoder::SerializeRangeToString(nsRange* aRange,
if (startContainer == endContainer && IsTextNode(startContainer)) {
if (mFlags & SkipInvisibleContent) {
// 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);
if (content && !content->GetPrimaryFrame()) {
nsIContent* parent = content->GetParent();
if (!parent || !IsVisibleNode(parent)) return NS_OK;
if (!parent || IsInvisibleNodeAndShouldBeSkipped(*parent)) {
return NS_OK;
}
}
}
rv = SerializeNodeStart(*startContainer, startOffset, endOffset,
@ -847,9 +855,9 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
aOutputString.Truncate();
nsString output;
static const size_t bufferSize = 2048;
static const size_t kStringBufferSizeInBytes = 2048;
if (!mCachedBuffer) {
mCachedBuffer = nsStringBuffer::Alloc(bufferSize).take();
mCachedBuffer = nsStringBuffer::Alloc(kStringBufferSizeInBytes).take();
if (NS_WARN_IF(!mCachedBuffer)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -975,7 +983,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
bool setOutput = false;
// Try to cache the buffer.
if (mCachedBuffer) {
if (mCachedBuffer->StorageSize() == bufferSize &&
if ((mCachedBuffer->StorageSize() == kStringBufferSizeInBytes) &&
!mCachedBuffer->IsReadonly()) {
mCachedBuffer->AddRef();
} else {

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

@ -466,7 +466,7 @@ class nsINode : public mozilla::dom::EventTarget {
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); }

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

@ -35,6 +35,9 @@ interface JSWindowActorChild {
[Throws]
readonly attribute BrowsingContext? browsingContext;
[Throws]
readonly attribute nsIDocShell? docShell;
// NOTE: As this returns a window proxy, it may not be currently referencing
// the document associated with this JSWindowActor. Generally prefer using
// `document`.

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

@ -76,7 +76,7 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_bug563329.html]
skip-if = true # Disabled due to timeouts.
[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_bug593959.html]
[test_bug603008.html]

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

@ -63,7 +63,6 @@ function forceScrollAndWait(scrollbox, callback) {
}
}
var kExtraEvents = 5;
var kDelta = 3;
function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum, callback) {
@ -91,11 +90,9 @@ function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum, callback
scrollbox.addEventListener("wheel", onwheel);
synthesizeWheel(scrollbox, 10, 10, event, win);
// then 5 additional pixel scrolls
// then additional pixel scroll
event.lineOrPageDeltaY = 0;
for (let i = 1; i <= kExtraEvents; ++i) {
synthesizeWheel(scrollbox, 10, 10, event, win);
}
}
function runTest() {
@ -147,7 +144,7 @@ function runTest() {
let postfix = isMomentum ? ", even after releasing the touchpad" : "";
// Normal scroll: scroll
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);
} else {
if (!isMomentum) {
@ -155,7 +152,7 @@ function runTest() {
is(scrollbox.scrollTop, scrollTopBefore, "Ctrl-scrolling shouldn't scroll while the user is touching the touchpad");
} else {
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");
}
}

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

@ -2653,14 +2653,6 @@ nsresult nsGenericHTMLElement::NewURIFromString(const nsAString& aURISpec,
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,
mozilla::ErrorResult& aError) {
// 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);
}
if (!IsRendered(*this)) {
if (!IsRendered()) {
GetTextContentInternal(aValue, aError);
} else {
nsRange::GetInnerTextNoFlush(aValue, aError, this);

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

@ -106,6 +106,14 @@ BrowsingContext* JSWindowActorChild::GetBrowsingContext(ErrorResult& aRv) {
return mManager->BrowsingContext();
}
nsIDocShell* JSWindowActorChild::GetDocShell(ErrorResult& aRv) {
if (BrowsingContext* bc = GetBrowsingContext(aRv)) {
return bc->GetDocShell();
}
return nullptr;
}
Nullable<WindowProxyHolder> JSWindowActorChild::GetContentWindow(
ErrorResult& aRv) {
if (BrowsingContext* bc = GetBrowsingContext(aRv)) {

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

@ -51,6 +51,7 @@ class JSWindowActorChild final : public JSWindowActor {
void AfterDestroy();
Document* GetDocument(ErrorResult& aRv);
BrowsingContext* GetBrowsingContext(ErrorResult& aRv);
nsIDocShell* GetDocShell(ErrorResult& aRv);
Nullable<WindowProxyHolder> GetContentWindow(ErrorResult& aRv);
protected:

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

@ -7,7 +7,5 @@ support-files =
[browser_domainPolicy.js]
[browser_memory_distribution_telemetry.js]
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]
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) {
#if defined(XP_LINUX)
return "pulse";
#elif defined(XP_MACOSX)
#if defined(XP_MACOSX)
return "audiounit";
#elif defined(XP_WIN)
return "wasapi";
#elif defined(ANDROID)
return "opensl";
#elif defined(__OpenBSD__)
return "sndio";
#else
return "pulse";
#endif
}

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

@ -516,8 +516,8 @@ bool SMILCSSValueType::SetPropertyValues(const SMILValue& aValue,
bool changed = false;
for (const auto& value : wrapper->mServoValues) {
changed |=
Servo_DeclarationBlock_SetPropertyToAnimationValue(aDecl.Raw(), value);
changed |= Servo_DeclarationBlock_SetPropertyToAnimationValue(aDecl.Raw(),
value, {});
}
return changed;

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

@ -12,7 +12,9 @@
enum AnimationPlayState { "idle", "running", "paused", "finished" };
[Constructor (optional AnimationEffect? effect = null,
enum AnimationReplaceState { "active", "removed", "persisted" };
[Constructor(optional AnimationEffect? effect = null,
optional AnimationTimeline? timeline)]
interface Animation : EventTarget {
attribute DOMString id;
@ -30,22 +32,30 @@ interface Animation : EventTarget {
readonly attribute AnimationPlayState playState;
[BinaryName="pendingFromJS"]
readonly attribute boolean pending;
[Pref="dom.animations-api.autoremove.enabled"]
readonly attribute AnimationReplaceState replaceState;
[Func="Document::IsWebAnimationsEnabled", Throws]
readonly attribute Promise<Animation> ready;
[Func="Document::IsWebAnimationsEnabled", Throws]
readonly attribute Promise<Animation> finished;
attribute EventHandler onfinish;
attribute EventHandler oncancel;
void cancel ();
[Pref="dom.animations-api.autoremove.enabled"]
attribute EventHandler onremove;
void cancel();
[Throws]
void finish ();
void finish();
[Throws, BinaryName="playFromJS"]
void play ();
void play();
[Throws, BinaryName="pauseFromJS"]
void pause ();
void pause();
void updatePlaybackRate (double playbackRate);
[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

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

@ -15,6 +15,6 @@ dictionary DocumentTimelineOptions {
};
[Func="Document::AreWebAnimationsTimelinesEnabled",
Constructor (optional DocumentTimelineOptions options)]
Constructor(optional DocumentTimelineOptions options)]
interface DocumentTimeline : AnimationTimeline {
};

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

@ -24,18 +24,18 @@ dictionary KeyframeEffectOptions : EffectTiming {
// processing on the `keyframes` object.
[Func="Document::IsWebAnimationsEnabled",
RunConstructorInCallerCompartment,
Constructor ((Element or CSSPseudoElement)? target,
Constructor((Element or CSSPseudoElement)? target,
object? keyframes,
optional (unrestricted double or KeyframeEffectOptions) options),
Constructor (KeyframeEffect source)]
Constructor(KeyframeEffect source)]
interface KeyframeEffect : AnimationEffect {
attribute (Element or CSSPseudoElement)? target;
[Pref="dom.animations-api.compositing.enabled"]
attribute IterationCompositeOperation iterationComposite;
[Pref="dom.animations-api.compositing.enabled"]
attribute CompositeOperation composite;
[Throws] sequence<object> getKeyframes ();
[Throws] void setKeyframes (object? keyframes);
[Throws] sequence<object> getKeyframes();
[Throws] void setKeyframes(object? keyframes);
};
// Non-standard extensions

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

@ -260,7 +260,7 @@ class MOZ_RAII JS_PUBLIC_API AutoDebuggerJobQueueInterruption {
enum class PromiseRejectionHandlingState { Unhandled, Handled };
typedef void (*PromiseRejectionTrackerCallback)(
JSContext* cx, JS::HandleObject promise,
JSContext* cx, bool mutedErrors, JS::HandleObject promise,
JS::PromiseRejectionHandlingState state, void* data);
/**

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

@ -1137,7 +1137,7 @@ static bool TrackUnhandledRejections(JSContext* cx, JS::HandleObject promise,
}
static void ForwardingPromiseRejectionTrackerCallback(
JSContext* cx, JS::HandleObject promise,
JSContext* cx, bool mutedErrors, JS::HandleObject promise,
JS::PromiseRejectionHandlingState state, void* data) {
AutoReportException are(cx);

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

@ -637,9 +637,15 @@ void JSRuntime::addUnhandledRejectedPromise(JSContext* cx,
return;
}
bool mutedErrors = false;
if (JSScript* script = cx->currentScript()) {
mutedErrors = script->mutedErrors();
}
void* data = cx->promiseRejectionTrackerCallbackData;
cx->promiseRejectionTrackerCallback(
cx, promise, JS::PromiseRejectionHandlingState::Unhandled, data);
cx, mutedErrors, promise, JS::PromiseRejectionHandlingState::Unhandled,
data);
}
void JSRuntime::removeUnhandledRejectedPromise(JSContext* cx,
@ -649,9 +655,15 @@ void JSRuntime::removeUnhandledRejectedPromise(JSContext* cx,
return;
}
bool mutedErrors = false;
if (JSScript* script = cx->currentScript()) {
mutedErrors = script->mutedErrors();
}
void* data = cx->promiseRejectionTrackerCallbackData;
cx->promiseRejectionTrackerCallback(
cx, promise, JS::PromiseRejectionHandlingState::Handled, data);
cx, mutedErrors, promise, JS::PromiseRejectionHandlingState::Handled,
data);
}
mozilla::non_crypto::XorShift128PlusRNG& JSRuntime::randomKeyGenerator() {

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

@ -225,6 +225,10 @@ static ContentMap& GetContentMap() {
template <typename TestType>
static bool HasMatchingAnimations(EffectSet& aEffects, TestType&& aTest) {
for (KeyframeEffect* effect : aEffects) {
if (!effect->GetAnimation() || !effect->GetAnimation()->IsRelevant()) {
continue;
}
if (aTest(*effect, aEffects)) {
return true;
}
@ -263,8 +267,7 @@ bool nsLayoutUtils::HasAnimationOfPropertySet(
return HasMatchingAnimations(
aFrame, aPropertySet,
[&aPropertySet](KeyframeEffect& aEffect, const EffectSet&) {
return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
aEffect.HasAnimationOfPropertySet(aPropertySet);
return aEffect.HasAnimationOfPropertySet(aPropertySet);
});
}
@ -294,8 +297,7 @@ bool nsLayoutUtils::HasAnimationOfPropertySet(
return HasMatchingAnimations(
*aEffectSet,
[&aPropertySet](KeyframeEffect& aEffect, const EffectSet& aEffectSet) {
return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
aEffect.HasAnimationOfPropertySet(aPropertySet);
return aEffect.HasAnimationOfPropertySet(aPropertySet);
});
}
@ -305,8 +307,7 @@ bool nsLayoutUtils::HasEffectiveAnimation(
return HasMatchingAnimations(
aFrame, aPropertySet,
[&aPropertySet](KeyframeEffect& aEffect, const EffectSet& aEffectSet) {
return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
aEffect.HasEffectiveAnimationOfPropertySet(aPropertySet,
return aEffect.HasEffectiveAnimationOfPropertySet(aPropertySet,
aEffectSet);
});
}

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

@ -41,6 +41,7 @@
#include "nsComponentManagerUtils.h"
#include "mozilla/Logging.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "nsIXULRuntime.h"
#include "jsapi.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) {
MOZ_ASSERT(!nsContentUtils::GetCurrentJSContext(),
"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) {
// This is the FlushType::Style case.

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

@ -2747,8 +2747,8 @@ nsresult nsFrameSelection::UpdateSelectionCacheOnRepaintSelection(
nsCOMPtr<Document> aDoc = presShell->GetDocument();
if (aDoc && aSel && !aSel->IsCollapsed()) {
return nsCopySupport::HTMLCopy(aSel, aDoc, nsIClipboard::kSelectionCache,
false);
return nsCopySupport::EncodeDocumentWithContextAndPutToClipboard(
aSel, aDoc, nsIClipboard::kSelectionCache, false);
}
return NS_OK;
@ -2762,8 +2762,9 @@ int16_t AutoCopyListener::sClipboardID = -1;
* What we do now:
* On every selection change, we copy to the clipboard anew, creating a
* HTML buffer, a transferable, an nsISupportsString and
* a huge mess every time. This is basically what nsCopySupport::HTMLCopy()
* does to move the selection into the clipboard for Edit->Copy.
* a huge mess every time. This is basically what
* 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:
* Create a singleton transferable with our own magic converter. When selection
@ -2830,8 +2831,10 @@ void AutoCopyListener::OnSelectionChange(Document* aDocument,
return;
}
// Call the copy code.
DebugOnly<nsresult> rv =
nsCopySupport::HTMLCopy(&aSelection, aDocument, sClipboardID, false);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "nsCopySupport::HTMLCopy() failed");
nsCopySupport::EncodeDocumentWithContextAndPutToClipboard(
&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.
// TODO(heycam): Handle these elsewhere.
struct RawServoAnimationValueTable;
struct RawServoAnimationValueMap;
#endif // mozilla_ServoBindingTypes_h

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

@ -24,6 +24,7 @@
// to just generate the forward declaration.
SERVO_BOXED_TYPE(StyleSet, RawServoStyleSet)
SERVO_BOXED_TYPE(AnimationValueMap, RawServoAnimationValueMap)
SERVO_BOXED_TYPE(AuthorStyles, RawServoAuthorStyles)
SERVO_BOXED_TYPE(SelectorList, RawServoSelectorList)
SERVO_BOXED_TYPE(SharedMemoryBuilder, RawServoSharedMemoryBuilder)

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

@ -127,6 +127,19 @@ VARCACHE_PREF(
// 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?
#ifdef RELEASE_OR_BETA
# 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.javascript", 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.res", false);
pref("network.protocol-handler.external.shell", false);

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

@ -7,8 +7,6 @@
#include "PKCS11ModuleDB.h"
#include "ScopedNSSTypes.h"
#include "mozilla/Telemetry.h"
#include "nsCRTGlue.h"
#include "nsIMutableArray.h"
#include "nsNSSCertHelper.h"
#include "nsNSSComponent.h"
@ -63,32 +61,6 @@ PKCS11ModuleDB::DeleteModule(const nsAString& aModuleName) {
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.
NS_IMETHODIMP
PKCS11ModuleDB::AddModule(const nsAString& aModuleName,
@ -131,23 +103,6 @@ PKCS11ModuleDB::AddModule(const nsAString& aModuleName,
if (srv != SECSuccess) {
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;
}

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

@ -8,8 +8,6 @@
#include "nsIPKCS11ModuleDB.h"
#include "nsString.h"
namespace mozilla {
namespace psm {
@ -31,9 +29,6 @@ class PKCS11ModuleDB : public nsIPKCS11ModuleDB {
virtual ~PKCS11ModuleDB() {}
};
void GetModuleNameForTelemetry(/*in*/ const SECMODModule* module,
/*out*/ nsString& result);
} // namespace psm
} // namespace mozilla

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

@ -9,7 +9,6 @@
#include "EnterpriseRoots.h"
#include "ExtendedValidation.h"
#include "NSSCertDBTrustDomain.h"
#include "PKCS11ModuleDB.h"
#include "ScopedNSSTypes.h"
#include "SharedSSLState.h"
#include "cert.h"
@ -1793,28 +1792,6 @@ nsresult nsNSSComponent::InitializeNSS() {
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"));
{

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

@ -50,40 +50,13 @@ function checkTestModuleExists() {
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() {
// Check that if we have never added the test module, that we don't find it
// in the module list.
checkTestModuleNotPresent();
checkModuleTelemetry();
// Check that adding the test module makes it appear in the module list.
loadPKCS11TestModule(true);
checkModuleTelemetry(
`${AppConstants.DLL_PREFIX}pkcs11testmodule${AppConstants.DLL_SUFFIX}`);
let testModule = checkTestModuleExists();
// Check that listing the slots for the test module works.

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

@ -5,12 +5,22 @@
//! FFI implementations for types listed in ServoBoxedTypeList.h.
use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use crate::properties::animated_properties::AnimationValueMap;
use to_shmem::SharedMemoryBuilder;
// 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
// 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")]
unsafe impl HasFFI for SharedMemoryBuilder {
type FFIType = crate::gecko_bindings::bindings::RawServoSharedMemoryBuilder;

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

@ -9,9 +9,7 @@
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::sugar::ownership::{HasFFI, HasSimpleFFI};
use itertools::{EitherOrBoth, Itertools};
use crate::properties::{CSSWideKeyword, PropertyDeclaration};
use crate::properties::longhands;
@ -190,13 +188,6 @@ impl AnimatedProperty {
/// composed for each TransitionProperty.
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
/// property in order to be interpolated with another one. When interpolating,
/// 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.
pub fn drain(&mut self) -> 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::media_queries::MediaList;
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::{ComputedValues, Importance, NonCustomPropertyId};
use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId};
@ -913,6 +913,36 @@ fn resolve_rules_for_element_with_context<'a>(
.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]
pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
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(
declarations: &RawServoDeclarationBlock,
property_id: PropertyId,
@ -4123,19 +4175,13 @@ fn set_property(
} else {
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();
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.update(source_declarations.drain(), importance, &mut updates)
});
true
set_property_to_declarations(
declarations,
&mut source_declarations,
before_change_closure,
importance,
)
}
#[no_mangle]
@ -4167,13 +4213,17 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
declarations: &RawServoDeclarationBlock,
animation_value: &RawServoAnimationValue,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(
AnimationValue::as_arc(&animation_value).uncompute(),
let mut source_declarations =
SourcePropertyDeclaration::with_one(AnimationValue::as_arc(&animation_value).uncompute());
set_property_to_declarations(
declarations,
&mut source_declarations,
before_change_closure,
Importance::Normal,
)
})
}
#[no_mangle]

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

@ -21,16 +21,12 @@ job-template:
attributes:
artifact_prefix: public
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:
by-platform:
android.*: taskcluster/taskgraph/manifests/fennec_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
attributes:
artifact_map:
by-project:
by-release-type:
beta|release.*|esr.*: taskcluster/taskgraph/manifests/firefox_candidates.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
attributes:
artifact_map:
by-project:
mozilla-release: taskcluster/taskgraph/manifests/fennec_candidates.yml
mozilla-beta: taskcluster/taskgraph/manifests/fennec_candidates.yml
by-release-type:
beta|release.*|esr.*: taskcluster/taskgraph/manifests/fennec_candidates.yml
default: taskcluster/taskgraph/manifests/fennec_nightly.yml

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

@ -269,7 +269,7 @@ win32-shippable/opt:
by-release-type:
nightly: true
beta: true
release: true
release.*: true
esr.*: false
default:
by-project:
@ -832,7 +832,7 @@ win32-devedition-nightly/opt:
by-release-type:
nightly: true
beta: true
release: true
release.*: true
default:
by-project:
# browser/confvars.sh looks for nightly-try

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

@ -42,7 +42,7 @@ jobs:
- releases/bouncer_firefox_beta.py
release:
- releases/bouncer_firefox_release.py
esr60:
esr.*:
- releases/bouncer_firefox_esr.py
default:
- releases/bouncer_firefox_beta.py
@ -51,6 +51,7 @@ jobs:
mozilla-beta: LATEST_FIREFOX_RELEASED_DEVEL_VERSION
mozilla-release: LATEST_FIREFOX_VERSION
mozilla-esr60: FIREFOX_ESR
mozilla-esr68: FIREFOX_ESR_NEXT
default: LATEST_FIREFOX_DEVEL_VERSION
products-url: https://product-details.mozilla.org/1.0/firefox_versions.json
treeherder:

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

@ -34,12 +34,14 @@ jobs:
beta: [32]
release: [145]
esr60: [806]
esr68: [882]
default: []
staging:
by-release-type:
beta: [32]
release: [145]
esr60: [806]
esr68: [875]
default: []
treeherder:
platform: firefox-release/opt
@ -50,10 +52,13 @@ jobs:
description: Schedule Firefox publishing in balrog (bz2)
name: release-firefox_schedule_publishing_in_balrog-bz2
shipping-product: firefox
run-on-releases: [esr60]
run-on-releases: [esr60, esr68]
worker:
product: firefox
publish-rules: [521]
publish-rules:
by-release-type:
esr60: [521]
default: []
blob-suffix: -bz2
treeherder:
platform: firefox-release/opt

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

@ -39,12 +39,13 @@ jobs:
by-release-type:
beta: ["beta", "beta-localtest", "beta-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: []
rules-to-update:
by-release-type:
beta: ["firefox-beta-cdntest", "firefox-beta-localtest"]
release(-rc)?: ["firefox-release-cdntest", "firefox-release-localtest"]
esr68: ["firefox-esr68-cdntest", "firefox-esr68-localtest"]
esr60: ["firefox-esr60-cdntest", "firefox-esr60-localtest"]
default: []
platforms: ["linux", "linux64", "macosx64", "win32", "win64", "win64-aarch64"]
@ -58,11 +59,14 @@ jobs:
name: submit-toplevel-firefox-release-to-balrog-bz2
description: Submit toplevel Firefox release to balrog
shipping-product: firefox
run-on-releases: [esr60]
run-on-releases: [esr60, esr68]
worker:
product: firefox
channel-names: ["esr", "esr-localtest", "esr-cdntest"]
rules-to-update: ["esr52-cdntest", "esr52-localtest"]
channel-names: ["esr", "esr-localtest", "esr-cdntest", "esr-localtest-next", "esr-cdntest-next"]
rules-to-update:
by-release-type:
esr68: ["esr52-cdntest-next", "esr52-localtest-next"]
esr60: ["esr52-cdntest", "esr52-localtest"]
platforms: ["linux", "linux64", "macosx64", "win32", "win64"]
blob-suffix: -bz2
complete-mar-filename-pattern: '%s-%s.bz2.complete.mar'

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

@ -79,6 +79,10 @@ jobs:
firefox-esr-latest-ssl: installer-ssl
firefox-esr-latest: installer
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:
firefox-latest-ssl: installer-ssl
firefox-latest: installer

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

@ -57,7 +57,7 @@ jobs:
- releases/bouncer_firefox_beta.py
release:
- releases/bouncer_firefox_release.py
esr60:
esr.*:
- releases/bouncer_firefox_esr.py
default:
- releases/bouncer_firefox_beta.py

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

@ -52,11 +52,11 @@ jobs:
firefox:
bouncer-platforms: ['linux', 'linux64', 'osx', 'win', 'win64', 'win64-aarch64']
bouncer-products:
by-project:
by-release-type:
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
mozilla-esr60: ['complete-mar', 'complete-mar-bz2', 'installer', 'installer-ssl', 'partial-mar']
jamun: ['complete-mar', 'complete-mar-bz2', 'installer', 'installer-ssl', 'partial-mar']
esr60: ['complete-mar', 'complete-mar-bz2', 'installer', 'installer-ssl', 'partial-mar']
shipping-product: firefox
treeherder:
platform: firefox-release/opt

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

@ -59,7 +59,7 @@ jobs:
firefox:
shipping-product: firefox
attributes:
build_platform: linux64-snap-shippable
build_platform: linux64-shippable
build_type: opt
treeherder:
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"
default: null
esr60: "52.0esr"
esr68: "68.0esr"
default: "default"
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
package-formats:
by-release-type:
esr60:
esr(60|68):
by-build-platform:
linux.*: [mar, mar-bz2]
linux4\b.*: [mar, mar-bz2]

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

@ -73,7 +73,7 @@ job-template:
- repackage/win64_signed.py
package-formats:
by-release-type:
esr60:
esr(60|68):
by-build-platform:
linux.*: [mar, mar-bz2]
linux4\b.*: [mar, mar-bz2]

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

@ -46,10 +46,10 @@
},
"arrow": {
"hashes": [
"sha256:3397e5448952e18e1295bf047014659effa5ae8da6a5371d37ff0ddc46fa6872",
"sha256:6f54d9f016c0b7811fac9fb8c2c7fa7421d80c54dbdd75ffb12913c55db60b8a"
"sha256:002f2315cf4c8404de737c42860441732d339bbc57fee584e2027520e055ecc1",
"sha256:82dd5e13b733787d4eb0fef42d1ee1a99136dc1d65178f70373b3678b3181bfc"
],
"version": "==0.13.1"
"version": "==0.13.2"
},
"asn1crypto": {
"hashes": [
@ -74,11 +74,11 @@
},
"awscli": {
"hashes": [
"sha256:b7a6e758a7d2e7230e4e21acab9f80db2fd31248333ca8575b4538a5c43ebd2c",
"sha256:fae8839c4ddf6e7fb49543beec8d9659afd60e2fa23481ee723390f0a3a7d0f7"
"sha256:34e7ee2bd912e6613ac064099c13e2114722d508fc35e01fd0dfc3be41ddd92c",
"sha256:f73c11e6726a5ca25df3399762fae7f6882c71e097dc622d0e4743c9f8e84526"
],
"index": "pypi",
"version": "==1.16.156"
"version": "==1.16.161"
},
"backports.lzma": {
"hashes": [
@ -88,10 +88,10 @@
},
"botocore": {
"hashes": [
"sha256:1517c52eaa3056d0e81f9a81b580d7f28440e7e1523d10a8acc8160c56be7113",
"sha256:19d9d56fcf4f16ffea8a929bbf3c72db3458b6c1f306c04031f3166759cd62ac"
"sha256:5e4774c106bb02f8e4639818c2f8157b8ec114a76e481e17cd3fe6955206e088",
"sha256:cfc667e7888aad09ead8f7e32129ea90aa5c7f602531094954bf6305db74aac4"
],
"version": "==1.12.146"
"version": "==1.12.151"
},
"certifi": {
"hashes": [
@ -370,11 +370,11 @@
},
"requests": {
"hashes": [
"sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
"sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
],
"index": "pypi",
"version": "==2.21.0"
"version": "==2.22.0"
},
"rsa": {
"hashes": [
@ -392,11 +392,11 @@
},
"scriptworker": {
"hashes": [
"sha256:44b19ef0ddfe14309ddb035e4f6e82da8d9eb3d7c3de8ed82ee74a75beefb767",
"sha256:4b7bd567c8b511f1a87c68ac541c94b730d6f307ad86bb0af279ac30ef5867e9"
"sha256:836181e36befcd74bb6b9457fd9336d8efa1350e77c285f0dc32bdb0ef6e4270",
"sha256:d858c4e0dae3305dec3683458d2e879752b0a3645e9f95278b717d53d45c2809"
],
"index": "pypi",
"version": "==23.0.4"
"version": "==23.0.5"
},
"sh": {
"hashes": [

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

@ -367,11 +367,14 @@ Publishes signed langpacks to archive.mozilla.org
release-update-verify
---------------------
Verifies the contents and package of release update MARs.
release-secondary-update-verify
-------------------------------
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
----------------------------
Creates configs for release-update-verify tasks
@ -380,6 +383,10 @@ release-secondary-update-verify-config
--------------------------------------
Creates configs for release-secondary-update-verify tasks
release-update-verify-config-next
---------------------------------
Creates configs for release-update-verify-next tasks
release-updates-builder
-----------------------
Top level Balrog blob submission & patcher/update verify config updates.

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

@ -332,7 +332,7 @@ mapping:
checksums_path: ${path_platform}/${locale}/Firefox Setup ${version}.msi
target.complete.mar:
<<: *default
description: "The main installer we ship our mobile products baked within"
description: "Complete MAR to serve as updates"
all_locales: true
from:
- mar-signing
@ -341,6 +341,18 @@ mapping:
update_balrog_manifest: true
destinations:
- ${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}:
<<: *default
description: "Partials MAR files to serve as updates"

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

@ -315,7 +315,7 @@ def make_task_worker(config, jobs):
signing_task_ref = "<" + str(signing_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(
config, job, platform, locale
)
@ -329,7 +329,7 @@ def make_task_worker(config, jobs):
'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(
config, job, platform=platform, locale=locale)

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

@ -145,7 +145,7 @@ def make_beetmover_checksums_worker(config, jobs):
'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(
config, job, platform, locale
)

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

@ -138,7 +138,7 @@ def make_beetmover_checksums_worker(config, jobs):
'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(
config, job, platform, locales
)

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

@ -358,7 +358,7 @@ def make_task_worker(config, jobs):
locale = job["attributes"].get("locale")
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(
config, job, platform, locale)
else:
@ -373,7 +373,7 @@ def make_task_worker(config, jobs):
'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(
config, job, platform=platform, locale=locale)
@ -412,7 +412,7 @@ def make_partials_artifacts(config, jobs):
partials_info = get_partials_info_from_params(
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(
generate_beetmover_partials_artifact_map(
config, job, partials_info, platform=platform, locale=locale))

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

@ -137,7 +137,7 @@ def make_beetmover_checksums_worker(config, jobs):
raise NotImplementedError(
"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,
job, platform, locale)
else:
@ -149,7 +149,7 @@ def make_beetmover_checksums_worker(config, jobs):
'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(
config, job, platform=platform)

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

@ -131,7 +131,8 @@ def make_task_worker(config, jobs):
**{'release-level': config.params.release_level()}
)
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

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

@ -125,7 +125,7 @@ def make_task_worker(config, jobs):
platform = job["attributes"]["build_platform"]
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(
config, job, platform, locale,
)
@ -139,7 +139,7 @@ def make_task_worker(config, jobs):
'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(
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
# amend artifactMap entries as well
if should_use_artifact_map(backup_platform, config.params['project']):
if should_use_artifact_map(backup_platform):
platform_mapping = {
'linux64': 'linux-x86_64',
'linux': 'linux-i686',

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

@ -156,7 +156,7 @@ def make_task_worker(config, jobs):
platform = job["attributes"]["build_platform"]
# 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(
config, job, platform=None, locale=None
)
@ -168,7 +168,7 @@ def make_task_worker(config, jobs):
worker['upstream-artifacts'] = upstream_artifacts
# 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(
config, job, platform=platform)

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

@ -19,7 +19,7 @@ transforms = TransformSequence()
def add_command(config, tasks):
config_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
for task in tasks:

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

@ -33,6 +33,8 @@ INCLUDE_VERSION_REGEXES = {
"devedition_hack": r"'^((?!58\.0b1$)\d+\.\d+(b\d+)?)$'",
# Same as nonbeta, except for the esr suffix
"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 = {

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

@ -427,8 +427,10 @@ def generate_beetmover_upstream_artifacts(config, job, platform, locale=None, de
resolve_keyed_by(
job, 'attributes.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']))
upstream_artifacts = list()
@ -469,6 +471,11 @@ def generate_beetmover_upstream_artifacts(config, job, platform, locale=None, de
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:
continue
@ -556,8 +563,10 @@ def generate_beetmover_artifact_map(config, job, **kwargs):
resolve_keyed_by(
job, 'attributes.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']))
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(
job, 'attributes.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']))
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
# should_use_artifact_map {{{
def should_use_artifact_map(platform, project):
def should_use_artifact_map(platform):
"""Return True if this task uses the beetmover artifact map.
This function exists solely for the beetmover artifact map
migration.
"""
if 'linux64-snap-shippable' 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
return 'devedition' not in platform

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

@ -91,8 +91,8 @@ def cli(runner_class=MarionetteTestRunner, parser_class=MarionetteArguments,
failed = harness_instance.run()
if failed > 0:
sys.exit(10)
except Exception:
logger.error('Failure during harness execution', exc_info=True)
except Exception as e:
logger.error(e.message, exc_info=True)
sys.exit(1)
sys.exit(0)

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

@ -44,6 +44,18 @@ config = {
"win64",
],
},
"complete-mar-bz2": {
"product-name": "Firefox-%(version)s-Complete-bz2",
"check_uptake": True,
"platforms": [
"linux",
"linux64",
"osx",
"win",
"win64",
"win64-aarch64",
],
},
},
"partials": {
"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)]);
}, '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
//
@ -270,6 +288,16 @@ async_test(function(t) {
}, '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');
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
//
@ -659,6 +687,43 @@ async_test(function(t) {
}, 10);
}, '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
//

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

@ -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'
+ ' 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 => {
const div = createDiv(t);
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>
'use strict';
// Test that each property defined in the Animation interface does not produce
// style change events.
// Test that each property defined in the Animation interface behaves as
// expected with regards to whether or not it produces style change events.
//
// There are two types of tests:
//
@ -29,8 +29,9 @@
// (b) An object with the following format:
//
// {
// setup: elem => { /* return Animation */ }
// test: animation => { /* play |animation| */ }
// setup: elem => { /* return Animation */ },
// test: animation => { /* play |animation| */ },
// shouldFlush: boolean /* optional, defaults to false */
// }
//
// 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.
const PlayAnimationTest = testFuncOrObj => {
let test, setup;
let test, setup, shouldFlush;
if (typeof testFuncOrObj === 'function') {
test = testFuncOrObj;
shouldFlush = false;
} else {
test = testFuncOrObj.test;
if (typeof testFuncOrObj.setup === 'function') {
setup = testFuncOrObj.setup;
}
shouldFlush = !!testFuncOrObj.shouldFlush;
}
if (!setup) {
@ -74,11 +77,11 @@ const PlayAnimationTest = testFuncOrObj => {
);
}
return { test, setup };
return { test, setup, shouldFlush };
};
const UsePropertyTest = testFuncOrObj => {
const { setup, test } = PlayAnimationTest(testFuncOrObj);
const { setup, test, shouldFlush } = PlayAnimationTest(testFuncOrObj);
let coveringAnimation;
return {
@ -93,6 +96,7 @@ const UsePropertyTest = testFuncOrObj => {
test(animation);
coveringAnimation.play();
},
shouldFlush,
};
};
@ -160,6 +164,7 @@ const tests = {
}),
playState: UsePropertyTest(animation => animation.playState),
pending: UsePropertyTest(animation => animation.pending),
replaceState: UsePropertyTest(animation => animation.replaceState),
ready: UsePropertyTest(animation => animation.ready),
finished: UsePropertyTest(animation => {
// Get the finished Promise
@ -172,6 +177,13 @@ const tests = {
// Set the onfinish menber
animation.onfinish = () => {};
}),
onremove: UsePropertyTest(animation => {
// Get the onremove member
animation.onremove;
// Set the onremove menber
animation.onremove = () => {};
}),
oncancel: UsePropertyTest(animation => {
// Get the oncancel member
animation.oncancel;
@ -225,6 +237,51 @@ const tests = {
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']() {
let originalElem;
return UsePropertyTest({
@ -266,7 +323,7 @@ test(() => {
for (const key of properties) {
promise_test(async t => {
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
const div = createDiv(t);
@ -276,7 +333,7 @@ for (const key of properties) {
});
// Setup animation
const animation = setup(div);
const animation = await setup(div);
// Setup transition start point
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
// a transition.
// Wait for the animation to start and then for at least one animation
// frame to give the transitionrun event a chance to be dispatched.
// Wait for the animation to start and then for at least two animation
// frames to give the transitionrun event a chance to be dispatched.
assert_true(
typeof animation.ready !== 'undefined',
'Should have a valid animation to wait on'
);
await animation.ready;
await waitForAnimationFrames(1);
await waitForAnimationFrames(2);
assert_false(gotTransition, 'A transition should NOT have been triggered');
}, `Animation.${key} does NOT trigger a style change event`);
if (shouldFlush) {
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>
</body>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -223,4 +223,35 @@ promise_test(async t => {
}, 'Playback events with the same timeline retain the order in which they are' +
'queued');
promise_test(async t => {
const div = createDiv(t);
// Create two animations with separate timelines
const timelineA = document.timeline;
const animA = div.animate(null, 100 * MS_PER_SEC);
const timelineB = new DocumentTimeline();
const animB = new Animation(
new KeyframeEffect(div, null, 100 * MS_PER_SEC),
timelineB
);
animB.play();
animA.currentTime = 99.9 * MS_PER_SEC;
animB.currentTime = 99.9 * MS_PER_SEC;
// When the next tick happens both animations should be updated, and we will
// notice that they are now finished. As a result their finished promise
// callbacks should be queued. All of that should happen before we run the
// next microtask checkpoint and actually run the promise callbacks and
// hence the calls to cancel should not stop the existing callbacks from
// being run.
animA.finished.then(() => { animB.cancel() });
animB.finished.then(() => { animA.cancel() });
await Promise.all([animA.finished, animB.finished]);
}, 'All timelines are updated before running microtasks');
</script>

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

@ -36,12 +36,7 @@ class WebNavigationChild extends ActorChild {
this.gotoIndex(message.data);
break;
case "WebNavigation:LoadURI":
let histogram = Services.telemetry.getKeyedHistogramById("FX_TAB_REMOTE_NAVIGATION_DELAY_MS");
histogram.add("WebNavigation:LoadURI",
Services.telemetry.msSystemNow() - message.data.requestTime);
this.loadURI(message.data);
break;
case "WebNavigation:SetOriginAttributes":
this.setOriginAttributes(message.data.originAttributes);

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

@ -64,6 +64,9 @@ var EnableDelayHelper = function({enableDialog, disableDialog, focusTarget}) {
this.focusTarget.addEventListener("blur", this);
this.focusTarget.addEventListener("focus", this);
// While the user key-repeats, we want to renew the timer until keyup:
this.focusTarget.addEventListener("keyup", this, true);
this.focusTarget.addEventListener("keydown", this, true);
this.focusTarget.document.addEventListener("unload", this);
this.startOnFocusDelay();
@ -75,11 +78,29 @@ this.EnableDelayHelper.prototype = {
},
handleEvent(event) {
if (event.target != this.focusTarget &&
if (!event.type.startsWith("key") &&
event.target != this.focusTarget &&
event.target != this.focusTarget.document)
return;
switch (event.type) {
case "keyup":
// As soon as any key goes up, we can stop treating keypresses
// as indicative of key-repeating that should prolong the timer.
this.focusTarget.removeEventListener("keyup", this, true);
this.focusTarget.removeEventListener("keydown", this, true);
break;
case "keydown":
// Renew timer for repeating keydowns:
if (this._focusTimer) {
this._focusTimer.cancel();
this._focusTimer = null;
this.startOnFocusDelay();
event.preventDefault();
}
break;
case "blur":
this.onBlur();
break;
@ -111,6 +132,8 @@ this.EnableDelayHelper.prototype = {
onUnload() {
this.focusTarget.removeEventListener("blur", this);
this.focusTarget.removeEventListener("focus", this);
this.focusTarget.removeEventListener("keyup", this, true);
this.focusTarget.removeEventListener("keydown", this, true);
this.focusTarget.document.removeEventListener("unload", this);
if (this._focusTimer) {

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

@ -116,7 +116,6 @@ RemoteWebNavigation.prototype = {
triggeringPrincipal: E10SUtils.serializePrincipal(
aLoadURIOptions.triggeringPrincipal || Services.scriptSecurityManager.createNullPrincipal({})),
csp: aLoadURIOptions.csp ? E10SUtils.serializeCSP(aLoadURIOptions.csp) : null,
requestTime: Services.telemetry.msSystemNow(),
cancelContentJSEpoch,
});
},

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

@ -6282,17 +6282,6 @@
"n_buckets": 20,
"description": "Firefox: Time in ms spent on switching tabs in response to a tab click"
},
"FX_TAB_REMOTE_NAVIGATION_DELAY_MS": {
"record_in_processes": ["content"],
"alert_emails": ["mconley@mozilla.com"],
"bug_numbers": [1352961, 1501295],
"expires_in_version": "69",
"kind": "exponential",
"high": 4000,
"n_buckets": 100,
"keyed": true,
"description": "Time taken (in ms) from the point of the parent sending the naviagion triggering message to the content and the content receiving it. This message can be either SessionStore:restoreTabContent or WebNavigation:LoadURI and these names are used as keys for this histogram. This is e10s only and recorded in the content process."
},
"FX_BOOKMARKS_TOOLBAR_INIT_MS": {
"record_in_processes": ["main", "content"],
"expires_in_version": "never",

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

@ -449,22 +449,6 @@ identity.fxaccounts:
- main
security:
pkcs11_modules_loaded:
bug_numbers:
- 1369911
- 1445961
description: >
A keyed boolean indicating the library names of the PKCS#11 modules that
have been loaded by the browser.
expires: "69"
kind: boolean
keyed: true
notification_emails:
- seceng-telemetry@mozilla.com
- dkeeler@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
webauthn_used:
bug_numbers:
- 1265472
@ -1449,6 +1433,21 @@ devtools.inspector:
record_in_processes:
- 'main'
node_selection_count:
bug_numbers:
- 1550794
description: >
Number of times a different node is marked as selected in the Inspector regardless
of the cause: context menu, manual selection in markup view, etc.
expires: "never"
kind: uint
notification_emails:
- dev-developer-tools@lists.mozilla.org
- mbalfanz@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- 'main'
devtools.shadowdom:
shadow_root_displayed:
bug_numbers:

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