Bug 1504065 - Run background-color animations on the compositor. r=birtles

Changes for nsIDOMWindowUtils.getOMTAValue is in the next commit with come test
cases.

Differential Revision: https://phabricator.services.mozilla.com/D13001

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Hiroyuki Ikezoe 2018-11-27 09:26:51 +00:00
parent ebe85db8e7
commit 212fa4884a
16 changed files with 220 additions and 17 deletions

View File

@ -1894,6 +1894,23 @@ KeyframeEffect::IsMatchForCompositor(
return KeyframeEffect::MatchForCompositor::NoAndBlockThisProperty;
}
if (aProperty == eCSSProperty_background_color) {
if (!StaticPrefs::gfx_omta_background_color()) {
return KeyframeEffect::MatchForCompositor::No;
}
if (nsIContent* content = aFrame->GetContent()) {
RefPtr<layers::LayerManager> layerManager =
nsContentUtils::LayerManagerForContent(content);
if (layerManager &&
layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
// Bug 1510030: We don't yet support background-color animations on the
// compositor for WebRender.
return KeyframeEffect::MatchForCompositor::No;
}
}
}
return mAnimation->IsPlaying()
? KeyframeEffect::MatchForCompositor::Yes
: KeyframeEffect::MatchForCompositor::IfNeeded;

View File

