Bug 1383650 - Notify style system when SMIL animation changes length r=birtles,longsonr

When animating geometry attribute, we need to notify style system about the change of SMIL override style.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
violet 2019-05-16 00:58:56 +00:00
Родитель e3fcbc33d6
Коммит a5f610a05c
8 изменённых файлов: 127 добавлений и 26 удалений

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

@ -6,6 +6,7 @@
#include "SMILCompositor.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "nsComputedDOMStyle.h"
#include "nsCSSProps.h"
#include "nsHashKeys.h"
@ -147,19 +148,21 @@ nsCSSPropertyID SMILCompositor::GetCSSPropertyToAnimate() const {
// If we are animating the 'width' or 'height' of an outer SVG
// element we should animate it as a CSS property, but for other elements
// (e.g. <rect>) we should animate it as a length attribute.
// The easiest way to test for an outer SVG element, is to see if it is an
// SVG-namespace element mapping its width/height attribute to style.
//
// If we have animation of 'width' or 'height' on an SVG element that is
// NOT mapping that attributes to style then it must not be an outermost SVG
// element so we should return eCSSProperty_UNKNOWN to indicate that we
// should animate as an attribute instead.
// in SVG namespace (e.g. <rect>) we should animate it as a length attribute.
if ((mKey.mAttributeName == nsGkAtoms::width ||
mKey.mAttributeName == nsGkAtoms::height) &&
mKey.mElement->GetNameSpaceID() == kNameSpaceID_SVG &&
!mKey.mElement->IsAttributeMapped(mKey.mAttributeName)) {
return eCSSProperty_UNKNOWN;
mKey.mElement->GetNameSpaceID() == kNameSpaceID_SVG) {
// Not an <svg> element.
if (!mKey.mElement->IsSVGElement(nsGkAtoms::svg)) {
return eCSSProperty_UNKNOWN;
}
// An inner <svg> element
if (static_cast<dom::SVGSVGElement const&>(*mKey.mElement).IsInner()) {
return eCSSProperty_UNKNOWN;
}
// Indeed an outer <svg> element, fall through.
}
return propID;

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

@ -30,6 +30,7 @@
#include "nsAttrValueOrString.h"
#include "nsCSSProps.h"
#include "nsContentUtils.h"
#include "nsDOMCSSAttrDeclaration.h"
#include "nsICSSDeclaration.h"
#include "nsIContentInlines.h"
#include "mozilla/dom/Document.h"
@ -53,6 +54,7 @@
#include "SVGAnimatedOrient.h"
#include "SVGAnimatedString.h"
#include "SVGAnimatedViewBox.h"
#include "SVGGeometryProperty.h"
#include "SVGMotionSMILAttr.h"
#include <stdarg.h>
@ -1020,6 +1022,41 @@ already_AddRefed<DOMSVGAnimatedString> SVGElement::ClassName() {
return mClassAttribute.ToDOMAnimatedString(this);
}
/* static */
bool SVGElement::UpdateDeclarationBlockFromLength(
DeclarationBlock& aBlock, nsCSSPropertyID aPropId,
const SVGAnimatedLength& aLength, ValToUse aValToUse) {
aBlock.AssertMutable();
float value;
if (aValToUse == ValToUse::Anim) {
value = aLength.GetAnimValInSpecifiedUnits();
} else {
MOZ_ASSERT(aValToUse == ValToUse::Base);
value = aLength.GetBaseValInSpecifiedUnits();
}
// SVG parser doesn't check non-negativity of some parsed value,
// we should not pass those to CSS side.
if (value < 0 &&
SVGGeometryProperty::IsNonNegativeGeometryProperty(aPropId)) {
return false;
}
nsCSSUnit cssUnit = SVGGeometryProperty::SpecifiedUnitTypeToCSSUnit(
aLength.GetSpecifiedUnitType());
if (cssUnit == eCSSUnit_Percent) {
Servo_DeclarationBlock_SetPercentValue(aBlock.Raw(), aPropId,
value / 100.f);
} else {
Servo_DeclarationBlock_SetLengthValue(aBlock.Raw(), aPropId, value,
cssUnit);
}
return true;
}
//------------------------------------------------------------------------
// Helper class: MappedAttrParser, for parsing values of mapped attributes
@ -1391,6 +1428,15 @@ void SVGElement::DidChangeLength(uint8_t aAttrEnum,
}
void SVGElement::DidAnimateLength(uint8_t aAttrEnum) {
if (SVGGeometryProperty::ElementMapsLengthsToStyle(this)) {
nsCSSPropertyID propId =
SVGGeometryProperty::AttrEnumToCSSPropId(this, aAttrEnum);
SMILOverrideStyle()->SetSMILValue(propId,
GetLengthInfo().mLengths[aAttrEnum]);
return;
}
ClearAnyCachedPath();
nsIFrame* frame = GetPrimaryFrame();

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

@ -165,6 +165,12 @@ class SVGElement : public SVGElementBase // nsIContent
virtual bool HasValidDimensions() const { return true; }
void SetLength(nsAtom* aName, const SVGAnimatedLength& aLength);
enum class ValToUse { Base, Anim };
static bool UpdateDeclarationBlockFromLength(DeclarationBlock& aBlock,
nsCSSPropertyID aPropId,
const SVGAnimatedLength& aLength,
ValToUse aValToUse);
nsAttrValue WillChangeLength(uint8_t aAttrEnum);
nsAttrValue WillChangeNumberPair(uint8_t aAttrEnum);
nsAttrValue WillChangeIntegerPair(uint8_t aAttrEnum);

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

@ -69,6 +69,19 @@ nsCSSPropertyID AttrEnumToCSSPropId(const SVGElement* aElement,
return eCSSProperty_UNKNOWN;
}
bool IsNonNegativeGeometryProperty(nsCSSPropertyID aProp) {
return aProp == eCSSProperty_r || aProp == eCSSProperty_rx ||
aProp == eCSSProperty_ry || aProp == eCSSProperty_width ||
aProp == eCSSProperty_height;
}
bool ElementMapsLengthsToStyle(SVGElement const* aElement) {
return aElement->IsSVGElement(nsGkAtoms::rect) ||
aElement->IsSVGElement(nsGkAtoms::circle) ||
aElement->IsSVGElement(nsGkAtoms::ellipse) ||
aElement->IsSVGElement(nsGkAtoms::foreignObject);
}
} // namespace SVGGeometryProperty
} // namespace dom
} // namespace mozilla

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

