mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1526847 - Let ComputeSuitableScaleForAnimation check other transform-like properties. r=hiro
Check all transform-like properties which may affect the scaling factors when computing the suitable scale for animations. Differential Revision: https://phabricator.services.mozilla.com/D19526 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
a57c781b04
commit
9782f68abf
@ -357,19 +357,47 @@ static float GetSuitableScale(float aMaxScale, float aMinScale,
|
||||
return std::max(std::min(aMaxScale, displayVisibleRatio), aMinScale);
|
||||
}
|
||||
|
||||
// The first value in this pair is the min scale, and the second one is the max
|
||||
// scale.
|
||||
using MinAndMaxScale = Pair<Size, Size>;
|
||||
|
||||
static inline void UpdateMinMaxScale(const nsIFrame* aFrame,
|
||||
const AnimationValue& aValue,
|
||||
Size& aMinScale, Size& aMaxScale) {
|
||||
MinAndMaxScale& aMinAndMaxScale) {
|
||||
Size size = aValue.GetScaleValue(aFrame);
|
||||
aMaxScale.width = std::max<float>(aMaxScale.width, size.width);
|
||||
aMaxScale.height = std::max<float>(aMaxScale.height, size.height);
|
||||
aMinScale.width = std::min<float>(aMinScale.width, size.width);
|
||||
aMinScale.height = std::min<float>(aMinScale.height, size.height);
|
||||
Size& minScale = aMinAndMaxScale.first();
|
||||
Size& maxScale = aMinAndMaxScale.second();
|
||||
|
||||
minScale = Min(minScale, size);
|
||||
maxScale = Max(maxScale, size);
|
||||
}
|
||||
|
||||
static void GetMinAndMaxScaleForAnimationProperty(
|
||||
const nsIFrame* aFrame, nsTArray<RefPtr<dom::Animation>>& aAnimations,
|
||||
Size& aMaxScale, Size& aMinScale) {
|
||||
// The final transform matrix is calculated by merging the final results of each
|
||||
// transform-like properties, so do the scale factors. In other words, the
|
||||
// potential min/max scales could be gotten by multiplying the max/min scales of
|
||||
// each properties.
|
||||
//
|
||||
// For example, there is an animation:
|
||||
// from { "transform: scale(1, 1)", "scale: 3, 3" };
|
||||
// to { "transform: scale(2, 2)", "scale: 1, 1" };
|
||||
//
|
||||
// the min scale is (1, 1) * (1, 1) = (1, 1), and
|
||||
// The max scale is (2, 2) * (3, 3) = (6, 6).
|
||||
// This means we multiply the min/max scale factor of transform property and the
|
||||
// min/max scale factor of scale property to get the final max/min scale factor.
|
||||
static Array<MinAndMaxScale, 2> GetMinAndMaxScaleForAnimationProperty(
|
||||
const nsIFrame* aFrame,
|
||||
const nsTArray<RefPtr<dom::Animation>>& aAnimations) {
|
||||
// We use a fixed array to store the min/max scales for each property.
|
||||
// The first element in the array is for eCSSProperty_transform, and the
|
||||
// second one is for eCSSProperty_scale.
|
||||
const MinAndMaxScale defaultValue =
|
||||
MakePair(Size(std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max()),
|
||||
Size(std::numeric_limits<float>::min(),
|
||||
std::numeric_limits<float>::min()));
|
||||
Array<MinAndMaxScale, 2> minAndMaxScales(defaultValue, defaultValue);
|
||||
|
||||
for (dom::Animation* anim : aAnimations) {
|
||||
// This method is only expected to be passed animations that are running on
|
||||
// the compositor and we only pass playing animations to the compositor,
|
||||
@ -377,54 +405,101 @@ static void GetMinAndMaxScaleForAnimationProperty(
|
||||
// not yet finished or which are filling forwards).
|
||||
MOZ_ASSERT(anim->IsRelevant());
|
||||
|
||||
dom::KeyframeEffect* effect =
|
||||
const dom::KeyframeEffect* effect =
|
||||
anim->GetEffect() ? anim->GetEffect()->AsKeyframeEffect() : nullptr;
|
||||
MOZ_ASSERT(effect, "A playing animation should have a keyframe effect");
|
||||
for (size_t propIdx = effect->Properties().Length(); propIdx-- != 0;) {
|
||||
const AnimationProperty& prop = effect->Properties()[propIdx];
|
||||
// FIXME: Bug 1526847: Make this accept rotate and scale.
|
||||
if (prop.mProperty != eCSSProperty_transform) {
|
||||
for (const AnimationProperty& prop : effect->Properties()) {
|
||||
if (prop.mProperty != eCSSProperty_transform &&
|
||||
prop.mProperty != eCSSProperty_scale) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 0: eCSSProperty_transform.
|
||||
// 1: eCSSProperty_scale.
|
||||
MinAndMaxScale& scales =
|
||||
minAndMaxScales[prop.mProperty == eCSSProperty_transform ? 0 : 1];
|
||||
|
||||
// We need to factor in the scale of the base style if the base style
|
||||
// will be used on the compositor.
|
||||
AnimationValue baseStyle = effect->BaseStyle(prop.mProperty);
|
||||
const AnimationValue& baseStyle = effect->BaseStyle(prop.mProperty);
|
||||
if (!baseStyle.IsNull()) {
|
||||
UpdateMinMaxScale(aFrame, baseStyle, aMinScale, aMaxScale);
|
||||
UpdateMinMaxScale(aFrame, baseStyle, scales);
|
||||
}
|
||||
|
||||
for (const AnimationPropertySegment& segment : prop.mSegments) {
|
||||
// In case of add or accumulate composite, StyleAnimationValue does
|
||||
// not have a valid value.
|
||||
if (segment.HasReplaceableFromValue()) {
|
||||
UpdateMinMaxScale(aFrame, segment.mFromValue, aMinScale, aMaxScale);
|
||||
UpdateMinMaxScale(aFrame, segment.mFromValue, scales);
|
||||
}
|
||||
|
||||
if (segment.HasReplaceableToValue()) {
|
||||
UpdateMinMaxScale(aFrame, segment.mToValue, aMinScale, aMaxScale);
|
||||
UpdateMinMaxScale(aFrame, segment.mToValue, scales);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minAndMaxScales;
|
||||
}
|
||||
|
||||
Size nsLayoutUtils::ComputeSuitableScaleForAnimation(
|
||||
const nsIFrame* aFrame, const nsSize& aVisibleSize,
|
||||
const nsSize& aDisplaySize) {
|
||||
const nsTArray<RefPtr<dom::Animation>> compositorAnimations =
|
||||
EffectCompositor::GetAnimationsForCompositor(
|
||||
aFrame,
|
||||
nsCSSPropertyIDSet{eCSSProperty_transform, eCSSProperty_scale});
|
||||
|
||||
if (compositorAnimations.IsEmpty()) {
|
||||
return Size(1.0, 1.0);
|
||||
}
|
||||
|
||||
const Array<MinAndMaxScale, 2> minAndMaxScales =
|
||||
GetMinAndMaxScaleForAnimationProperty(aFrame, compositorAnimations);
|
||||
|
||||
// This might cause an issue if users use std::numeric_limits<float>::min()
|
||||
// (or max()) as the scale value. However, in this case, we may render an
|
||||
// extreme small (or large) element, so this may not be a problem. If so,
|
||||
// please fix this.
|
||||
Size maxScale(std::numeric_limits<float>::min(),
|
||||
std::numeric_limits<float>::min());
|
||||
Size minScale(std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max());
|
||||
|
||||
// FIXME: Bug 1526847: Add rotate and scale into this set.
|
||||
nsTArray<RefPtr<dom::Animation>> compositorAnimations =
|
||||
EffectCompositor::GetAnimationsForCompositor(
|
||||
aFrame, nsCSSPropertyIDSet{eCSSProperty_transform});
|
||||
GetMinAndMaxScaleForAnimationProperty(aFrame, compositorAnimations, maxScale,
|
||||
minScale);
|
||||
auto isUnset = [](const Size& aMax, const Size& aMin) {
|
||||
return aMax.width == std::numeric_limits<float>::min() &&
|
||||
aMax.height == std::numeric_limits<float>::min() &&
|
||||
aMin.width == std::numeric_limits<float>::max() &&
|
||||
aMin.height == std::numeric_limits<float>::max();
|
||||
};
|
||||
|
||||
if (maxScale.width == std::numeric_limits<float>::min()) {
|
||||
// We didn't encounter a transform
|
||||
// Iterate the slots to get the final scale value.
|
||||
for (const auto& pair : minAndMaxScales) {
|
||||
const Size& currMinScale = pair.first();
|
||||
const Size& currMaxScale = pair.second();
|
||||
|
||||
if (isUnset(currMaxScale, currMinScale)) {
|
||||
// We don't have this animation property, so skip.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isUnset(maxScale, minScale)) {
|
||||
// Initialize maxScale and minScale.
|
||||
maxScale = currMaxScale;
|
||||
minScale = currMinScale;
|
||||
} else {
|
||||
// The scale factors of each transform-like property should be multiplied
|
||||
// by others because we merge their sampled values as a final matrix by
|
||||
// matrix multiplication, so here we multiply the scale factors by the
|
||||
// previous one to get the possible max and min scale factors.
|
||||
maxScale = maxScale * currMaxScale;
|
||||
minScale = minScale * currMinScale;
|
||||
}
|
||||
}
|
||||
|
||||
if (isUnset(maxScale, minScale)) {
|
||||
// We didn't encounter any transform-like property.
|
||||
return Size(1.0, 1.0);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE HTML>
|
||||
<title>Testcase, bug 1122526</title>
|
||||
<style>
|
||||
|
||||
#outer, #inner {
|
||||
display: inline-block;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
#inner {
|
||||
vertical-align: top;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
background: repeating-linear-gradient(to top left, yellow, blue 10px);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="outer">
|
||||
<div id="inner">
|
||||
</div>
|
||||
</div>
|
27
layout/reftests/transform/animate-layer-scale-inherit-4.html
Normal file
27
layout/reftests/transform/animate-layer-scale-inherit-4.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE HTML>
|
||||
<title>Testcase, bug 1526847</title>
|
||||
<style>
|
||||
|
||||
#outer, #inner {
|
||||
display: inline-block;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
#outer { scale: 5 }
|
||||
#inner {
|
||||
vertical-align: top;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
background: repeating-linear-gradient(to top left, yellow, blue 10px);
|
||||
animation: HoldTransform linear infinite 1s;
|
||||
}
|
||||
@keyframes HoldTransform {
|
||||
from, to { scale: 0.5; transform: scale(0.4); }
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="outer">
|
||||
<div id="inner">
|
||||
</div>
|
||||
</div>
|
@ -147,3 +147,5 @@ fuzzy-if(d2d,0-1,0-5) fuzzy-if(skiaContent,0-26,0-208) == table-overflowed-by-an
|
||||
fails == translate-rounding-3.html translate-rounding-viewport-ref.html # bug 1397146
|
||||
== invalidate-transform-1.html invalidate-transform-1-ref.html
|
||||
== invalidate-svg-scale-1.html invalidate-svg-scale-1-ref.html
|
||||
# Bug 1526847
|
||||
pref(layout.css.individual-transform.enabled,true) == animate-layer-scale-inherit-4.html animate-layer-scale-inherit-4-ref.html
|
||||
|
Loading…
Reference in New Issue
Block a user