StyleAnimationValue.cpp (9174B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* Utilities for animation of computed style values */ 8 9 #include "mozilla/StyleAnimationValue.h" 10 11 #include "gfx2DGlue.h" 12 #include "gfxMatrix.h" 13 #include "gfxQuaternion.h" 14 #include "mozilla/ComputedStyle.h" 15 #include "mozilla/ComputedStyleInlines.h" 16 #include "mozilla/PresShell.h" 17 #include "mozilla/PresShellInlines.h" 18 #include "mozilla/ServoBindings.h" // StyleLockedDeclarationBlock 19 #include "mozilla/ServoCSSParser.h" 20 #include "mozilla/ServoStyleSet.h" 21 #include "mozilla/dom/Document.h" 22 #include "mozilla/dom/Element.h" 23 #include "mozilla/layers/LayersMessages.h" 24 #include "nsCOMArray.h" 25 #include "nsCSSPseudoElements.h" 26 #include "nsComputedDOMStyle.h" 27 #include "nsIFrame.h" 28 #include "nsString.h" 29 30 using namespace mozilla; 31 using namespace mozilla::css; 32 using namespace mozilla::dom; 33 using namespace mozilla::gfx; 34 35 bool AnimationValue::operator==(const AnimationValue& aOther) const { 36 if (mServo && aOther.mServo) { 37 return Servo_AnimationValue_DeepEqual(mServo, aOther.mServo); 38 } 39 if (!mServo && !aOther.mServo) { 40 return true; 41 } 42 return false; 43 } 44 45 bool AnimationValue::operator!=(const AnimationValue& aOther) const { 46 return !operator==(aOther); 47 } 48 49 float AnimationValue::GetOpacity() const { 50 MOZ_ASSERT(mServo); 51 return Servo_AnimationValue_GetOpacity(mServo); 52 } 53 54 nscolor AnimationValue::GetColor(nscolor aForegroundColor) const { 55 MOZ_ASSERT(mServo); 56 return Servo_AnimationValue_GetColor(mServo, aForegroundColor); 57 } 58 59 bool AnimationValue::IsCurrentColor() const { 60 MOZ_ASSERT(mServo); 61 return Servo_AnimationValue_IsCurrentColor(mServo); 62 } 63 64 const StyleTranslate& AnimationValue::GetTranslateProperty() const { 65 MOZ_ASSERT(mServo); 66 return *Servo_AnimationValue_GetTranslate(mServo); 67 } 68 69 const StyleRotate& AnimationValue::GetRotateProperty() const { 70 MOZ_ASSERT(mServo); 71 return *Servo_AnimationValue_GetRotate(mServo); 72 } 73 74 const StyleScale& AnimationValue::GetScaleProperty() const { 75 MOZ_ASSERT(mServo); 76 return *Servo_AnimationValue_GetScale(mServo); 77 } 78 79 const StyleTransform& AnimationValue::GetTransformProperty() const { 80 MOZ_ASSERT(mServo); 81 return *Servo_AnimationValue_GetTransform(mServo); 82 } 83 84 void AnimationValue::GetOffsetPathProperty(StyleOffsetPath& aOffsetPath) const { 85 MOZ_ASSERT(mServo); 86 Servo_AnimationValue_GetOffsetPath(mServo, &aOffsetPath); 87 } 88 89 const mozilla::LengthPercentage& AnimationValue::GetOffsetDistanceProperty() 90 const { 91 MOZ_ASSERT(mServo); 92 return *Servo_AnimationValue_GetOffsetDistance(mServo); 93 } 94 95 const mozilla::StyleOffsetRotate& AnimationValue::GetOffsetRotateProperty() 96 const { 97 MOZ_ASSERT(mServo); 98 return *Servo_AnimationValue_GetOffsetRotate(mServo); 99 } 100 101 const mozilla::StylePositionOrAuto& AnimationValue::GetOffsetAnchorProperty() 102 const { 103 MOZ_ASSERT(mServo); 104 return *Servo_AnimationValue_GetOffsetAnchor(mServo); 105 } 106 107 const mozilla::StyleOffsetPosition& AnimationValue::GetOffsetPositionProperty() 108 const { 109 MOZ_ASSERT(mServo); 110 return *Servo_AnimationValue_GetOffsetPosition(mServo); 111 } 112 113 bool AnimationValue::IsOffsetPathUrl() const { 114 return mServo && Servo_AnimationValue_IsOffsetPathUrl(mServo); 115 } 116 117 MatrixScales AnimationValue::GetScaleValue(const nsIFrame* aFrame) const { 118 using namespace nsStyleTransformMatrix; 119 120 CSSPropertyId property(eCSSProperty_UNKNOWN); 121 Servo_AnimationValue_GetPropertyId(mServo, &property); 122 switch (property.mId) { 123 case eCSSProperty_scale: { 124 const StyleScale& scale = GetScaleProperty(); 125 return scale.IsNone() 126 ? MatrixScales() 127 : MatrixScales(scale.AsScale()._0, scale.AsScale()._1); 128 } 129 case eCSSProperty_rotate: 130 case eCSSProperty_translate: 131 return MatrixScales(); 132 case eCSSProperty_transform: 133 break; 134 default: 135 MOZ_ASSERT_UNREACHABLE( 136 "Should only need to check in transform properties"); 137 return MatrixScales(); 138 } 139 140 TransformReferenceBox refBox(aFrame); 141 Matrix4x4 t = 142 ReadTransforms(StyleTranslate::None(), StyleRotate::None(), 143 StyleScale::None(), nullptr, GetTransformProperty(), 144 refBox, aFrame->PresContext()->AppUnitsPerDevPixel()); 145 Matrix transform2d; 146 bool canDraw2D = t.CanDraw2D(&transform2d); 147 if (!canDraw2D) { 148 return MatrixScales(0, 0); 149 } 150 return transform2d.ScaleFactors(); 151 } 152 153 void AnimationValue::SerializeSpecifiedValue( 154 const CSSPropertyId& aProperty, const StylePerDocumentStyleData* aRawData, 155 nsACString& aString) const { 156 MOZ_ASSERT(mServo); 157 Servo_AnimationValue_Serialize(mServo, &aProperty, aRawData, &aString); 158 } 159 160 bool AnimationValue::IsInterpolableWith(const CSSPropertyId& aProperty, 161 const AnimationValue& aToValue) const { 162 if (IsNull() || aToValue.IsNull()) { 163 return false; 164 } 165 166 MOZ_ASSERT(mServo); 167 MOZ_ASSERT(aToValue.mServo); 168 return Servo_AnimationValues_IsInterpolable(mServo, aToValue.mServo); 169 } 170 171 double AnimationValue::ComputeDistance(const AnimationValue& aOther) const { 172 if (IsNull() || aOther.IsNull()) { 173 return 0.0; 174 } 175 176 MOZ_ASSERT(mServo); 177 MOZ_ASSERT(aOther.mServo); 178 179 double distance = 180 Servo_AnimationValues_ComputeDistance(mServo, aOther.mServo); 181 return distance < 0.0 ? 0.0 : distance; 182 } 183 184 /* static */ 185 AnimationValue AnimationValue::FromString(CSSPropertyId& aProperty, 186 const nsACString& aValue, 187 Element* aElement) { 188 MOZ_ASSERT(aElement); 189 190 AnimationValue result; 191 192 nsCOMPtr<Document> doc = aElement->GetComposedDoc(); 193 if (!doc) { 194 return result; 195 } 196 197 RefPtr<PresShell> presShell = doc->GetPresShell(); 198 if (!presShell) { 199 return result; 200 } 201 202 // GetComputedStyle() flushes style, so we shouldn't assume that any 203 // non-owning references we have are still valid. 204 RefPtr<const ComputedStyle> computedStyle = 205 nsComputedDOMStyle::GetComputedStyle(aElement); 206 MOZ_ASSERT(computedStyle); 207 208 RefPtr<StyleLockedDeclarationBlock> declarations = 209 ServoCSSParser::ParseProperty(aProperty, aValue, 210 ServoCSSParser::GetParsingEnvironment(doc), 211 StyleParsingMode::DEFAULT); 212 213 if (!declarations) { 214 return result; 215 } 216 217 result.mServo = presShell->StyleSet()->ComputeAnimationValue( 218 aElement, declarations, computedStyle); 219 return result; 220 } 221 222 /* static */ 223 already_AddRefed<StyleAnimationValue> AnimationValue::FromAnimatable( 224 NonCustomCSSPropertyId aProperty, const layers::Animatable& aAnimatable) { 225 switch (aAnimatable.type()) { 226 case layers::Animatable::Tnull_t: 227 break; 228 case layers::Animatable::TStyleTransform: { 229 const StyleTransform& transform = aAnimatable.get_StyleTransform(); 230 MOZ_ASSERT(!transform.HasPercent(), 231 "Received transform operations should have been resolved."); 232 return Servo_AnimationValue_Transform(&transform).Consume(); 233 } 234 case layers::Animatable::Tfloat: 235 return Servo_AnimationValue_Opacity(aAnimatable.get_float()).Consume(); 236 case layers::Animatable::Tnscolor: 237 return Servo_AnimationValue_Color(aProperty, aAnimatable.get_nscolor()) 238 .Consume(); 239 case layers::Animatable::TStyleRotate: 240 return Servo_AnimationValue_Rotate(&aAnimatable.get_StyleRotate()) 241 .Consume(); 242 case layers::Animatable::TStyleScale: 243 return Servo_AnimationValue_Scale(&aAnimatable.get_StyleScale()) 244 .Consume(); 245 case layers::Animatable::TStyleTranslate: 246 MOZ_ASSERT( 247 aAnimatable.get_StyleTranslate().IsNone() || 248 (!aAnimatable.get_StyleTranslate() 249 .AsTranslate() 250 ._0.HasPercent() && 251 !aAnimatable.get_StyleTranslate().AsTranslate()._1.HasPercent()), 252 "Should have been resolved already"); 253 return Servo_AnimationValue_Translate(&aAnimatable.get_StyleTranslate()) 254 .Consume(); 255 case layers::Animatable::TStyleOffsetPath: 256 return Servo_AnimationValue_OffsetPath(&aAnimatable.get_StyleOffsetPath()) 257 .Consume(); 258 case layers::Animatable::TLengthPercentage: 259 return Servo_AnimationValue_OffsetDistance( 260 &aAnimatable.get_LengthPercentage()) 261 .Consume(); 262 case layers::Animatable::TStyleOffsetRotate: 263 return Servo_AnimationValue_OffsetRotate( 264 &aAnimatable.get_StyleOffsetRotate()) 265 .Consume(); 266 case layers::Animatable::TStylePositionOrAuto: 267 return Servo_AnimationValue_OffsetAnchor( 268 &aAnimatable.get_StylePositionOrAuto()) 269 .Consume(); 270 case layers::Animatable::TStyleOffsetPosition: 271 return Servo_AnimationValue_OffsetPosition( 272 &aAnimatable.get_StyleOffsetPosition()) 273 .Consume(); 274 default: 275 MOZ_ASSERT_UNREACHABLE("Unsupported type"); 276 } 277 return nullptr; 278 }