// Copyright 2016 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/css_interpolation_types_map.h" #include #include #include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h" #include "third_party/blink/renderer/core/animation/css_angle_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_border_image_length_box_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_clip_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_color_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_custom_length_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_custom_list_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_default_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_filter_list_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_font_size_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_font_stretch_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_font_weight_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_image_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_image_list_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_image_slice_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_length_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_length_list_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_length_pair_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_number_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_offset_rotate_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_paint_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_path_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_percentage_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_position_axis_list_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_position_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_ray_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_resolution_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_rotate_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_scale_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_shadow_list_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_size_list_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_text_indent_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_time_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_transform_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_transform_origin_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_translate_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_var_cycle_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_visibility_interpolation_type.h" #include "third_party/blink/renderer/core/css/css_property_names.h" #include "third_party/blink/renderer/core/css/css_syntax_definition.h" #include "third_party/blink/renderer/core/css/properties/css_property.h" #include "third_party/blink/renderer/core/css/property_registry.h" #include "third_party/blink/renderer/core/feature_policy/layout_animations_policy.h" #include "third_party/blink/renderer/core/frame/local_frame.h" namespace blink { CSSInterpolationTypesMap::CSSInterpolationTypesMap( const PropertyRegistry* registry, const Document& document) : registry_(registry) { allow_all_animations_ = document.GetExecutionContext()->IsFeatureEnabled( blink::mojom::blink::DocumentPolicyFeature::kLayoutAnimations); } static const PropertyRegistration* GetRegistration( const PropertyRegistry* registry, const PropertyHandle& property) { DCHECK(property.IsCSSCustomProperty()); if (!registry) { return nullptr; } return registry->Registration(property.CustomPropertyName()); } const InterpolationTypes& CSSInterpolationTypesMap::Get( const PropertyHandle& property) const { using ApplicableTypesMap = HashMap>; // TODO(iclelland): Combine these two hashmaps into a single map on // std::pair DEFINE_STATIC_LOCAL(ApplicableTypesMap, all_applicable_types_map, ()); DEFINE_STATIC_LOCAL(ApplicableTypesMap, composited_applicable_types_map, ()); ApplicableTypesMap& applicable_types_map = allow_all_animations_ ? all_applicable_types_map : composited_applicable_types_map; auto entry = applicable_types_map.find(property); bool found_entry = entry != applicable_types_map.end(); // Custom property interpolation types may change over time so don't trust the // applicableTypesMap without checking the registry. if (registry_ && property.IsCSSCustomProperty()) { const auto* registration = GetRegistration(registry_, property); if (registration) { if (found_entry) { applicable_types_map.erase(entry); } return registration->GetInterpolationTypes(); } } if (found_entry) { return *entry->value; } std::unique_ptr applicable_types = std::make_unique(); const CSSProperty& css_property = property.IsCSSProperty() ? property.GetCSSProperty() : property.PresentationAttribute(); // We treat presentation attributes identically to their CSS property // equivalents when interpolating. PropertyHandle used_property = property.IsCSSProperty() ? property : PropertyHandle(css_property); // TODO(crbug.com/838263): Support site-defined list of acceptable properties // through feature policy declarations. bool property_maybe_blocked_by_feature_policy = LayoutAnimationsPolicy::AffectedCSSProperties().Contains(&css_property); if (allow_all_animations_ || !property_maybe_blocked_by_feature_policy) { switch (css_property.PropertyID()) { case CSSPropertyID::kBaselineShift: case CSSPropertyID::kBorderBottomWidth: case CSSPropertyID::kBorderLeftWidth: case CSSPropertyID::kBorderRightWidth: case CSSPropertyID::kBorderTopWidth: case CSSPropertyID::kBottom: case CSSPropertyID::kCx: case CSSPropertyID::kCy: case CSSPropertyID::kFlexBasis: case CSSPropertyID::kHeight: case CSSPropertyID::kLeft: case CSSPropertyID::kLetterSpacing: case CSSPropertyID::kMarginBottom: case CSSPropertyID::kMarginLeft: case CSSPropertyID::kMarginRight: case CSSPropertyID::kMarginTop: case CSSPropertyID::kMaxHeight: case CSSPropertyID::kMaxWidth: case CSSPropertyID::kMinHeight: case CSSPropertyID::kMinWidth: case CSSPropertyID::kOffsetDistance: case CSSPropertyID::kOutlineOffset: case CSSPropertyID::kOutlineWidth: case CSSPropertyID::kPaddingBottom: case CSSPropertyID::kPaddingLeft: case CSSPropertyID::kPaddingRight: case CSSPropertyID::kPaddingTop: case CSSPropertyID::kPerspective: case CSSPropertyID::kR: case CSSPropertyID::kRight: case CSSPropertyID::kRx: case CSSPropertyID::kRy: case CSSPropertyID::kShapeMargin: case CSSPropertyID::kStrokeDashoffset: case CSSPropertyID::kStrokeWidth: case CSSPropertyID::kTextDecorationThickness: case CSSPropertyID::kTextUnderlineOffset: case CSSPropertyID::kTop: case CSSPropertyID::kVerticalAlign: case CSSPropertyID::kWebkitBorderHorizontalSpacing: case CSSPropertyID::kWebkitBorderVerticalSpacing: case CSSPropertyID::kColumnGap: case CSSPropertyID::kRowGap: case CSSPropertyID::kColumnRuleWidth: case CSSPropertyID::kColumnWidth: case CSSPropertyID::kWebkitPerspectiveOriginX: case CSSPropertyID::kWebkitPerspectiveOriginY: case CSSPropertyID::kWebkitTransformOriginX: case CSSPropertyID::kWebkitTransformOriginY: case CSSPropertyID::kWebkitTransformOriginZ: case CSSPropertyID::kWidth: case CSSPropertyID::kWordSpacing: case CSSPropertyID::kX: case CSSPropertyID::kY: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kFlexGrow: case CSSPropertyID::kFlexShrink: case CSSPropertyID::kFillOpacity: case CSSPropertyID::kFloodOpacity: case CSSPropertyID::kFontSizeAdjust: case CSSPropertyID::kOpacity: case CSSPropertyID::kOrder: case CSSPropertyID::kOrphans: case CSSPropertyID::kShapeImageThreshold: case CSSPropertyID::kStopOpacity: case CSSPropertyID::kStrokeMiterlimit: case CSSPropertyID::kStrokeOpacity: case CSSPropertyID::kColumnCount: case CSSPropertyID::kTextSizeAdjust: case CSSPropertyID::kWidows: case CSSPropertyID::kZIndex: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kLineHeight: case CSSPropertyID::kTabSize: applicable_types->push_back( std::make_unique(used_property)); applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kBackgroundColor: case CSSPropertyID::kBorderBottomColor: case CSSPropertyID::kBorderLeftColor: case CSSPropertyID::kBorderRightColor: case CSSPropertyID::kBorderTopColor: case CSSPropertyID::kCaretColor: case CSSPropertyID::kColor: case CSSPropertyID::kFloodColor: case CSSPropertyID::kLightingColor: case CSSPropertyID::kOutlineColor: case CSSPropertyID::kStopColor: case CSSPropertyID::kTextDecorationColor: case CSSPropertyID::kColumnRuleColor: case CSSPropertyID::kWebkitTextStrokeColor: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kFill: case CSSPropertyID::kStroke: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kOffsetPath: applicable_types->push_back( std::make_unique(used_property)); FALLTHROUGH; case CSSPropertyID::kD: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kBoxShadow: case CSSPropertyID::kTextShadow: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kBorderImageSource: case CSSPropertyID::kListStyleImage: case CSSPropertyID::kWebkitMaskBoxImageSource: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kBackgroundImage: case CSSPropertyID::kWebkitMaskImage: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kStrokeDasharray: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kFontWeight: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kFontStretch: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kFontVariationSettings: applicable_types->push_back( std::make_unique( used_property)); break; case CSSPropertyID::kVisibility: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kClip: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kOffsetRotate: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kBackgroundPositionX: case CSSPropertyID::kBackgroundPositionY: case CSSPropertyID::kWebkitMaskPositionX: case CSSPropertyID::kWebkitMaskPositionY: applicable_types->push_back( std::make_unique( used_property)); break; case CSSPropertyID::kObjectPosition: case CSSPropertyID::kOffsetAnchor: case CSSPropertyID::kOffsetPosition: case CSSPropertyID::kPerspectiveOrigin: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kBorderBottomLeftRadius: case CSSPropertyID::kBorderBottomRightRadius: case CSSPropertyID::kBorderTopLeftRadius: case CSSPropertyID::kBorderTopRightRadius: case CSSPropertyID::kContainIntrinsicSize: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kTranslate: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kTransformOrigin: applicable_types->push_back( std::make_unique( used_property)); break; case CSSPropertyID::kBackgroundSize: case CSSPropertyID::kWebkitMaskSize: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kBorderImageOutset: case CSSPropertyID::kBorderImageWidth: case CSSPropertyID::kWebkitMaskBoxImageOutset: case CSSPropertyID::kWebkitMaskBoxImageWidth: applicable_types->push_back( std::make_unique( used_property)); break; case CSSPropertyID::kScale: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kFontSize: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kTextIndent: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kBorderImageSlice: case CSSPropertyID::kWebkitMaskBoxImageSlice: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kClipPath: case CSSPropertyID::kShapeOutside: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kRotate: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kBackdropFilter: case CSSPropertyID::kFilter: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kTransform: applicable_types->push_back( std::make_unique(used_property)); break; case CSSPropertyID::kVariable: DCHECK_EQ(GetRegistration(registry_, property), nullptr); break; default: DCHECK(!css_property.IsInterpolable()); break; } } applicable_types->push_back( std::make_unique(used_property)); auto add_result = applicable_types_map.insert(property, std::move(applicable_types)); return *add_result.stored_value->value; } size_t CSSInterpolationTypesMap::Version() const { return registry_ ? registry_->Version() : 0; } static std::unique_ptr CreateInterpolationTypeForCSSSyntax(CSSSyntaxType syntax, PropertyHandle property, const PropertyRegistration& registration) { switch (syntax) { case CSSSyntaxType::kAngle: return std::make_unique(property, ®istration); case CSSSyntaxType::kColor: return std::make_unique(property, ®istration); case CSSSyntaxType::kLength: return std::make_unique(property, ®istration); case CSSSyntaxType::kLengthPercentage: return std::make_unique(property, ®istration); case CSSSyntaxType::kPercentage: return std::make_unique(property, ®istration); case CSSSyntaxType::kNumber: return std::make_unique(property, ®istration); case CSSSyntaxType::kResolution: return std::make_unique(property, ®istration); case CSSSyntaxType::kTime: return std::make_unique(property, ®istration); case CSSSyntaxType::kImage: // TODO(andruud): Implement smooth interpolation for gradients. return nullptr; case CSSSyntaxType::kInteger: return std::make_unique(property, ®istration, true); case CSSSyntaxType::kTransformFunction: case CSSSyntaxType::kTransformList: // TODO(alancutter): Support smooth interpolation of these types. return nullptr; case CSSSyntaxType::kCustomIdent: case CSSSyntaxType::kIdent: case CSSSyntaxType::kTokenStream: case CSSSyntaxType::kUrl: // Smooth interpolation not supported for these types. return nullptr; default: NOTREACHED(); return nullptr; } } InterpolationTypes CSSInterpolationTypesMap::CreateInterpolationTypesForCSSSyntax( const AtomicString& property_name, const CSSSyntaxDefinition& definition, const PropertyRegistration& registration) { PropertyHandle property(property_name); InterpolationTypes result; // All custom properties may encounter var() dependency cycles. result.push_back( std::make_unique(property, registration)); for (const CSSSyntaxComponent& component : definition.Components()) { std::unique_ptr interpolation_type = CreateInterpolationTypeForCSSSyntax(component.GetType(), property, registration); if (!interpolation_type) continue; if (component.IsRepeatable()) { interpolation_type = std::make_unique( property, ®istration, std::move(interpolation_type), component.GetType(), component.GetRepeat()); } result.push_back(std::move(interpolation_type)); } result.push_back(std::make_unique(property)); return result; } } // namespace blink