@ -50,7 +50,9 @@ div {
/** Test for bug 1045994 - Add a chrome-only property to inspect if an
animation is running on the compositor or not **/
var omtaEnabled = isOMTAEnabled();
const omtaEnabled = isOMTAEnabled();
const isWebRender =
SpecialPowers.DOMWindowUtils.layerManagerType == 'WebRender';
function assert_animation_is_running_on_compositor(animation, desc) {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
@ -988,5 +990,41 @@ promise_test(async t => {
'Transform animation on table element should be running on the compositor');
}, 'Transform animation on table element runs on the compositor');
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ backgroundColor: ['blue', 'green'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
if (!isWebRender) {
assert_animation_is_running_on_compositor(animation,
'background-color animation should be running on the compositor');
} else {
assert_animation_is_not_running_on_compositor(animation,
'background-color animation is not yet able to run on the compositor ' +
'on WebRender');
}
}, 'backgound-color animation runs on the compositor');
promise_test(async t => {
await SpecialPowers.pushPrefEnv({
set: [["gfx.omta.background-color", false]]
});
const div = addDiv(t);
const animation = div.animate({ backgroundColor: ['blue', 'green'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_not_running_on_compositor(animation,
'background-color animation should NOT be running on the compositor ' +
'if the pref is disabled');
}, 'backgound-color animation does not run on the compositor if the pref ' +
'is disabled');
</script>
</body>

View File

@ -5,6 +5,7 @@ prefs =
dom.animations-api.getAnimations.enabled=true
dom.animations-api.implicit-keyframes.enabled=true
dom.animations-api.timelines.enabled=true
gfx.omta.background-color=true
layout.css.motion-path.enabled=true
layout.css.individual-transform.enabled=true
# Support files for chrome tests that we want to load over HTTP need

View File

@ -519,7 +519,7 @@ CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
}
static already_AddRefed<RawServoAnimationValue>
ToAnimationValue(const Animatable& aAnimatable)
ToAnimationValue(nsCSSPropertyID aProperty, const Animatable& aAnimatable)
{
RefPtr<RawServoAnimationValue> result;
@ -540,6 +540,10 @@ ToAnimationValue(const Animatable& aAnimatable)
case Animatable::Tfloat:
result = Servo_AnimationValue_Opacity(aAnimatable.get_float()).Consume();
break;
case Animatable::Tnscolor:
result = Servo_AnimationValue_Color(aProperty,
aAnimatable.get_nscolor()).Consume();
break;
default:
MOZ_ASSERT_UNREACHABLE("Unsupported type");
}
@ -580,7 +584,8 @@ AnimationHelper::SetAnimations(
}
if (animation.baseStyle().type() != Animatable::Tnull_t) {
aBaseAnimationStyle = ToAnimationValue(animation.baseStyle());
aBaseAnimationStyle = ToAnimationValue(animation.property(),
animation.baseStyle());
}
AnimData* data = aAnimData.AppendElement();
@ -605,8 +610,10 @@ AnimationHelper::SetAnimations(
const InfallibleTArray<AnimationSegment>& segments = animation.segments();
for (const AnimationSegment& segment : segments) {
startValues.AppendElement(ToAnimationValue(segment.startState()));
endValues.AppendElement(ToAnimationValue(segment.endState()));
startValues.AppendElement(ToAnimationValue(animation.property(),
segment.startState()));
endValues.AppendElement(ToAnimationValue(animation.property(),
segment.endState()));
TimingFunction tf = segment.sampleFn();
Maybe<ComputedTimingFunction> ctf =

View File

@ -633,6 +633,19 @@ ApplyAnimatedValue(Layer* aLayer,
HostLayer* layerCompositor = aLayer->AsHostLayer();
switch (aProperty) {
case eCSSProperty_background_color: {
// We don't support 'color' animations on the compositor yet so we never
// meet currentColor on the compositor.
nscolor color = Servo_AnimationValue_GetColor(aValue, NS_RGBA(0, 0, 0, 0));
aLayer->AsColorLayer()->SetColor(gfx::Color::FromABGR(color));
aStorage->SetAnimatedValue(aLayer->GetCompositorAnimationsId(), color);
layerCompositor->SetShadowOpacity(aLayer->GetOpacity());
layerCompositor->SetShadowOpacitySetByAnimation(false);
layerCompositor->SetShadowBaseTransform(aLayer->GetBaseTransform());
layerCompositor->SetShadowTransformSetByAnimation(false);
break;
}
case eCSSProperty_opacity: {
float opacity = Servo_AnimationValue_GetOpacity(aValue);
layerCompositor->SetShadowOpacity(opacity);
@ -709,19 +722,22 @@ SampleAnimations(Layer* aLayer,
}
case AnimationHelper::SampleResult::Skipped:
switch (animations[0].property()) {
case eCSSProperty_background_color:
case eCSSProperty_opacity: {
MOZ_ASSERT(
layer->AsHostLayer()->GetShadowOpacitySetByAnimation());
if (animations[0].property() == eCSSProperty_opacity) {
MOZ_ASSERT(
layer->AsHostLayer()->GetShadowOpacitySetByAnimation());
#ifdef DEBUG
// Disable this assertion until the root cause is fixed in bug
// 1459775.
// MOZ_ASSERT(FuzzyEqualsMultiplicative(
// Servo_AnimationValue_GetOpacity(animationValue),
// *(aStorage->GetAnimationOpacity(layer->GetCompositorAnimationsId()))));
// Disable this assertion until the root cause is fixed in bug
// 1459775.
// MOZ_ASSERT(FuzzyEqualsMultiplicative(
// Servo_AnimationValue_GetOpacity(animationValue),
// *(aStorage->GetAnimationOpacity(layer->GetCompositorAnimationsId()))));
#endif
// Even if opacity animation value has unchanged, we have to set
// the shadow base transform value here since the value might
// have been changed by APZC.
}
// Even if opacity or background-color animation value has
// unchanged, we have to set the shadow base transform value
// here since the value might have been changed by APZC.
HostLayer* layerCompositor = layer->AsHostLayer();
layerCompositor->SetShadowBaseTransform(
layer->GetBaseTransform());

View File

@ -19,6 +19,7 @@ using struct mozilla::gfx::Color from "mozilla/gfx/2D.h";
using struct mozilla::gfx::Point3D from "mozilla/gfx/Point.h";
using mozilla::gfx::IntPoint from "mozilla/gfx/Point.h";
using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
using nscolor from "nsColor.h";
using nscoord from "nsCoord.h";
using struct nsRect from "nsRect.h";
using struct nsPoint from "nsPoint.h";
@ -160,6 +161,7 @@ union MaybeTimeDuration {
union Animatable {
null_t;
float;
nscolor;
TransformFunction[];
};

View File

@ -438,6 +438,23 @@ SetAnimatable(nsCSSPropertyID aProperty,
}
switch (aProperty) {
case eCSSProperty_background_color: {
// We don't support color animation on the compositor yet so that we can
// resolve currentColor at this moment.
nscolor foreground;
if (aFrame->Style()->RelevantLinkVisited()) {
if (ComputedStyle* styleIfVisited =
aFrame->Style()->GetStyleIfVisited()) {
foreground = styleIfVisited->StyleColor()->mColor;
} else {
foreground = aFrame->Style()->StyleColor()->mColor;
}
} else {
foreground = aFrame->Style()->StyleColor()->mColor;
}
aAnimatable = aAnimationValue.GetColor(foreground);
break;
}
case eCSSProperty_opacity:
aAnimatable = aAnimationValue.GetOpacity();
break;
@ -673,7 +690,7 @@ AddAnimationsForProperty(nsIFrame* aFrame,
scaleX,
scaleY,
hasPerspectiveParent);
} else if (aProperty == eCSSProperty_opacity) {
} else {
data = null_t();
}
@ -3529,6 +3546,7 @@ nsDisplaySolidColor::GetLayerState(nsDisplayListBuilder* aBuilder,
if (ForceActiveLayers()) {
return LAYER_ACTIVE;
}
return LAYER_NONE;
}
@ -5022,6 +5040,12 @@ nsDisplayBackgroundColor::GetLayerState(
if (ForceActiveLayers() && clip != StyleGeometryBox::Text) {
return LAYER_ACTIVE;
}
if (EffectCompositor::HasAnimationsForCompositor(
mFrame, eCSSProperty_background_color)) {
return LAYER_ACTIVE_FORCE;
}
return LAYER_NONE;
}
@ -5049,6 +5073,11 @@ nsDisplayBackgroundColor::BuildLayer(
layer->SetBaseTransform(gfx::Matrix4x4::Translation(
aContainerParameters.mOffset.x, aContainerParameters.mOffset.y, 0));
nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(
layer, aBuilder,
this, mFrame,
eCSSProperty_background_color);
return layer.forget();
}
@ -8571,6 +8600,14 @@ nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
return mAllowAsyncAnimation;
}
bool
nsDisplayBackgroundColor::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
{
LayerManager* layerManager = aBuilder->GetWidgetLayerManager();
return layerManager &&
layerManager->GetBackendType() != layers::LayersBackend::LAYERS_WR;
}
/* static */ auto
nsDisplayTransform::ShouldPrerenderTransformedContent(
nsDisplayListBuilder* aBuilder,

View File

@ -5074,6 +5074,8 @@ public:
void WriteDebugInfo(std::stringstream& aStream) override;
bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
protected:
const nsRect mBackgroundRect;
RefPtr<mozilla::ComputedStyle> mBackgroundStyle;

View File

@ -14,6 +14,7 @@ namespace mozilla {
/* static */ const Array<DisplayItemType,
nsCSSPropertyIDSet::CompositorAnimatableCount()>
LayerAnimationInfo::sDisplayItemTypes = {
DisplayItemType::TYPE_BACKGROUND_COLOR,
DisplayItemType::TYPE_OPACITY,
DisplayItemType::TYPE_TRANSFORM,
};
@ -22,6 +23,8 @@ namespace mozilla {
LayerAnimationInfo::GetDisplayItemTypeForProperty(nsCSSPropertyID aProperty)
{
switch (aProperty) {
case eCSSProperty_background_color:
return DisplayItemType::TYPE_BACKGROUND_COLOR;
case eCSSProperty_opacity:
return DisplayItemType::TYPE_OPACITY;
case eCSSProperty_transform:

View File

@ -34,9 +34,13 @@ struct LayerAnimationInfo {
nsCSSPropertyIDSet{ eCSSProperty_transform };
static const nsCSSPropertyIDSet opacityProperties =
nsCSSPropertyIDSet{ eCSSProperty_opacity };
static const nsCSSPropertyIDSet backgroundColorProperties =
nsCSSPropertyIDSet{ eCSSProperty_background_color };
static const nsCSSPropertyIDSet empty = nsCSSPropertyIDSet();
switch (aDisplayItemType) {
case DisplayItemType::TYPE_BACKGROUND_COLOR:
return backgroundColorProperties;
case DisplayItemType::TYPE_OPACITY:
return opacityProperties;
case DisplayItemType::TYPE_TRANSFORM:
@ -58,6 +62,8 @@ struct LayerAnimationInfo {
GetChangeHintFor(DisplayItemType aDisplayItemType)
{
switch (aDisplayItemType) {
case DisplayItemType::TYPE_BACKGROUND_COLOR:
return nsChangeHint_RepaintFrame;
case DisplayItemType::TYPE_OPACITY:
return nsChangeHint_UpdateOpacityLayer;
case DisplayItemType::TYPE_TRANSFORM:

View File

@ -676,6 +676,11 @@ void Servo_AnimationValue_Serialize(
nsCSSPropertyID property,
nsAString* buffer);
nscolor Servo_AnimationValue_GetColor(RawServoAnimationValueBorrowed value,
nscolor foregroundColor);
RawServoAnimationValueStrong Servo_AnimationValue_Color(nsCSSPropertyID,
nscolor);
float Servo_AnimationValue_GetOpacity(RawServoAnimationValueBorrowed value);
RawServoAnimationValueStrong Servo_AnimationValue_Opacity(float);

View File

@ -120,6 +120,13 @@ AnimationValue::GetOpacity() const
return Servo_AnimationValue_GetOpacity(mServo);
}
nscolor
AnimationValue::GetColor(nscolor aForegroundColor) const
{
MOZ_ASSERT(mServo);
return Servo_AnimationValue_GetColor(mServo, aForegroundColor);
}
already_AddRefed<const nsCSSValueSharedList>
AnimationValue::GetTransformList() const
{

View File

@ -78,6 +78,10 @@ struct AnimationValue
float GetOpacity() const;
// Returns nscolor value in this AnimationValue.
// Currently only background-color is supported.
nscolor GetColor(nscolor aForegroundColor) const;
// Return the transform list as a RefPtr.
already_AddRefed<const nsCSSValueSharedList> GetTransformList() const;

View File

@ -494,6 +494,18 @@ VARCACHE_PREF(
RelaxedAtomicBool, false
)
#ifdef RELEASE_OR_BETA
# define PREF_VALUE false
#else
# define PREF_VALUE true
#endif
VARCACHE_PREF(
"gfx.omta.background-color",
gfx_omta_background_color,
bool, PREF_VALUE
)
#undef PREF_VALUE
//---------------------------------------------------------------------------
// HTML5 parser prefs
//---------------------------------------------------------------------------

View File

@ -15,7 +15,8 @@ ${helpers.predefined_type(
animation_value_type="AnimatedColor",
ignored_when_colors_disabled=True,
allow_quirks=True,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER \
CAN_ANIMATE_ON_COMPOSITOR",
)}
${helpers.predefined_type(

View File

@ -797,6 +797,27 @@ pub extern "C" fn Servo_AnimationValue_Serialize(
debug_assert!(rv.is_ok());
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_GetColor(
value: RawServoAnimationValueBorrowed,
foreground_color: structs::nscolor,
) -> structs::nscolor {
use style::gecko::values::convert_nscolor_to_rgba;
use style::gecko::values::convert_rgba_to_nscolor;
use style::values::animated::ToAnimatedValue;
use style::values::computed::color::Color as ComputedColor;
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::BackgroundColor(color) => {
let computed: ComputedColor = ToAnimatedValue::from_animated_value(color);
let foreground_color = convert_nscolor_to_rgba(foreground_color);
convert_rgba_to_nscolor(&computed.to_rgba(foreground_color))
}
_ => panic!("Other color properties are not supported yet"),
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_GetOpacity(value: RawServoAnimationValueBorrowed) -> f32 {
let value = AnimationValue::as_arc(&value);
@ -812,6 +833,30 @@ pub extern "C" fn Servo_AnimationValue_Opacity(opacity: f32) -> RawServoAnimatio
Arc::new(AnimationValue::Opacity(opacity)).into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_Color(
color_property: nsCSSPropertyID,
color: structs::nscolor
) -> RawServoAnimationValueStrong {
use style::gecko::values::convert_nscolor_to_rgba;
use style::values::animated::color::RGBA as AnimatedRGBA;
let property = LonghandId::from_nscsspropertyid(color_property)
.expect("We don't have shorthand property animation value");
let rgba = convert_nscolor_to_rgba(color);
let animatedRGBA = AnimatedRGBA::new(rgba.red_f32(),
rgba.green_f32(),
rgba.blue_f32(),
rgba.alpha_f32());
match property {
LonghandId::BackgroundColor =>
Arc::new(AnimationValue::BackgroundColor(animatedRGBA.into())).into_strong(),
_ => panic!("Should be background-color property"),
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_GetTransform(
value: RawServoAnimationValueBorrowed,