| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_STRING_KEYFRAME_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_STRING_KEYFRAME_H_ |
| |
| #include "third_party/blink/renderer/core/animation/keyframe.h" |
| #include "third_party/blink/renderer/core/css/css_property_value_set.h" |
| #include "third_party/blink/renderer/platform/heap/heap.h" |
| #include "third_party/blink/renderer/platform/wtf/hash_map.h" |
| |
| namespace blink { |
| |
| class StyleSheetContents; |
| |
| // An implementation of Keyframe used for CSS Animations, web-animations, and |
| // the HTML <marquee> element. |
| // |
| // A StringKeyframe instance supports an arbitrary number of (property, value) |
| // pairs. The properties can be CSS properties or SVG attributes, mapping to |
| // CSSValue or plain String values respectively. CSS properties added to a |
| // StringKeyframe are expanded to shorthand and de-duplicated, with newer |
| // properties replacing older ones. SVG attributes are similarly de-duplicated. |
| // |
| class CORE_EXPORT StringKeyframe : public Keyframe { |
| public: |
| StringKeyframe() |
| : presentation_attribute_map_( |
| MakeGarbageCollected<MutableCSSPropertyValueSet>( |
| kHTMLStandardMode)) {} |
| StringKeyframe(const StringKeyframe& copy_from); |
| |
| MutableCSSPropertyValueSet::SetResult SetCSSPropertyValue( |
| const AtomicString& custom_property_name, |
| const String& value, |
| SecureContextMode, |
| StyleSheetContents*); |
| MutableCSSPropertyValueSet::SetResult SetCSSPropertyValue( |
| CSSPropertyID, |
| const String& value, |
| SecureContextMode, |
| StyleSheetContents*); |
| void SetCSSPropertyValue(const CSSProperty&, const CSSValue&); |
| void RemoveCustomCSSProperty(const PropertyHandle& property); |
| |
| void SetPresentationAttributeValue(const CSSProperty&, |
| const String& value, |
| SecureContextMode, |
| StyleSheetContents*); |
| void SetSVGAttributeValue(const QualifiedName&, const String& value); |
| |
| const CSSValue& CssPropertyValue(const PropertyHandle& property) const { |
| EnsureCssPropertyMap(); |
| int index = -1; |
| if (property.IsCSSCustomProperty()) { |
| index = |
| css_property_map_->FindPropertyIndex(property.CustomPropertyName()); |
| } else { |
| DCHECK(!property.GetCSSProperty().IsShorthand()); |
| index = css_property_map_->FindPropertyIndex( |
| property.GetCSSProperty().PropertyID()); |
| } |
| CHECK_GE(index, 0); |
| return css_property_map_->PropertyAt(static_cast<unsigned>(index)).Value(); |
| } |
| |
| const CSSValue& PresentationAttributeValue( |
| const CSSProperty& property) const { |
| int index = |
| presentation_attribute_map_->FindPropertyIndex(property.PropertyID()); |
| CHECK_GE(index, 0); |
| return presentation_attribute_map_->PropertyAt(static_cast<unsigned>(index)) |
| .Value(); |
| } |
| |
| String SvgPropertyValue(const QualifiedName& attribute_name) const { |
| return svg_attribute_map_.at(&attribute_name); |
| } |
| |
| PropertyHandleSet Properties() const override; |
| |
| bool HasCssProperty() const; |
| |
| void AddKeyframePropertiesToV8Object(V8ObjectBuilder&, |
| Element*) const override; |
| |
| Keyframe* Clone() const override; |
| |
| bool HasLogicalProperty() { return has_logical_property_; } |
| |
| bool SetLogicalPropertyResolutionContext(TextDirection text_direction, |
| WritingMode writing_mode); |
| |
| void Trace(Visitor*) const override; |
| |
| class CSSPropertySpecificKeyframe |
| : public Keyframe::PropertySpecificKeyframe { |
| public: |
| CSSPropertySpecificKeyframe(double offset, |
| scoped_refptr<TimingFunction> easing, |
| const CSSValue* value, |
| EffectModel::CompositeOperation composite) |
| : Keyframe::PropertySpecificKeyframe(offset, |
| std::move(easing), |
| composite), |
| value_(value) {} |
| |
| const CSSValue* Value() const { return value_.Get(); } |
| |
| bool PopulateCompositorKeyframeValue( |
| const PropertyHandle&, |
| Element&, |
| const ComputedStyle& base_style, |
| const ComputedStyle* parent_style) const final; |
| const CompositorKeyframeValue* GetCompositorKeyframeValue() const final { |
| return compositor_keyframe_value_cache_; |
| } |
| |
| bool IsNeutral() const final { return !value_; } |
| bool IsRevert() const final; |
| Keyframe::PropertySpecificKeyframe* NeutralKeyframe( |
| double offset, |
| scoped_refptr<TimingFunction> easing) const final; |
| |
| void Trace(Visitor*) const override; |
| |
| private: |
| Keyframe::PropertySpecificKeyframe* CloneWithOffset( |
| double offset) const override; |
| bool IsCSSPropertySpecificKeyframe() const override { return true; } |
| |
| Member<const CSSValue> value_; |
| mutable Member<CompositorKeyframeValue> compositor_keyframe_value_cache_; |
| }; |
| |
| class SVGPropertySpecificKeyframe |
| : public Keyframe::PropertySpecificKeyframe { |
| public: |
| SVGPropertySpecificKeyframe(double offset, |
| scoped_refptr<TimingFunction> easing, |
| const String& value, |
| EffectModel::CompositeOperation composite) |
| : Keyframe::PropertySpecificKeyframe(offset, |
| std::move(easing), |
| composite), |
| value_(value) {} |
| |
| const String& Value() const { return value_; } |
| |
| PropertySpecificKeyframe* CloneWithOffset(double offset) const final; |
| |
| const CompositorKeyframeValue* GetCompositorKeyframeValue() const final { |
| return nullptr; |
| } |
| |
| bool IsNeutral() const final { return value_.IsNull(); } |
| bool IsRevert() const final { return false; } |
| PropertySpecificKeyframe* NeutralKeyframe( |
| double offset, |
| scoped_refptr<TimingFunction> easing) const final; |
| |
| private: |
| bool IsSVGPropertySpecificKeyframe() const override { return true; } |
| |
| String value_; |
| }; |
| |
| class PropertyResolver : public GarbageCollected<PropertyResolver> { |
| public: |
| // Custom properties must use this version of the constructor. |
| PropertyResolver(CSSPropertyID property_id, const CSSValue& css_value); |
| |
| // Shorthand and logical properties must use this version of the |
| // constructor. |
| PropertyResolver(const CSSProperty& property, |
| const MutableCSSPropertyValueSet* property_value_set, |
| bool is_logical); |
| |
| static PropertyResolver* CreateCustomVariableResolver( |
| const CSSValue& css_value); |
| |
| bool IsValid() const; |
| |
| const CSSValue* CssValue(); |
| |
| void AppendTo(MutableCSSPropertyValueSet* property_value_set, |
| TextDirection text_direction, |
| WritingMode writing_mode); |
| |
| void SetProperty(MutableCSSPropertyValueSet* property_value_set, |
| CSSPropertyID property_id, |
| const CSSValue& value, |
| TextDirection text_direction, |
| WritingMode writing_mode); |
| |
| static bool HasLowerPriority(PropertyResolver* first, |
| PropertyResolver* second); |
| |
| // Helper methods for resolving longhand name collisions. |
| // Longhands take priority over shorthands. |
| // Physical properties take priority over logical. |
| // Two shorthands with overlapping longhand properties are sorted based |
| // on the number of longhand properties in their expansions. |
| bool IsLogical() { return is_logical_; } |
| bool IsShorthand() { return css_property_value_set_; } |
| unsigned ExpansionCount() { |
| return css_property_value_set_ ? css_property_value_set_->PropertyCount() |
| : 1; |
| } |
| |
| void Trace(Visitor* visitor) const; |
| |
| private: |
| CSSPropertyID property_id_ = CSSPropertyID::kInvalid; |
| Member<const CSSValue> css_value_ = nullptr; |
| Member<ImmutableCSSPropertyValueSet> css_property_value_set_ = nullptr; |
| bool is_logical_ = false; |
| }; |
| |
| private: |
| Keyframe::PropertySpecificKeyframe* CreatePropertySpecificKeyframe( |
| const PropertyHandle&, |
| EffectModel::CompositeOperation effect_composite, |
| double offset) const override; |
| |
| void InvalidateCssPropertyMap() { css_property_map_ = nullptr; } |
| void EnsureCssPropertyMap() const; |
| |
| bool IsStringKeyframe() const override { return true; } |
| |
| // Mapping of unresolved properties to a their resolvers. A resolver knows |
| // how to expand shorthands to their corresponding longhand property names, |
| // convert logical to physical property names and compare precedence for |
| // resolving longhand name collisions. The resolver also knows how to |
| // create serialized text for a shorthand, which is required for getKeyframes |
| // calls. |
| // See: https://drafts.csswg.org/web-animations/#keyframes-section |
| HeapHashMap<PropertyHandle, Member<PropertyResolver>> input_properties_; |
| |
| // The resolved properties are computed from unresolved ones applying these |
| // steps: |
| // 1. Resolve conflicts when multiple properties map to same underlying |
| // one (e.g., margin, margin-top) |
| // 2. Expand shorthands to longhands |
| // 3. Expand logical properties to physical ones |
| mutable Member<MutableCSSPropertyValueSet> css_property_map_; |
| Member<MutableCSSPropertyValueSet> presentation_attribute_map_; |
| HashMap<const QualifiedName*, String> svg_attribute_map_; |
| |
| // If the keyframes contain one or more logical properties, these need to be |
| // remapped to physical properties when the writing mode or text direction |
| // changes. |
| bool has_logical_property_ = false; |
| |
| // The following properties are required for mapping logical to physical |
| // property names. Though the same for all keyframes within the same model, |
| // we store the value here to facilitate lazy evaluation of the CSS |
| // properties. |
| TextDirection text_direction_ = TextDirection::kLtr; |
| WritingMode writing_mode_ = WritingMode::kHorizontalTb; |
| }; |
| |
| using CSSPropertySpecificKeyframe = StringKeyframe::CSSPropertySpecificKeyframe; |
| using SVGPropertySpecificKeyframe = StringKeyframe::SVGPropertySpecificKeyframe; |
| |
| template <> |
| struct DowncastTraits<StringKeyframe> { |
| static bool AllowFrom(const Keyframe& value) { |
| return value.IsStringKeyframe(); |
| } |
| }; |
| template <> |
| struct DowncastTraits<CSSPropertySpecificKeyframe> { |
| static bool AllowFrom(const Keyframe::PropertySpecificKeyframe& value) { |
| return value.IsCSSPropertySpecificKeyframe(); |
| } |
| }; |
| template <> |
| struct DowncastTraits<SVGPropertySpecificKeyframe> { |
| static bool AllowFrom(const Keyframe::PropertySpecificKeyframe& value) { |
| return value.IsSVGPropertySpecificKeyframe(); |
| } |
| }; |
| |
| } // namespace blink |
| |
| #endif |