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 /* representation of a SMIL-animatable CSS property on an element */
8 
9 #include "nsSMILCSSProperty.h"
10 
11 #include "mozilla/dom/Element.h"
12 #include "mozilla/Move.h"
13 #include "mozilla/ServoBindings.h"
14 #include "mozilla/StyleAnimationValue.h"
15 #include "nsDOMCSSAttrDeclaration.h"
16 #include "nsSMILCSSValueType.h"
17 #include "nsSMILValue.h"
18 #include "nsCSSProps.h"
19 
20 using namespace mozilla;
21 using namespace mozilla::dom;
22 
23 // Class Methods
nsSMILCSSProperty(nsCSSPropertyID aPropID,Element * aElement,nsStyleContext * aBaseStyleContext)24 nsSMILCSSProperty::nsSMILCSSProperty(nsCSSPropertyID aPropID, Element* aElement,
25                                      nsStyleContext* aBaseStyleContext)
26     : mPropID(aPropID),
27       mElement(aElement),
28       mBaseStyleContext(aBaseStyleContext) {
29   MOZ_ASSERT(IsPropertyAnimatable(mPropID,
30                                   aElement->OwnerDoc()->GetStyleBackendType()),
31              "Creating a nsSMILCSSProperty for a property "
32              "that's not supported for animation");
33 }
34 
GetBaseValue() const35 nsSMILValue nsSMILCSSProperty::GetBaseValue() const {
36   // To benefit from Return Value Optimization and avoid copy constructor calls
37   // due to our use of return-by-value, we must return the exact same object
38   // from ALL return points. This function must only return THIS variable:
39   nsSMILValue baseValue;
40 
41   // SPECIAL CASE: (a) Shorthands
42   //               (b) 'display'
43   //               (c) No base style context
44   if (nsCSSProps::IsShorthand(mPropID) || mPropID == eCSSProperty_display ||
45       !mBaseStyleContext) {
46     // We can't look up the base (computed-style) value of shorthand
47     // properties because they aren't guaranteed to have a consistent computed
48     // value.
49     //
50     // Also, although we can look up the base value of the display property,
51     // doing so involves clearing and resetting the property which can cause
52     // frames to be recreated which we'd like to avoid.
53     //
54     // Furthermore, if we don't (yet) have a base style context we obviously
55     // can't resolve a base value.
56     //
57     // In any case, just return a dummy value (initialized with the right
58     // type, so as not to indicate failure).
59     nsSMILValue tmpVal(&nsSMILCSSValueType::sSingleton);
60     Swap(baseValue, tmpVal);
61     return baseValue;
62   }
63 
64   AnimationValue computedValue;
65   if (mElement->IsStyledByServo()) {
66     computedValue.mServo = Servo_ComputedValues_ExtractAnimationValue(
67                                mBaseStyleContext->AsServo(), mPropID)
68                                .Consume();
69     if (!computedValue.mServo) {
70       return baseValue;
71     }
72   } else {
73 #ifdef MOZ_OLD_STYLE
74     if (!StyleAnimationValue::ExtractComputedValue(
75             mPropID, mBaseStyleContext->AsGecko(), computedValue.mGecko)) {
76       return baseValue;
77     }
78 #else
79     MOZ_CRASH("old style system disabled");
80 #endif
81   }
82 
83   baseValue = nsSMILCSSValueType::ValueFromAnimationValue(mPropID, mElement,
84                                                           computedValue);
85   return baseValue;
86 }
87 
ValueFromString(const nsAString & aStr,const SVGAnimationElement * aSrcElement,nsSMILValue & aValue,bool & aPreventCachingOfSandwich) const88 nsresult nsSMILCSSProperty::ValueFromString(
89     const nsAString& aStr, const SVGAnimationElement* aSrcElement,
90     nsSMILValue& aValue, bool& aPreventCachingOfSandwich) const {
91   NS_ENSURE_TRUE(IsPropertyAnimatable(
92                      mPropID, mElement->OwnerDoc()->GetStyleBackendType()),
93                  NS_ERROR_FAILURE);
94 
95   nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue,
96                                       &aPreventCachingOfSandwich);
97 
98   if (aValue.IsNull()) {
99     return NS_ERROR_FAILURE;
100   }
101 
102   // XXX Due to bug 536660 (or at least that seems to be the most likely
103   // culprit), when we have animation setting display:none on a <use> element,
104   // if we DON'T set the property every sample, chaos ensues.
105   if (!aPreventCachingOfSandwich && mPropID == eCSSProperty_display) {
106     aPreventCachingOfSandwich = true;
107   }
108   return NS_OK;
109 }
110 
SetAnimValue(const nsSMILValue & aValue)111 nsresult nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue) {
112   NS_ENSURE_TRUE(IsPropertyAnimatable(
113                      mPropID, mElement->OwnerDoc()->GetStyleBackendType()),
114                  NS_ERROR_FAILURE);
115 
116   // Convert nsSMILValue to string
117   nsAutoString valStr;
118   nsSMILCSSValueType::ValueToString(aValue, valStr);
119 
120   // Use string value to style the target element
121   nsDOMCSSAttributeDeclaration* overrideDecl = mElement->GetSMILOverrideStyle();
122   if (overrideDecl) {
123     nsAutoString oldValStr;
124     overrideDecl->GetPropertyValue(mPropID, oldValStr);
125     if (valStr.Equals(oldValStr)) {
126       return NS_OK;
127     }
128     overrideDecl->SetPropertyValue(mPropID, valStr, nullptr);
129   }
130   return NS_OK;
131 }
132 
ClearAnimValue()133 void nsSMILCSSProperty::ClearAnimValue() {
134   // Put empty string in override style for our property
135   nsDOMCSSAttributeDeclaration* overrideDecl = mElement->GetSMILOverrideStyle();
136   if (overrideDecl) {
137     overrideDecl->SetPropertyValue(mPropID, EmptyString(), nullptr);
138   }
139 }
140 
141 // Based on http://www.w3.org/TR/SVG/propidx.html
142 // static
IsPropertyAnimatable(nsCSSPropertyID aPropID,StyleBackendType aBackend)143 bool nsSMILCSSProperty::IsPropertyAnimatable(nsCSSPropertyID aPropID,
144                                              StyleBackendType aBackend) {
145   // Bug 1353918: Drop this check
146   if (aBackend == StyleBackendType::Servo &&
147       !Servo_Property_IsAnimatable(aPropID)) {
148     return false;
149   }
150 
151   // NOTE: Right now, Gecko doesn't recognize the following properties from
152   // the SVG Property Index:
153   //   alignment-baseline
154   //   baseline-shift
155   //   color-profile
156   //   color-rendering
157   //   glyph-orientation-horizontal
158   //   glyph-orientation-vertical
159   //   kerning
160   //   writing-mode
161 
162   switch (aPropID) {
163     case eCSSProperty_clip:
164     case eCSSProperty_clip_rule:
165     case eCSSProperty_clip_path:
166     case eCSSProperty_color:
167     case eCSSProperty_color_interpolation:
168     case eCSSProperty_color_interpolation_filters:
169     case eCSSProperty_cursor:
170     case eCSSProperty_display:
171     case eCSSProperty_dominant_baseline:
172     case eCSSProperty_fill:
173     case eCSSProperty_fill_opacity:
174     case eCSSProperty_fill_rule:
175     case eCSSProperty_filter:
176     case eCSSProperty_flood_color:
177     case eCSSProperty_flood_opacity:
178     case eCSSProperty_font:
179     case eCSSProperty_font_family:
180     case eCSSProperty_font_size:
181     case eCSSProperty_font_size_adjust:
182     case eCSSProperty_font_stretch:
183     case eCSSProperty_font_style:
184     case eCSSProperty_font_variant:
185     case eCSSProperty_font_weight:
186     case eCSSProperty_height:
187     case eCSSProperty_image_rendering:
188     case eCSSProperty_letter_spacing:
189     case eCSSProperty_lighting_color:
190     case eCSSProperty_marker:
191     case eCSSProperty_marker_end:
192     case eCSSProperty_marker_mid:
193     case eCSSProperty_marker_start:
194     case eCSSProperty_mask:
195     case eCSSProperty_mask_type:
196     case eCSSProperty_opacity:
197     case eCSSProperty_overflow:
198     case eCSSProperty_pointer_events:
199     case eCSSProperty_shape_rendering:
200     case eCSSProperty_stop_color:
201     case eCSSProperty_stop_opacity:
202     case eCSSProperty_stroke:
203     case eCSSProperty_stroke_dasharray:
204     case eCSSProperty_stroke_dashoffset:
205     case eCSSProperty_stroke_linecap:
206     case eCSSProperty_stroke_linejoin:
207     case eCSSProperty_stroke_miterlimit:
208     case eCSSProperty_stroke_opacity:
209     case eCSSProperty_stroke_width:
210     case eCSSProperty_text_anchor:
211     case eCSSProperty_text_decoration:
212     case eCSSProperty_text_decoration_line:
213     case eCSSProperty_text_rendering:
214     case eCSSProperty_vector_effect:
215     case eCSSProperty_width:
216     case eCSSProperty_visibility:
217     case eCSSProperty_word_spacing:
218       return true;
219 
220     // EXPLICITLY NON-ANIMATABLE PROPERTIES:
221     // (Some of these aren't supported at all in Gecko -- I've commented those
222     // ones out. If/when we add support for them, uncomment their line here)
223     // ----------------------------------------------------------------------
224     // case eCSSProperty_enable_background:
225     // case eCSSProperty_glyph_orientation_horizontal:
226     // case eCSSProperty_glyph_orientation_vertical:
227     // case eCSSProperty_writing_mode:
228     case eCSSProperty_direction:
229     case eCSSProperty_unicode_bidi:
230       return false;
231 
232     default:
233       return false;
234   }
235 }
236