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