@ -152,6 +152,9 @@ nsCSSUnit SpecifiedUnitTypeToCSSUnit(uint8_t aSpecifiedUnit);
nsCSSPropertyID AttrEnumToCSSPropId(const SVGElement* aElement,
uint8_t aAttrEnum);
bool IsNonNegativeGeometryProperty(nsCSSPropertyID aProp);
bool ElementMapsLengthsToStyle(SVGElement const* aElement);
} // namespace SVGGeometryProperty
} // namespace dom
} // namespace mozilla

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

@ -124,6 +124,17 @@ class SVGViewportElement : public SVGGraphicsElement {
mViewportHeight = aSize.height;
}
/**
* Returns true if either this is an SVG <svg> element that is the child of
* another non-foreignObject SVG element, or this is a SVG <symbol> element
* this is the root of a use-element shadow tree.
*/
bool IsInner() const {
const nsIContent* parent = GetFlattenedTreeParent();
return parent && parent->IsSVGElement() &&
!parent->IsSVGElement(nsGkAtoms::foreignObject);
}
// WebIDL
already_AddRefed<SVGAnimatedRect> ViewBox();
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
@ -139,17 +150,6 @@ class SVGViewportElement : public SVGGraphicsElement {
return IsInUncomposedDoc() && !GetParent();
}
/**
* Returns true if either this is an SVG <svg> element that is the child of
* another non-foreignObject SVG element, or this is a SVG <symbol> element
* this is the root of a use-element shadow tree.
*/
bool IsInner() const {
const nsIContent* parent = GetFlattenedTreeParent();
return parent && parent->IsSVGElement() &&
!parent->IsSVGElement(nsGkAtoms::foreignObject);
}
/**
* Returns the explicit or default preserveAspectRatio, unless we're
* synthesizing a viewBox, in which case it returns the "none" value.

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

@ -10,10 +10,12 @@
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/SVGElement.h"
#include "mozilla/dom/MutationEventBinding.h"
#include "mozilla/DeclarationBlock.h"
#include "mozilla/InternalMutationEvent.h"
#include "mozilla/SMILCSSValueType.h"
#include "mozilla/SMILValue.h"
#include "mozAutoDocUpdate.h"
#include "nsIURI.h"
#include "nsNodeUtils.h"
@ -133,9 +135,10 @@ nsDOMCSSAttributeDeclaration::GetParsingEnvironment(
};
}
nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
const nsCSSPropertyID aPropID, const SMILValue& aValue) {
template <typename SetterFunc>
nsresult nsDOMCSSAttributeDeclaration::SetSMILValueHelper(SetterFunc aFunc) {
MOZ_ASSERT(mIsSMILOverride);
// No need to do the ActiveLayerTracker / ScrollLinkedEffectDetector bits,
// since we're in a SMIL animation anyway, no need to try to detect we're a
// scripted animation.
@ -147,7 +150,9 @@ nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
}
mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
bool changed = SMILCSSValueType::SetPropertyValues(aValue, *decl);
bool changed = aFunc(*decl);
if (changed) {
// We can pass nullptr as the latter param, since this is
// mIsSMILOverride == true case.
@ -156,6 +161,23 @@ nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
return NS_OK;
}
nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
const nsCSSPropertyID /*aPropID*/, const SMILValue& aValue) {
MOZ_ASSERT(aValue.mType == &SMILCSSValueType::sSingleton,
"We should only try setting a CSS value type");
return SetSMILValueHelper([&aValue](DeclarationBlock& aDecl) {
return SMILCSSValueType::SetPropertyValues(aValue, aDecl);
});
}
nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
const nsCSSPropertyID aPropID, const SVGAnimatedLength& aLength) {
return SetSMILValueHelper([aPropID, &aLength](DeclarationBlock& aDecl) {
return SVGElement::UpdateDeclarationBlockFromLength(
aDecl, aPropID, aLength, SVGElement::ValToUse::Anim);
});
}
nsresult nsDOMCSSAttributeDeclaration::SetPropertyValue(
const nsCSSPropertyID aPropID, const nsAString& aValue,
nsIPrincipal* aSubjectPrincipal) {

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

@ -18,6 +18,7 @@ struct RawServoUnlockedDeclarationBlock;
namespace mozilla {
class SMILValue;
class SVGAnimatedLength;
namespace dom {
class DomGroup;
@ -29,6 +30,7 @@ class nsDOMCSSAttributeDeclaration final : public nsDOMCSSDeclaration {
public:
typedef mozilla::dom::Element Element;
typedef mozilla::SMILValue SMILValue;
typedef mozilla::SVGAnimatedLength SVGAnimatedLength;
nsDOMCSSAttributeDeclaration(Element* aContent, bool aIsSMILOverride);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -45,7 +47,9 @@ class nsDOMCSSAttributeDeclaration final : public nsDOMCSSDeclaration {
nsINode* GetParentObject() override { return mElement; }
nsresult SetSMILValue(const nsCSSPropertyID aPropID, const SMILValue&);
nsresult SetSMILValue(const nsCSSPropertyID aPropID, const SMILValue& aValue);
nsresult SetSMILValue(const nsCSSPropertyID aPropID,
const SVGAnimatedLength& aLength);
nsresult SetPropertyValue(const nsCSSPropertyID aPropID,
const nsAString& aValue,
@ -79,6 +83,10 @@ class nsDOMCSSAttributeDeclaration final : public nsDOMCSSDeclaration {
* than the inline style rule).
*/
const bool mIsSMILOverride;
private:
template <typename SetterFunc>
nsresult SetSMILValueHelper(SetterFunc aFunc);
};
#endif /* nsDOMCSSAttributeDeclaration_h */