// 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. #include "third_party/blink/renderer/core/animation/string_keyframe.h" #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" #include "third_party/blink/renderer/core/animation/animation_input_helpers.h" #include "third_party/blink/renderer/core/animation/css/css_animations.h" #include "third_party/blink/renderer/core/css/css_custom_property_declaration.h" #include "third_party/blink/renderer/core/css/resolver/style_resolver.h" #include "third_party/blink/renderer/core/style_property_shorthand.h" #include "third_party/blink/renderer/core/svg/svg_element.h" namespace blink { StringKeyframe::StringKeyframe(const StringKeyframe& copy_from) : Keyframe(copy_from.offset_, copy_from.composite_, copy_from.easing_), css_property_map_(copy_from.css_property_map_->MutableCopy()), presentation_attribute_map_( copy_from.presentation_attribute_map_->MutableCopy()), svg_attribute_map_(copy_from.svg_attribute_map_) {} MutableCSSPropertyValueSet::SetResult StringKeyframe::SetCSSPropertyValue( const AtomicString& property_name, const PropertyRegistry* registry, const String& value, SecureContextMode secure_context_mode, StyleSheetContents* style_sheet_contents) { bool is_animation_tainted = true; return css_property_map_->SetProperty( property_name, registry, value, false, secure_context_mode, style_sheet_contents, is_animation_tainted); } MutableCSSPropertyValueSet::SetResult StringKeyframe::SetCSSPropertyValue( CSSPropertyID property, const String& value, SecureContextMode secure_context_mode, StyleSheetContents* style_sheet_contents) { DCHECK_NE(property, CSSPropertyInvalid); if (CSSAnimations::IsAnimationAffectingProperty(CSSProperty::Get(property))) { bool did_parse = true; bool did_change = false; return MutableCSSPropertyValueSet::SetResult{did_parse, did_change}; } return css_property_map_->SetProperty( property, value, false, secure_context_mode, style_sheet_contents); } void StringKeyframe::SetCSSPropertyValue(const CSSProperty& property, const CSSValue& value) { DCHECK_NE(property.PropertyID(), CSSPropertyInvalid); DCHECK(!CSSAnimations::IsAnimationAffectingProperty(property)); css_property_map_->SetProperty(property.PropertyID(), value, false); } void StringKeyframe::SetPresentationAttributeValue( const CSSProperty& property, const String& value, SecureContextMode secure_context_mode, StyleSheetContents* style_sheet_contents) { DCHECK_NE(property.PropertyID(), CSSPropertyInvalid); if (!CSSAnimations::IsAnimationAffectingProperty(property)) { presentation_attribute_map_->SetProperty(property.PropertyID(), value, false, secure_context_mode, style_sheet_contents); } } void StringKeyframe::SetSVGAttributeValue(const QualifiedName& attribute_name, const String& value) { svg_attribute_map_.Set(&attribute_name, value); } PropertyHandleSet StringKeyframe::Properties() const { // This is not used in time-critical code, so we probably don't need to // worry about caching this result. PropertyHandleSet properties; for (unsigned i = 0; i < css_property_map_->PropertyCount(); ++i) { CSSPropertyValueSet::PropertyReference property_reference = css_property_map_->PropertyAt(i); const CSSProperty& property = property_reference.Property(); DCHECK(!property.IsShorthand()) << "Web Animations: Encountered unexpanded shorthand CSS property (" << property.PropertyID() << ")."; if (property.IDEquals(CSSPropertyVariable)) { properties.insert(PropertyHandle( ToCSSCustomPropertyDeclaration(property_reference.Value()) .GetName())); } else { properties.insert(PropertyHandle(property, false)); } } for (unsigned i = 0; i < presentation_attribute_map_->PropertyCount(); ++i) { properties.insert(PropertyHandle( presentation_attribute_map_->PropertyAt(i).Property(), true)); } for (auto* const key : svg_attribute_map_.Keys()) properties.insert(PropertyHandle(*key)); return properties; } bool StringKeyframe::HasCssProperty() const { PropertyHandleSet properties = Properties(); for (const PropertyHandle& property : properties) { if (property.IsCSSProperty()) return true; } return false; } void StringKeyframe::AddKeyframePropertiesToV8Object( V8ObjectBuilder& object_builder) const { Keyframe::AddKeyframePropertiesToV8Object(object_builder); for (const PropertyHandle& property : Properties()) { String property_name = AnimationInputHelpers::PropertyHandleToKeyframeAttribute(property); String value; if (property.IsCSSProperty()) { value = CssPropertyValue(property).CssText(); } else if (property.IsPresentationAttribute()) { const auto& attribute = property.PresentationAttribute(); value = PresentationAttributeValue(attribute).CssText(); } else { DCHECK(property.IsSVGAttribute()); value = SvgPropertyValue(property.SvgAttribute()); } object_builder.Add(property_name, value); } } scoped_refptr StringKeyframe::Clone() const { return base::AdoptRef(new StringKeyframe(*this)); } scoped_refptr StringKeyframe::CreatePropertySpecificKeyframe( const PropertyHandle& property, EffectModel::CompositeOperation effect_composite, double offset) const { EffectModel::CompositeOperation composite = composite_.value_or(effect_composite); if (property.IsCSSProperty()) { return CSSPropertySpecificKeyframe::Create( offset, &Easing(), &CssPropertyValue(property), composite); } if (property.IsPresentationAttribute()) { return CSSPropertySpecificKeyframe::Create( offset, &Easing(), &PresentationAttributeValue(property.PresentationAttribute()), composite); } DCHECK(property.IsSVGAttribute()); return SVGPropertySpecificKeyframe::Create( offset, &Easing(), SvgPropertyValue(property.SvgAttribute()), composite); } bool StringKeyframe::CSSPropertySpecificKeyframe::PopulateAnimatableValue( const CSSProperty& property, Element& element, const ComputedStyle& base_style, const ComputedStyle* parent_style) const { animatable_value_cache_ = StyleResolver::CreateAnimatableValueSnapshot( element, base_style, parent_style, property, value_.Get()); return true; } scoped_refptr StringKeyframe::CSSPropertySpecificKeyframe::NeutralKeyframe( double offset, scoped_refptr easing) const { return Create(offset, std::move(easing), nullptr, EffectModel::kCompositeAdd); } scoped_refptr StringKeyframe::CSSPropertySpecificKeyframe::CloneWithOffset( double offset) const { scoped_refptr clone = Create(offset, easing_, value_.Get(), composite_); clone->animatable_value_cache_ = animatable_value_cache_; return clone; } scoped_refptr SVGPropertySpecificKeyframe::CloneWithOffset(double offset) const { return Create(offset, easing_, value_, composite_); } scoped_refptr SVGPropertySpecificKeyframe::NeutralKeyframe( double offset, scoped_refptr easing) const { return Create(offset, std::move(easing), String(), EffectModel::kCompositeAdd); } } // namespace blink