/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include"CompositorAnimationStorage.h"
#include"AnimationHelper.h" #include"mozilla/gfx/MatrixFwd.h" #include"mozilla/layers/APZSampler.h"// for APZSampler #include"mozilla/layers/CompositorBridgeParent.h"// for CompositorBridgeParent #include"mozilla/layers/CompositorThread.h"// for CompositorThreadHolder #include"mozilla/layers/OMTAController.h"// for OMTAController #include"mozilla/ProfilerMarkers.h" #include"mozilla/ScopeExit.h" #include"mozilla/ServoStyleConsts.h" #include"mozilla/webrender/WebRenderTypes.h"// for ToWrTransformProperty, etc #include"nsDeviceContext.h"// for AppUnitsPerCSSPixel #include"nsDisplayList.h"// for nsDisplayTransform, etc #include"nsLayoutUtils.h" #include"TreeTraversal.h"// for ForEachNode, BreadthFirstSearch
already_AddRefed<StyleAnimationValue> AnimatedValue::AsAnimationValue(
nsCSSPropertyID aProperty) const {
RefPtr<StyleAnimationValue> result;
mValue.match(
[&](const AnimationTransform& aTransform) { // Linear search. It's likely that the length of the array is one in // most common case, so it shouldn't have much performance impact. for (constauto& value : Transform().mAnimationValues) {
AnimatedPropertyID property(eCSSProperty_UNKNOWN);
Servo_AnimationValue_GetPropertyId(value, &property); if (property.mID == aProperty) {
result = value; break;
}
}
},
[&](constfloat& aOpacity) {
result = Servo_AnimationValue_Opacity(aOpacity).Consume();
},
[&](const nscolor& aColor) {
result = Servo_AnimationValue_Color(aProperty, aColor).Consume();
}); return result.forget();
}
// If there is the last animated value, then we need to store the id to remove // the value if the new animation doesn't produce any animated data (i.e. in // the delay phase) when we sample this new animation. if (mAnimatedValues.Contains(aId)) {
mNewAnimations.insert(aId);
}
}
// Returns clip rect in the scroll frame's coordinate space. static ParentLayerRect GetClipRectForPartialPrerender( const LayersId aLayersId, const PartialPrerenderData& aPartialPrerenderData, const RefPtr<APZSampler>& aSampler, const MutexAutoLock& aProofOfMapLock) { if (aSampler &&
aPartialPrerenderData.scrollId() != ScrollableLayerGuid::NULL_SCROLL_ID) { return aSampler->GetCompositionBounds(
aLayersId, aPartialPrerenderData.scrollId(), aProofOfMapLock);
}
return aPartialPrerenderData.clipRect();
}
void CompositorAnimationStorage::StoreAnimatedValue(
nsCSSPropertyID aProperty, uint64_t aId, const std::unique_ptr<AnimationStorageData>& aAnimationStorageData,
SampledAnimationArray&& aAnimationValues, const MutexAutoLock& aProofOfMapLock, const RefPtr<APZSampler>& aApzSampler,
AnimatedValue* aAnimatedValueEntry,
JankedAnimationMap& aJankedAnimationMap) { switch (aProperty) { case eCSSProperty_background_color: {
SetAnimatedValue(aId, aAnimatedValueEntry,
Servo_AnimationValue_GetColor(aAnimationValues[0],
NS_RGBA(0, 0, 0, 0))); break;
} case eCSSProperty_opacity: {
MOZ_ASSERT(aAnimationValues.Length() == 1);
SetAnimatedValue(aId, aAnimatedValueEntry,
Servo_AnimationValue_GetOpacity(aAnimationValues[0])); break;
} case eCSSProperty_rotate: case eCSSProperty_scale: case eCSSProperty_translate: case eCSSProperty_transform: case eCSSProperty_offset_path: case eCSSProperty_offset_distance: case eCSSProperty_offset_rotate: case eCSSProperty_offset_anchor: case eCSSProperty_offset_position: {
MOZ_ASSERT(aAnimationStorageData->mTransformData);
if (!sampleResult.IsSampled()) { // Note: Checking new animations first. If new animations arrive and we // scroll back to delay phase in the meantime for scroll-driven // animations, removing the previous animated value is still the // preferable way because the newly animation case would probably more // often than the scroll timeline. Besides, we expect the display items // get sync with main thread at this moment, so dropping the old // animation sampled result is more suitable. // FIXME: Bug 1791884: We might have to revisit this to make sure we // respect animation composition order. if (mNewAnimations.find(iter.first) != mNewAnimations.end()) {
mAnimatedValues.Remove(iter.first);
} elseif (sampleResult.mReason ==
AnimationHelper::SampleResult::Reason::ScrollToDelayPhase) { // For the scroll-driven animations, its animation effect phases may // be changed between the active phase and the before/after phase. // Basically we don't produce any sampled animation value for // before/after phase (if we don't have fills). In this case, we have // to make sure the animations are not applied on the compositor. // Removing the previous animated value is not enough because the // display item in webrender may be out-of-date. Therefore, we should // not just skip these animation values. Instead, storing their base // styles (which are in |animationValues| already) to simulate these // delayed animations. // // There are two possible situations: // 1. If there is just a new animation arrived but there is no sampled // animation value when we go from active phase, we remove the // previous AnimatedValue. This is done in the above condition. // 2. If |animation| is not replaced by a new arrived one, we detect // it in SampleAnimationForProperty(), which sets // ScrollToDelayPhase if it goes from the active phase to the // before/after phase. // // For the 2nd case, we store the base styles until we have some other // new sampled results or the new animations arrived (i.e. case 1).
StoreAnimatedValue(lastPropertyAnimationGroupProperty, iter.first,
animationStorageData, std::move(animationValues),
aProofOfMapLock, apzSampler, previousValue,
janked);
} continue;
}
// Store the normal sampled result.
StoreAnimatedValue(lastPropertyAnimationGroupProperty, iter.first,
animationStorageData, std::move(animationValues),
aProofOfMapLock, apzSampler, previousValue, janked);
}
};
if (apzSampler) { // Hold APZCTreeManager::mMapLock for all the animations inside this // CompositorBridgeParent. This ensures that APZ cannot process a // transaction on the updater thread in between sampling different // animations.
apzSampler->CallWithMapLock(callback);
} else { // A fallback way if we don't have |apzSampler|. We don't care about // APZCTreeManager::mMapLock in this case because we don't use any APZ // interface.
mozilla::Mutex dummy("DummyAPZMapLock");
MutexAutoLock lock(dummy);
callback(lock);
}
if (!janked.empty() && aOMTAController) {
aOMTAController->NotifyJankedAnimations(std::move(janked));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.