|
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 /* Utilities for animation of computed style values */ |
|
7 |
|
8 #ifndef nsStyleAnimation_h_ |
|
9 #define nsStyleAnimation_h_ |
|
10 |
|
11 #include "nsStringFwd.h" |
|
12 #include "nsCRTGlue.h" |
|
13 #include "nsStringBuffer.h" |
|
14 #include "nsCSSProperty.h" |
|
15 #include "nsCoord.h" |
|
16 #include "nsColor.h" |
|
17 #include "nsCSSValue.h" |
|
18 |
|
19 class nsStyleContext; |
|
20 class gfx3DMatrix; |
|
21 |
|
22 namespace mozilla { |
|
23 namespace dom { |
|
24 class Element; |
|
25 } // namespace dom |
|
26 } // namespace mozilla |
|
27 |
|
28 /** |
|
29 * Utility class to handle animated style values |
|
30 */ |
|
31 class nsStyleAnimation { |
|
32 public: |
|
33 class Value; |
|
34 |
|
35 // Mathematical methods |
|
36 // -------------------- |
|
37 /** |
|
38 * Adds |aCount| copies of |aValueToAdd| to |aDest|. The result of this |
|
39 * addition is stored in aDest. |
|
40 * |
|
41 * Note that if |aCount| is 0, then |aDest| will be unchanged. Also, if |
|
42 * this method fails, then |aDest| will be unchanged. |
|
43 * |
|
44 * @param aDest The value to add to. |
|
45 * @param aValueToAdd The value to add. |
|
46 * @param aCount The number of times to add aValueToAdd. |
|
47 * @return true on success, false on failure. |
|
48 */ |
|
49 static bool Add(nsCSSProperty aProperty, Value& aDest, |
|
50 const Value& aValueToAdd, uint32_t aCount) { |
|
51 return AddWeighted(aProperty, 1.0, aDest, aCount, aValueToAdd, aDest); |
|
52 } |
|
53 |
|
54 /** |
|
55 * Calculates a measure of 'distance' between two values. |
|
56 * |
|
57 * This measure of Distance is guaranteed to be proportional to |
|
58 * portions passed to Interpolate, Add, or AddWeighted. However, for |
|
59 * some types of Value it may not produce sensible results for paced |
|
60 * animation. |
|
61 * |
|
62 * If this method succeeds, the returned distance value is guaranteed to be |
|
63 * non-negative. |
|
64 * |
|
65 * @param aStartValue The start of the interval for which the distance |
|
66 * should be calculated. |
|
67 * @param aEndValue The end of the interval for which the distance |
|
68 * should be calculated. |
|
69 * @param aDistance The result of the calculation. |
|
70 * @return true on success, false on failure. |
|
71 */ |
|
72 static bool ComputeDistance(nsCSSProperty aProperty, |
|
73 const Value& aStartValue, |
|
74 const Value& aEndValue, |
|
75 double& aDistance); |
|
76 |
|
77 /** |
|
78 * Calculates an interpolated value that is the specified |aPortion| between |
|
79 * the two given values. |
|
80 * |
|
81 * This really just does the following calculation: |
|
82 * aResultValue = (1.0 - aPortion) * aStartValue + aPortion * aEndValue |
|
83 * |
|
84 * @param aStartValue The value defining the start of the interval of |
|
85 * interpolation. |
|
86 * @param aEndValue The value defining the end of the interval of |
|
87 * interpolation. |
|
88 * @param aPortion A number in the range [0.0, 1.0] defining the |
|
89 * distance of the interpolated value in the interval. |
|
90 * @param [out] aResultValue The resulting interpolated value. |
|
91 * @return true on success, false on failure. |
|
92 */ |
|
93 static bool Interpolate(nsCSSProperty aProperty, |
|
94 const Value& aStartValue, |
|
95 const Value& aEndValue, |
|
96 double aPortion, |
|
97 Value& aResultValue) { |
|
98 return AddWeighted(aProperty, 1.0 - aPortion, aStartValue, |
|
99 aPortion, aEndValue, aResultValue); |
|
100 } |
|
101 |
|
102 /** |
|
103 * Does the calculation: |
|
104 * aResultValue = aCoeff1 * aValue1 + aCoeff2 * aValue2 |
|
105 * |
|
106 * @param [out] aResultValue The resulting interpolated value. May be |
|
107 * the same as aValue1 or aValue2. |
|
108 * @return true on success, false on failure. |
|
109 * |
|
110 * NOTE: Current callers always pass aCoeff1 and aCoeff2 >= 0. They |
|
111 * are currently permitted to be negative; however, if, as we add |
|
112 * support more value types types, we find that this causes |
|
113 * difficulty, we might change this to restrict them to being |
|
114 * positive. |
|
115 */ |
|
116 static bool AddWeighted(nsCSSProperty aProperty, |
|
117 double aCoeff1, const Value& aValue1, |
|
118 double aCoeff2, const Value& aValue2, |
|
119 Value& aResultValue); |
|
120 |
|
121 // Type-conversion methods |
|
122 // ----------------------- |
|
123 /** |
|
124 * Creates a computed value for the given specified value |
|
125 * (property ID + string). A style context is needed in case the |
|
126 * specified value depends on inherited style or on the values of other |
|
127 * properties. |
|
128 * |
|
129 * @param aProperty The property whose value we're computing. |
|
130 * @param aTargetElement The content node to which our computed value is |
|
131 * applicable. |
|
132 * @param aSpecifiedValue The specified value, from which we'll build our |
|
133 * computed value. |
|
134 * @param aUseSVGMode A flag to indicate whether we should parse |
|
135 * |aSpecifiedValue| in SVG mode. |
|
136 * @param [out] aComputedValue The resulting computed value. |
|
137 * @param [out] aIsContextSensitive |
|
138 * Set to true if |aSpecifiedValue| may produce |
|
139 * a different |aComputedValue| depending on other CSS |
|
140 * properties on |aTargetElement| or its ancestors. |
|
141 * false otherwise. |
|
142 * Note that the operation of this method is |
|
143 * significantly faster when |aIsContextSensitive| is |
|
144 * nullptr. |
|
145 * @return true on success, false on failure. |
|
146 */ |
|
147 static bool ComputeValue(nsCSSProperty aProperty, |
|
148 mozilla::dom::Element* aTargetElement, |
|
149 const nsAString& aSpecifiedValue, |
|
150 bool aUseSVGMode, |
|
151 Value& aComputedValue, |
|
152 bool* aIsContextSensitive = nullptr); |
|
153 |
|
154 /** |
|
155 * Creates a specified value for the given computed value. |
|
156 * |
|
157 * The first overload fills in an nsCSSValue object; the second |
|
158 * produces a string. The nsCSSValue result may depend on objects |
|
159 * owned by the |aComputedValue| object, so users of that variant |
|
160 * must keep |aComputedValue| alive longer than |aSpecifiedValue|. |
|
161 * |
|
162 * @param aProperty The property whose value we're uncomputing. |
|
163 * @param aComputedValue The computed value to be converted. |
|
164 * @param [out] aSpecifiedValue The resulting specified value. |
|
165 * @return true on success, false on failure. |
|
166 */ |
|
167 static bool UncomputeValue(nsCSSProperty aProperty, |
|
168 const Value& aComputedValue, |
|
169 nsCSSValue& aSpecifiedValue); |
|
170 static bool UncomputeValue(nsCSSProperty aProperty, |
|
171 const Value& aComputedValue, |
|
172 nsAString& aSpecifiedValue); |
|
173 |
|
174 /** |
|
175 * Gets the computed value for the given property from the given style |
|
176 * context. |
|
177 * |
|
178 * @param aProperty The property whose value we're looking up. |
|
179 * @param aStyleContext The style context to check for the computed value. |
|
180 * @param [out] aComputedValue The resulting computed value. |
|
181 * @return true on success, false on failure. |
|
182 */ |
|
183 static bool ExtractComputedValue(nsCSSProperty aProperty, |
|
184 nsStyleContext* aStyleContext, |
|
185 Value& aComputedValue); |
|
186 |
|
187 /** |
|
188 * Interpolates between 2 matrices by decomposing them. |
|
189 * |
|
190 * @param aMatrix1 First matrix, using CSS pixel units. |
|
191 * @param aMatrix2 Second matrix, using CSS pixel units. |
|
192 * @param aProgress Interpolation value in the range [0.0, 1.0] |
|
193 */ |
|
194 static gfx3DMatrix InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, |
|
195 const gfx3DMatrix &aMatrix2, |
|
196 double aProgress); |
|
197 |
|
198 static already_AddRefed<nsCSSValue::Array> |
|
199 AppendTransformFunction(nsCSSKeyword aTransformFunction, |
|
200 nsCSSValueList**& aListTail); |
|
201 |
|
202 /** |
|
203 * The types and values for the values that we extract and animate. |
|
204 */ |
|
205 enum Unit { |
|
206 eUnit_Null, // not initialized |
|
207 eUnit_Normal, |
|
208 eUnit_Auto, |
|
209 eUnit_None, |
|
210 eUnit_Enumerated, |
|
211 eUnit_Visibility, // special case for transitions (which converts |
|
212 // Enumerated to Visibility as needed) |
|
213 eUnit_Integer, |
|
214 eUnit_Coord, |
|
215 eUnit_Percent, |
|
216 eUnit_Float, |
|
217 eUnit_Color, |
|
218 eUnit_Calc, // nsCSSValue* (never null), always with a single |
|
219 // calc() expression that's either length or length+percent |
|
220 eUnit_CSSValuePair, // nsCSSValuePair* (never null) |
|
221 eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null) |
|
222 eUnit_CSSRect, // nsCSSRect* (never null) |
|
223 eUnit_Dasharray, // nsCSSValueList* (never null) |
|
224 eUnit_Filter, // nsCSSValueList* (may be null) |
|
225 eUnit_Shadow, // nsCSSValueList* (may be null) |
|
226 eUnit_Transform, // nsCSSValueList* (never null) |
|
227 eUnit_BackgroundPosition, // nsCSSValueList* (never null) |
|
228 eUnit_CSSValuePairList, // nsCSSValuePairList* (never null) |
|
229 eUnit_UnparsedString // nsStringBuffer* (never null) |
|
230 }; |
|
231 |
|
232 class Value { |
|
233 private: |
|
234 Unit mUnit; |
|
235 union { |
|
236 int32_t mInt; |
|
237 nscoord mCoord; |
|
238 float mFloat; |
|
239 nscolor mColor; |
|
240 nsCSSValue* mCSSValue; |
|
241 nsCSSValuePair* mCSSValuePair; |
|
242 nsCSSValueTriplet* mCSSValueTriplet; |
|
243 nsCSSRect* mCSSRect; |
|
244 nsCSSValueList* mCSSValueList; |
|
245 nsCSSValueSharedList* mCSSValueSharedList; |
|
246 nsCSSValuePairList* mCSSValuePairList; |
|
247 nsStringBuffer* mString; |
|
248 } mValue; |
|
249 public: |
|
250 Unit GetUnit() const { |
|
251 NS_ASSERTION(mUnit != eUnit_Null, "uninitialized"); |
|
252 return mUnit; |
|
253 } |
|
254 |
|
255 // Accessor to let us verify assumptions about presence of null unit, |
|
256 // without tripping the assertion in GetUnit(). |
|
257 bool IsNull() const { |
|
258 return mUnit == eUnit_Null; |
|
259 } |
|
260 |
|
261 int32_t GetIntValue() const { |
|
262 NS_ASSERTION(IsIntUnit(mUnit), "unit mismatch"); |
|
263 return mValue.mInt; |
|
264 } |
|
265 nscoord GetCoordValue() const { |
|
266 NS_ASSERTION(mUnit == eUnit_Coord, "unit mismatch"); |
|
267 return mValue.mCoord; |
|
268 } |
|
269 float GetPercentValue() const { |
|
270 NS_ASSERTION(mUnit == eUnit_Percent, "unit mismatch"); |
|
271 return mValue.mFloat; |
|
272 } |
|
273 float GetFloatValue() const { |
|
274 NS_ASSERTION(mUnit == eUnit_Float, "unit mismatch"); |
|
275 return mValue.mFloat; |
|
276 } |
|
277 nscolor GetColorValue() const { |
|
278 NS_ASSERTION(mUnit == eUnit_Color, "unit mismatch"); |
|
279 return mValue.mColor; |
|
280 } |
|
281 nsCSSValue* GetCSSValueValue() const { |
|
282 NS_ASSERTION(IsCSSValueUnit(mUnit), "unit mismatch"); |
|
283 return mValue.mCSSValue; |
|
284 } |
|
285 nsCSSValuePair* GetCSSValuePairValue() const { |
|
286 NS_ASSERTION(IsCSSValuePairUnit(mUnit), "unit mismatch"); |
|
287 return mValue.mCSSValuePair; |
|
288 } |
|
289 nsCSSValueTriplet* GetCSSValueTripletValue() const { |
|
290 NS_ASSERTION(IsCSSValueTripletUnit(mUnit), "unit mismatch"); |
|
291 return mValue.mCSSValueTriplet; |
|
292 } |
|
293 nsCSSRect* GetCSSRectValue() const { |
|
294 NS_ASSERTION(IsCSSRectUnit(mUnit), "unit mismatch"); |
|
295 return mValue.mCSSRect; |
|
296 } |
|
297 nsCSSValueList* GetCSSValueListValue() const { |
|
298 NS_ASSERTION(IsCSSValueListUnit(mUnit), "unit mismatch"); |
|
299 return mValue.mCSSValueList; |
|
300 } |
|
301 nsCSSValueSharedList* GetCSSValueSharedListValue() const { |
|
302 NS_ASSERTION(IsCSSValueSharedListValue(mUnit), "unit mismatch"); |
|
303 return mValue.mCSSValueSharedList; |
|
304 } |
|
305 nsCSSValuePairList* GetCSSValuePairListValue() const { |
|
306 NS_ASSERTION(IsCSSValuePairListUnit(mUnit), "unit mismatch"); |
|
307 return mValue.mCSSValuePairList; |
|
308 } |
|
309 const char16_t* GetStringBufferValue() const { |
|
310 NS_ASSERTION(IsStringUnit(mUnit), "unit mismatch"); |
|
311 return GetBufferValue(mValue.mString); |
|
312 } |
|
313 |
|
314 void GetStringValue(nsAString& aBuffer) const { |
|
315 NS_ASSERTION(IsStringUnit(mUnit), "unit mismatch"); |
|
316 aBuffer.Truncate(); |
|
317 uint32_t len = NS_strlen(GetBufferValue(mValue.mString)); |
|
318 mValue.mString->ToString(len, aBuffer); |
|
319 } |
|
320 |
|
321 explicit Value(Unit aUnit = eUnit_Null) : mUnit(aUnit) { |
|
322 NS_ASSERTION(aUnit == eUnit_Null || aUnit == eUnit_Normal || |
|
323 aUnit == eUnit_Auto || aUnit == eUnit_None, |
|
324 "must be valueless unit"); |
|
325 } |
|
326 Value(const Value& aOther) : mUnit(eUnit_Null) { *this = aOther; } |
|
327 enum IntegerConstructorType { IntegerConstructor }; |
|
328 Value(int32_t aInt, Unit aUnit, IntegerConstructorType); |
|
329 enum CoordConstructorType { CoordConstructor }; |
|
330 Value(nscoord aLength, CoordConstructorType); |
|
331 enum PercentConstructorType { PercentConstructor }; |
|
332 Value(float aPercent, PercentConstructorType); |
|
333 enum FloatConstructorType { FloatConstructor }; |
|
334 Value(float aFloat, FloatConstructorType); |
|
335 enum ColorConstructorType { ColorConstructor }; |
|
336 Value(nscolor aColor, ColorConstructorType); |
|
337 |
|
338 ~Value() { FreeValue(); } |
|
339 |
|
340 void SetNormalValue(); |
|
341 void SetAutoValue(); |
|
342 void SetNoneValue(); |
|
343 void SetIntValue(int32_t aInt, Unit aUnit); |
|
344 void SetCoordValue(nscoord aCoord); |
|
345 void SetPercentValue(float aPercent); |
|
346 void SetFloatValue(float aFloat); |
|
347 void SetColorValue(nscolor aColor); |
|
348 void SetUnparsedStringValue(const nsString& aString); |
|
349 |
|
350 // These setters take ownership of |aValue|, and are therefore named |
|
351 // "SetAndAdopt*". |
|
352 void SetAndAdoptCSSValueValue(nsCSSValue *aValue, Unit aUnit); |
|
353 void SetAndAdoptCSSValuePairValue(nsCSSValuePair *aValue, Unit aUnit); |
|
354 void SetAndAdoptCSSValueTripletValue(nsCSSValueTriplet *aValue, Unit aUnit); |
|
355 void SetAndAdoptCSSRectValue(nsCSSRect *aValue, Unit aUnit); |
|
356 void SetAndAdoptCSSValueListValue(nsCSSValueList *aValue, Unit aUnit); |
|
357 void SetAndAdoptCSSValuePairListValue(nsCSSValuePairList *aValue); |
|
358 |
|
359 void SetTransformValue(nsCSSValueSharedList* aList); |
|
360 |
|
361 Value& operator=(const Value& aOther); |
|
362 |
|
363 bool operator==(const Value& aOther) const; |
|
364 bool operator!=(const Value& aOther) const |
|
365 { return !(*this == aOther); } |
|
366 |
|
367 private: |
|
368 void FreeValue(); |
|
369 |
|
370 static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) { |
|
371 return static_cast<char16_t*>(aBuffer->Data()); |
|
372 } |
|
373 |
|
374 static bool IsIntUnit(Unit aUnit) { |
|
375 return aUnit == eUnit_Enumerated || aUnit == eUnit_Visibility || |
|
376 aUnit == eUnit_Integer; |
|
377 } |
|
378 static bool IsCSSValueUnit(Unit aUnit) { |
|
379 return aUnit == eUnit_Calc; |
|
380 } |
|
381 static bool IsCSSValuePairUnit(Unit aUnit) { |
|
382 return aUnit == eUnit_CSSValuePair; |
|
383 } |
|
384 static bool IsCSSValueTripletUnit(Unit aUnit) { |
|
385 return aUnit == eUnit_CSSValueTriplet; |
|
386 } |
|
387 static bool IsCSSRectUnit(Unit aUnit) { |
|
388 return aUnit == eUnit_CSSRect; |
|
389 } |
|
390 static bool IsCSSValueListUnit(Unit aUnit) { |
|
391 return aUnit == eUnit_Dasharray || aUnit == eUnit_Filter || |
|
392 aUnit == eUnit_Shadow || |
|
393 aUnit == eUnit_BackgroundPosition; |
|
394 } |
|
395 static bool IsCSSValueSharedListValue(Unit aUnit) { |
|
396 return aUnit == eUnit_Transform; |
|
397 } |
|
398 static bool IsCSSValuePairListUnit(Unit aUnit) { |
|
399 return aUnit == eUnit_CSSValuePairList; |
|
400 } |
|
401 static bool IsStringUnit(Unit aUnit) { |
|
402 return aUnit == eUnit_UnparsedString; |
|
403 } |
|
404 }; |
|
405 }; |
|
406 |
|
407 #endif |