|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* representation of a SMIL-animatable CSS property on an element */ |
|
7 |
|
8 #include "nsSMILCSSProperty.h" |
|
9 #include "nsSMILCSSValueType.h" |
|
10 #include "nsSMILValue.h" |
|
11 #include "nsComputedDOMStyle.h" |
|
12 #include "nsCSSProps.h" |
|
13 #include "nsStyleAnimation.h" |
|
14 #include "mozilla/dom/Element.h" |
|
15 #include "nsIDOMElement.h" |
|
16 #include "nsIDocument.h" |
|
17 |
|
18 using namespace mozilla::dom; |
|
19 |
|
20 // Helper function |
|
21 static bool |
|
22 GetCSSComputedValue(Element* aElem, |
|
23 nsCSSProperty aPropID, |
|
24 nsAString& aResult) |
|
25 { |
|
26 NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aPropID), |
|
27 "Can't look up computed value of shorthand property"); |
|
28 NS_ABORT_IF_FALSE(nsSMILCSSProperty::IsPropertyAnimatable(aPropID), |
|
29 "Shouldn't get here for non-animatable properties"); |
|
30 |
|
31 nsIDocument* doc = aElem->GetCurrentDoc(); |
|
32 if (!doc) { |
|
33 // This can happen if we process certain types of restyles mid-sample |
|
34 // and remove anonymous animated content from the document as a result. |
|
35 // See bug 534975. |
|
36 return false; |
|
37 } |
|
38 |
|
39 nsIPresShell* shell = doc->GetShell(); |
|
40 if (!shell) { |
|
41 NS_WARNING("Unable to look up computed style -- no pres shell"); |
|
42 return false; |
|
43 } |
|
44 |
|
45 nsRefPtr<nsComputedDOMStyle> computedStyle = |
|
46 NS_NewComputedDOMStyle(aElem, EmptyString(), shell); |
|
47 |
|
48 computedStyle->GetPropertyValue(aPropID, aResult); |
|
49 return true; |
|
50 } |
|
51 |
|
52 // Class Methods |
|
53 nsSMILCSSProperty::nsSMILCSSProperty(nsCSSProperty aPropID, |
|
54 Element* aElement) |
|
55 : mPropID(aPropID), mElement(aElement) |
|
56 { |
|
57 NS_ABORT_IF_FALSE(IsPropertyAnimatable(mPropID), |
|
58 "Creating a nsSMILCSSProperty for a property " |
|
59 "that's not supported for animation"); |
|
60 } |
|
61 |
|
62 nsSMILValue |
|
63 nsSMILCSSProperty::GetBaseValue() const |
|
64 { |
|
65 // To benefit from Return Value Optimization and avoid copy constructor calls |
|
66 // due to our use of return-by-value, we must return the exact same object |
|
67 // from ALL return points. This function must only return THIS variable: |
|
68 nsSMILValue baseValue; |
|
69 |
|
70 // SPECIAL CASE: (a) Shorthands |
|
71 // (b) 'display' |
|
72 if (nsCSSProps::IsShorthand(mPropID) || mPropID == eCSSProperty_display) { |
|
73 // We can't look up the base (computed-style) value of shorthand |
|
74 // properties because they aren't guaranteed to have a consistent computed |
|
75 // value. |
|
76 // |
|
77 // Also, although we can look up the base value of the display property, |
|
78 // doing so involves clearing and resetting the property which can cause |
|
79 // frames to be recreated which we'd like to avoid. |
|
80 // |
|
81 // In either case, just return a dummy value (initialized with the right |
|
82 // type, so as not to indicate failure). |
|
83 nsSMILValue tmpVal(&nsSMILCSSValueType::sSingleton); |
|
84 baseValue.Swap(tmpVal); |
|
85 return baseValue; |
|
86 } |
|
87 |
|
88 // GENERAL CASE: Non-Shorthands |
|
89 // (1) Put empty string in override style for property mPropID |
|
90 // (saving old override style value, so we can set it again when we're done) |
|
91 nsICSSDeclaration* overrideDecl = mElement->GetSMILOverrideStyle(); |
|
92 nsAutoString cachedOverrideStyleVal; |
|
93 if (overrideDecl) { |
|
94 overrideDecl->GetPropertyValue(mPropID, cachedOverrideStyleVal); |
|
95 // (Don't bother clearing override style if it's already empty) |
|
96 if (!cachedOverrideStyleVal.IsEmpty()) { |
|
97 overrideDecl->SetPropertyValue(mPropID, EmptyString()); |
|
98 } |
|
99 } |
|
100 |
|
101 // (2) Get Computed Style |
|
102 nsAutoString computedStyleVal; |
|
103 bool didGetComputedVal = GetCSSComputedValue(mElement, mPropID, |
|
104 computedStyleVal); |
|
105 |
|
106 // (3) Put cached override style back (if it's non-empty) |
|
107 if (overrideDecl && !cachedOverrideStyleVal.IsEmpty()) { |
|
108 overrideDecl->SetPropertyValue(mPropID, cachedOverrideStyleVal); |
|
109 } |
|
110 |
|
111 // (4) Populate our nsSMILValue from the computed style |
|
112 if (didGetComputedVal) { |
|
113 // When we parse animation values we check if they are context-sensitive or |
|
114 // not so that we don't cache animation values whose meaning may change. |
|
115 // For base values however this is unnecessary since on each sample the |
|
116 // compositor will fetch the (computed) base value and compare it against |
|
117 // the cached (computed) value and detect changes for us. |
|
118 nsSMILCSSValueType::ValueFromString(mPropID, mElement, |
|
119 computedStyleVal, baseValue, |
|
120 nullptr); |
|
121 } |
|
122 return baseValue; |
|
123 } |
|
124 |
|
125 nsresult |
|
126 nsSMILCSSProperty::ValueFromString(const nsAString& aStr, |
|
127 const SVGAnimationElement* aSrcElement, |
|
128 nsSMILValue& aValue, |
|
129 bool& aPreventCachingOfSandwich) const |
|
130 { |
|
131 NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); |
|
132 |
|
133 nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue, |
|
134 &aPreventCachingOfSandwich); |
|
135 |
|
136 if (aValue.IsNull()) { |
|
137 return NS_ERROR_FAILURE; |
|
138 } |
|
139 |
|
140 // XXX Due to bug 536660 (or at least that seems to be the most likely |
|
141 // culprit), when we have animation setting display:none on a <use> element, |
|
142 // if we DON'T set the property every sample, chaos ensues. |
|
143 if (!aPreventCachingOfSandwich && mPropID == eCSSProperty_display) { |
|
144 aPreventCachingOfSandwich = true; |
|
145 } |
|
146 return NS_OK; |
|
147 } |
|
148 |
|
149 nsresult |
|
150 nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue) |
|
151 { |
|
152 NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); |
|
153 |
|
154 // Convert nsSMILValue to string |
|
155 nsAutoString valStr; |
|
156 if (!nsSMILCSSValueType::ValueToString(aValue, valStr)) { |
|
157 NS_WARNING("Failed to convert nsSMILValue for CSS property into a string"); |
|
158 return NS_ERROR_FAILURE; |
|
159 } |
|
160 |
|
161 // Use string value to style the target element |
|
162 nsICSSDeclaration* overrideDecl = mElement->GetSMILOverrideStyle(); |
|
163 if (overrideDecl) { |
|
164 nsAutoString oldValStr; |
|
165 overrideDecl->GetPropertyValue(mPropID, oldValStr); |
|
166 if (valStr.Equals(oldValStr)) { |
|
167 return NS_OK; |
|
168 } |
|
169 overrideDecl->SetPropertyValue(mPropID, valStr); |
|
170 } |
|
171 return NS_OK; |
|
172 } |
|
173 |
|
174 void |
|
175 nsSMILCSSProperty::ClearAnimValue() |
|
176 { |
|
177 // Put empty string in override style for our property |
|
178 nsICSSDeclaration* overrideDecl = mElement->GetSMILOverrideStyle(); |
|
179 if (overrideDecl) { |
|
180 overrideDecl->SetPropertyValue(mPropID, EmptyString()); |
|
181 } |
|
182 } |
|
183 |
|
184 // Based on http://www.w3.org/TR/SVG/propidx.html |
|
185 // static |
|
186 bool |
|
187 nsSMILCSSProperty::IsPropertyAnimatable(nsCSSProperty aPropID) |
|
188 { |
|
189 // NOTE: Right now, Gecko doesn't recognize the following properties from |
|
190 // the SVG Property Index: |
|
191 // alignment-baseline |
|
192 // baseline-shift |
|
193 // color-profile |
|
194 // color-rendering |
|
195 // glyph-orientation-horizontal |
|
196 // glyph-orientation-vertical |
|
197 // kerning |
|
198 // writing-mode |
|
199 |
|
200 switch (aPropID) { |
|
201 case eCSSProperty_clip: |
|
202 case eCSSProperty_clip_rule: |
|
203 case eCSSProperty_clip_path: |
|
204 case eCSSProperty_color: |
|
205 case eCSSProperty_color_interpolation: |
|
206 case eCSSProperty_color_interpolation_filters: |
|
207 case eCSSProperty_cursor: |
|
208 case eCSSProperty_display: |
|
209 case eCSSProperty_dominant_baseline: |
|
210 case eCSSProperty_fill: |
|
211 case eCSSProperty_fill_opacity: |
|
212 case eCSSProperty_fill_rule: |
|
213 case eCSSProperty_filter: |
|
214 case eCSSProperty_flood_color: |
|
215 case eCSSProperty_flood_opacity: |
|
216 case eCSSProperty_font: |
|
217 case eCSSProperty_font_family: |
|
218 case eCSSProperty_font_size: |
|
219 case eCSSProperty_font_size_adjust: |
|
220 case eCSSProperty_font_stretch: |
|
221 case eCSSProperty_font_style: |
|
222 case eCSSProperty_font_variant: |
|
223 case eCSSProperty_font_weight: |
|
224 case eCSSProperty_height: |
|
225 case eCSSProperty_image_rendering: |
|
226 case eCSSProperty_letter_spacing: |
|
227 case eCSSProperty_lighting_color: |
|
228 case eCSSProperty_marker: |
|
229 case eCSSProperty_marker_end: |
|
230 case eCSSProperty_marker_mid: |
|
231 case eCSSProperty_marker_start: |
|
232 case eCSSProperty_mask: |
|
233 case eCSSProperty_mask_type: |
|
234 case eCSSProperty_opacity: |
|
235 case eCSSProperty_overflow: |
|
236 case eCSSProperty_pointer_events: |
|
237 case eCSSProperty_shape_rendering: |
|
238 case eCSSProperty_stop_color: |
|
239 case eCSSProperty_stop_opacity: |
|
240 case eCSSProperty_stroke: |
|
241 case eCSSProperty_stroke_dasharray: |
|
242 case eCSSProperty_stroke_dashoffset: |
|
243 case eCSSProperty_stroke_linecap: |
|
244 case eCSSProperty_stroke_linejoin: |
|
245 case eCSSProperty_stroke_miterlimit: |
|
246 case eCSSProperty_stroke_opacity: |
|
247 case eCSSProperty_stroke_width: |
|
248 case eCSSProperty_text_anchor: |
|
249 case eCSSProperty_text_decoration: |
|
250 case eCSSProperty_text_decoration_line: |
|
251 case eCSSProperty_text_rendering: |
|
252 case eCSSProperty_vector_effect: |
|
253 case eCSSProperty_width: |
|
254 case eCSSProperty_visibility: |
|
255 case eCSSProperty_word_spacing: |
|
256 return true; |
|
257 |
|
258 // EXPLICITLY NON-ANIMATABLE PROPERTIES: |
|
259 // (Some of these aren't supported at all in Gecko -- I've commented those |
|
260 // ones out. If/when we add support for them, uncomment their line here) |
|
261 // ---------------------------------------------------------------------- |
|
262 // case eCSSProperty_enable_background: |
|
263 // case eCSSProperty_glyph_orientation_horizontal: |
|
264 // case eCSSProperty_glyph_orientation_vertical: |
|
265 // case eCSSProperty_writing_mode: |
|
266 case eCSSProperty_direction: |
|
267 case eCSSProperty_unicode_bidi: |
|
268 return false; |
|
269 |
|
270 default: |
|
271 return false; |
|
272 } |
|
273 } |