1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsStyleAnimation.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,3832 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* Utilities for animation of computed style values */ 1.10 + 1.11 +#include "mozilla/ArrayUtils.h" 1.12 +#include "mozilla/MathAlgorithms.h" 1.13 + 1.14 +#include "nsStyleAnimation.h" 1.15 +#include "nsStyleTransformMatrix.h" 1.16 +#include "nsCOMArray.h" 1.17 +#include "nsIStyleRule.h" 1.18 +#include "mozilla/css/StyleRule.h" 1.19 +#include "nsString.h" 1.20 +#include "nsStyleContext.h" 1.21 +#include "nsStyleSet.h" 1.22 +#include "nsComputedDOMStyle.h" 1.23 +#include "nsCSSParser.h" 1.24 +#include "mozilla/css/Declaration.h" 1.25 +#include "mozilla/dom/Element.h" 1.26 +#include "mozilla/FloatingPoint.h" 1.27 +#include "mozilla/Likely.h" 1.28 +#include "gfxMatrix.h" 1.29 +#include "gfxQuaternion.h" 1.30 +#include "nsIDocument.h" 1.31 + 1.32 +using namespace mozilla; 1.33 + 1.34 +// HELPER METHODS 1.35 +// -------------- 1.36 +/* 1.37 + * Given two units, this method returns a common unit that they can both be 1.38 + * converted into, if possible. This is intended to facilitate 1.39 + * interpolation, distance-computation, and addition between "similar" units. 1.40 + * 1.41 + * The ordering of the arguments should not affect the output of this method. 1.42 + * 1.43 + * If there's no sensible common unit, this method returns eUnit_Null. 1.44 + * 1.45 + * @param aFirstUnit One unit to resolve. 1.46 + * @param aFirstUnit The other unit to resolve. 1.47 + * @return A "common" unit that both source units can be converted into, or 1.48 + * eUnit_Null if that's not possible. 1.49 + */ 1.50 +static 1.51 +nsStyleAnimation::Unit 1.52 +GetCommonUnit(nsCSSProperty aProperty, 1.53 + nsStyleAnimation::Unit aFirstUnit, 1.54 + nsStyleAnimation::Unit aSecondUnit) 1.55 +{ 1.56 + if (aFirstUnit != aSecondUnit) { 1.57 + if (nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_STORES_CALC) && 1.58 + (aFirstUnit == nsStyleAnimation::eUnit_Coord || 1.59 + aFirstUnit == nsStyleAnimation::eUnit_Percent || 1.60 + aFirstUnit == nsStyleAnimation::eUnit_Calc) && 1.61 + (aSecondUnit == nsStyleAnimation::eUnit_Coord || 1.62 + aSecondUnit == nsStyleAnimation::eUnit_Percent || 1.63 + aSecondUnit == nsStyleAnimation::eUnit_Calc)) { 1.64 + // We can use calc() as the common unit. 1.65 + return nsStyleAnimation::eUnit_Calc; 1.66 + } 1.67 + return nsStyleAnimation::eUnit_Null; 1.68 + } 1.69 + return aFirstUnit; 1.70 +} 1.71 + 1.72 +static 1.73 +nsCSSUnit 1.74 +GetCommonUnit(nsCSSProperty aProperty, 1.75 + nsCSSUnit aFirstUnit, 1.76 + nsCSSUnit aSecondUnit) 1.77 +{ 1.78 + if (aFirstUnit != aSecondUnit) { 1.79 + if (nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_STORES_CALC) && 1.80 + (aFirstUnit == eCSSUnit_Pixel || 1.81 + aFirstUnit == eCSSUnit_Percent || 1.82 + aFirstUnit == eCSSUnit_Calc) && 1.83 + (aSecondUnit == eCSSUnit_Pixel || 1.84 + aSecondUnit == eCSSUnit_Percent || 1.85 + aSecondUnit == eCSSUnit_Calc)) { 1.86 + // We can use calc() as the common unit. 1.87 + return eCSSUnit_Calc; 1.88 + } 1.89 + return eCSSUnit_Null; 1.90 + } 1.91 + return aFirstUnit; 1.92 +} 1.93 + 1.94 +static nsCSSKeyword 1.95 +ToPrimitive(nsCSSKeyword aKeyword) 1.96 +{ 1.97 + switch (aKeyword) { 1.98 + case eCSSKeyword_translatex: 1.99 + case eCSSKeyword_translatey: 1.100 + case eCSSKeyword_translatez: 1.101 + case eCSSKeyword_translate: 1.102 + return eCSSKeyword_translate3d; 1.103 + case eCSSKeyword_scalex: 1.104 + case eCSSKeyword_scaley: 1.105 + case eCSSKeyword_scalez: 1.106 + case eCSSKeyword_scale: 1.107 + return eCSSKeyword_scale3d; 1.108 + default: 1.109 + return aKeyword; 1.110 + } 1.111 +} 1.112 + 1.113 +static already_AddRefed<nsCSSValue::Array> 1.114 +AppendFunction(nsCSSKeyword aTransformFunction) 1.115 +{ 1.116 + uint32_t nargs; 1.117 + switch (aTransformFunction) { 1.118 + case eCSSKeyword_matrix3d: 1.119 + nargs = 16; 1.120 + break; 1.121 + case eCSSKeyword_matrix: 1.122 + nargs = 6; 1.123 + break; 1.124 + case eCSSKeyword_rotate3d: 1.125 + nargs = 4; 1.126 + break; 1.127 + case eCSSKeyword_interpolatematrix: 1.128 + case eCSSKeyword_translate3d: 1.129 + case eCSSKeyword_scale3d: 1.130 + nargs = 3; 1.131 + break; 1.132 + case eCSSKeyword_translate: 1.133 + case eCSSKeyword_skew: 1.134 + case eCSSKeyword_scale: 1.135 + nargs = 2; 1.136 + break; 1.137 + default: 1.138 + NS_ERROR("must be a transform function"); 1.139 + case eCSSKeyword_translatex: 1.140 + case eCSSKeyword_translatey: 1.141 + case eCSSKeyword_translatez: 1.142 + case eCSSKeyword_scalex: 1.143 + case eCSSKeyword_scaley: 1.144 + case eCSSKeyword_scalez: 1.145 + case eCSSKeyword_skewx: 1.146 + case eCSSKeyword_skewy: 1.147 + case eCSSKeyword_rotate: 1.148 + case eCSSKeyword_rotatex: 1.149 + case eCSSKeyword_rotatey: 1.150 + case eCSSKeyword_rotatez: 1.151 + case eCSSKeyword_perspective: 1.152 + nargs = 1; 1.153 + break; 1.154 + } 1.155 + 1.156 + nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(nargs + 1); 1.157 + arr->Item(0).SetIntValue(aTransformFunction, eCSSUnit_Enumerated); 1.158 + 1.159 + return arr.forget(); 1.160 +} 1.161 + 1.162 +static already_AddRefed<nsCSSValue::Array> 1.163 +ToPrimitive(nsCSSValue::Array* aArray) 1.164 +{ 1.165 + nsCSSKeyword tfunc = nsStyleTransformMatrix::TransformFunctionOf(aArray); 1.166 + nsCSSKeyword primitive = ToPrimitive(tfunc); 1.167 + nsRefPtr<nsCSSValue::Array> arr = AppendFunction(primitive); 1.168 + 1.169 + // FIXME: This would produce fewer calc() expressions if the 1.170 + // zero were of compatible type (length vs. percent) when 1.171 + // needed. 1.172 + 1.173 + nsCSSValue zero(0.0f, eCSSUnit_Pixel); 1.174 + nsCSSValue one(1.0f, eCSSUnit_Number); 1.175 + switch(tfunc) { 1.176 + case eCSSKeyword_translate: 1.177 + { 1.178 + NS_ABORT_IF_FALSE(aArray->Count() == 2 || aArray->Count() == 3, 1.179 + "unexpected count"); 1.180 + arr->Item(1) = aArray->Item(1); 1.181 + arr->Item(2) = aArray->Count() == 3 ? aArray->Item(2) : zero; 1.182 + arr->Item(3) = zero; 1.183 + break; 1.184 + } 1.185 + case eCSSKeyword_translatex: 1.186 + { 1.187 + NS_ABORT_IF_FALSE(aArray->Count() == 2, "unexpected count"); 1.188 + arr->Item(1) = aArray->Item(1); 1.189 + arr->Item(2) = zero; 1.190 + arr->Item(3) = zero; 1.191 + break; 1.192 + } 1.193 + case eCSSKeyword_translatey: 1.194 + { 1.195 + NS_ABORT_IF_FALSE(aArray->Count() == 2, "unexpected count"); 1.196 + arr->Item(1) = zero; 1.197 + arr->Item(2) = aArray->Item(1); 1.198 + arr->Item(3) = zero; 1.199 + break; 1.200 + } 1.201 + case eCSSKeyword_translatez: 1.202 + { 1.203 + NS_ABORT_IF_FALSE(aArray->Count() == 2, "unexpected count"); 1.204 + arr->Item(1) = zero; 1.205 + arr->Item(2) = zero; 1.206 + arr->Item(3) = aArray->Item(1); 1.207 + break; 1.208 + } 1.209 + case eCSSKeyword_scale: 1.210 + { 1.211 + NS_ABORT_IF_FALSE(aArray->Count() == 2 || aArray->Count() == 3, 1.212 + "unexpected count"); 1.213 + arr->Item(1) = aArray->Item(1); 1.214 + arr->Item(2) = aArray->Count() == 3 ? aArray->Item(2) : aArray->Item(1); 1.215 + arr->Item(3) = one; 1.216 + break; 1.217 + } 1.218 + case eCSSKeyword_scalex: 1.219 + { 1.220 + NS_ABORT_IF_FALSE(aArray->Count() == 2, "unexpected count"); 1.221 + arr->Item(1) = aArray->Item(1); 1.222 + arr->Item(2) = one; 1.223 + arr->Item(3) = one; 1.224 + break; 1.225 + } 1.226 + case eCSSKeyword_scaley: 1.227 + { 1.228 + NS_ABORT_IF_FALSE(aArray->Count() == 2, "unexpected count"); 1.229 + arr->Item(1) = one; 1.230 + arr->Item(2) = aArray->Item(1); 1.231 + arr->Item(3) = one; 1.232 + break; 1.233 + } 1.234 + case eCSSKeyword_scalez: 1.235 + { 1.236 + NS_ABORT_IF_FALSE(aArray->Count() == 2, "unexpected count"); 1.237 + arr->Item(1) = one; 1.238 + arr->Item(2) = one; 1.239 + arr->Item(3) = aArray->Item(1); 1.240 + break; 1.241 + } 1.242 + default: 1.243 + arr = aArray; 1.244 + } 1.245 + return arr.forget(); 1.246 +} 1.247 + 1.248 +inline void 1.249 +nscoordToCSSValue(nscoord aCoord, nsCSSValue& aCSSValue) 1.250 +{ 1.251 + aCSSValue.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(aCoord), 1.252 + eCSSUnit_Pixel); 1.253 +} 1.254 + 1.255 +static void 1.256 +AppendCSSShadowValue(const nsCSSShadowItem *aShadow, 1.257 + nsCSSValueList **&aResultTail) 1.258 +{ 1.259 + NS_ABORT_IF_FALSE(aShadow, "shadow expected"); 1.260 + 1.261 + // X, Y, Radius, Spread, Color, Inset 1.262 + nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(6); 1.263 + nscoordToCSSValue(aShadow->mXOffset, arr->Item(0)); 1.264 + nscoordToCSSValue(aShadow->mYOffset, arr->Item(1)); 1.265 + nscoordToCSSValue(aShadow->mRadius, arr->Item(2)); 1.266 + // NOTE: This code sometimes stores mSpread: 0 even when 1.267 + // the parser would be required to leave it null. 1.268 + nscoordToCSSValue(aShadow->mSpread, arr->Item(3)); 1.269 + if (aShadow->mHasColor) { 1.270 + arr->Item(4).SetColorValue(aShadow->mColor); 1.271 + } 1.272 + if (aShadow->mInset) { 1.273 + arr->Item(5).SetIntValue(NS_STYLE_BOX_SHADOW_INSET, 1.274 + eCSSUnit_Enumerated); 1.275 + } 1.276 + 1.277 + nsCSSValueList *resultItem = new nsCSSValueList; 1.278 + resultItem->mValue.SetArrayValue(arr, eCSSUnit_Array); 1.279 + *aResultTail = resultItem; 1.280 + aResultTail = &resultItem->mNext; 1.281 +} 1.282 + 1.283 +// Like nsStyleCoord::Calc, but with length in float pixels instead of nscoord. 1.284 +struct CalcValue { 1.285 + float mLength, mPercent; 1.286 + bool mHasPercent; 1.287 +}; 1.288 + 1.289 +// Requires a canonical calc() value that we generated. 1.290 +static CalcValue 1.291 +ExtractCalcValueInternal(const nsCSSValue& aValue) 1.292 +{ 1.293 + NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Calc, "unexpected unit"); 1.294 + nsCSSValue::Array *arr = aValue.GetArrayValue(); 1.295 + NS_ABORT_IF_FALSE(arr->Count() == 1, "unexpected length"); 1.296 + 1.297 + const nsCSSValue &topval = arr->Item(0); 1.298 + CalcValue result; 1.299 + if (topval.GetUnit() == eCSSUnit_Pixel) { 1.300 + result.mLength = topval.GetFloatValue(); 1.301 + result.mPercent = 0.0f; 1.302 + result.mHasPercent = false; 1.303 + } else { 1.304 + NS_ABORT_IF_FALSE(topval.GetUnit() == eCSSUnit_Calc_Plus, 1.305 + "unexpected unit"); 1.306 + nsCSSValue::Array *arr2 = topval.GetArrayValue(); 1.307 + const nsCSSValue &len = arr2->Item(0); 1.308 + const nsCSSValue &pct = arr2->Item(1); 1.309 + NS_ABORT_IF_FALSE(len.GetUnit() == eCSSUnit_Pixel, "unexpected unit"); 1.310 + NS_ABORT_IF_FALSE(pct.GetUnit() == eCSSUnit_Percent, "unexpected unit"); 1.311 + result.mLength = len.GetFloatValue(); 1.312 + result.mPercent = pct.GetPercentValue(); 1.313 + result.mHasPercent = true; 1.314 + } 1.315 + 1.316 + return result; 1.317 +} 1.318 + 1.319 +// Requires a canonical calc() value that we generated. 1.320 +static CalcValue 1.321 +ExtractCalcValue(const nsStyleAnimation::Value& aValue) 1.322 +{ 1.323 + CalcValue result; 1.324 + if (aValue.GetUnit() == nsStyleAnimation::eUnit_Coord) { 1.325 + result.mLength = 1.326 + nsPresContext::AppUnitsToFloatCSSPixels(aValue.GetCoordValue()); 1.327 + result.mPercent = 0.0f; 1.328 + result.mHasPercent = false; 1.329 + return result; 1.330 + } 1.331 + if (aValue.GetUnit() == nsStyleAnimation::eUnit_Percent) { 1.332 + result.mLength = 0.0f; 1.333 + result.mPercent = aValue.GetPercentValue(); 1.334 + result.mHasPercent = true; 1.335 + return result; 1.336 + } 1.337 + NS_ABORT_IF_FALSE(aValue.GetUnit() == nsStyleAnimation::eUnit_Calc, 1.338 + "unexpected unit"); 1.339 + nsCSSValue *val = aValue.GetCSSValueValue(); 1.340 + return ExtractCalcValueInternal(*val); 1.341 +} 1.342 + 1.343 +static CalcValue 1.344 +ExtractCalcValue(const nsCSSValue& aValue) 1.345 +{ 1.346 + CalcValue result; 1.347 + if (aValue.GetUnit() == eCSSUnit_Pixel) { 1.348 + result.mLength = aValue.GetFloatValue(); 1.349 + result.mPercent = 0.0f; 1.350 + result.mHasPercent = false; 1.351 + return result; 1.352 + } 1.353 + if (aValue.GetUnit() == eCSSUnit_Percent) { 1.354 + result.mLength = 0.0f; 1.355 + result.mPercent = aValue.GetPercentValue(); 1.356 + result.mHasPercent = true; 1.357 + return result; 1.358 + } 1.359 + return ExtractCalcValueInternal(aValue); 1.360 +} 1.361 + 1.362 +static void 1.363 +SetCalcValue(const nsStyleCoord::Calc* aCalc, nsCSSValue& aValue) 1.364 +{ 1.365 + nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(1); 1.366 + if (!aCalc->mHasPercent) { 1.367 + nscoordToCSSValue(aCalc->mLength, arr->Item(0)); 1.368 + } else { 1.369 + nsCSSValue::Array *arr2 = nsCSSValue::Array::Create(2); 1.370 + arr->Item(0).SetArrayValue(arr2, eCSSUnit_Calc_Plus); 1.371 + nscoordToCSSValue(aCalc->mLength, arr2->Item(0)); 1.372 + arr2->Item(1).SetPercentValue(aCalc->mPercent); 1.373 + } 1.374 + 1.375 + aValue.SetArrayValue(arr, eCSSUnit_Calc); 1.376 +} 1.377 + 1.378 +static void 1.379 +SetCalcValue(const CalcValue& aCalc, nsCSSValue& aValue) 1.380 +{ 1.381 + nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(1); 1.382 + if (!aCalc.mHasPercent) { 1.383 + arr->Item(0).SetFloatValue(aCalc.mLength, eCSSUnit_Pixel); 1.384 + } else { 1.385 + nsCSSValue::Array *arr2 = nsCSSValue::Array::Create(2); 1.386 + arr->Item(0).SetArrayValue(arr2, eCSSUnit_Calc_Plus); 1.387 + arr2->Item(0).SetFloatValue(aCalc.mLength, eCSSUnit_Pixel); 1.388 + arr2->Item(1).SetPercentValue(aCalc.mPercent); 1.389 + } 1.390 + 1.391 + aValue.SetArrayValue(arr, eCSSUnit_Calc); 1.392 +} 1.393 + 1.394 +static already_AddRefed<nsStringBuffer> 1.395 +GetURIAsUtf16StringBuffer(nsIURI* aUri) 1.396 +{ 1.397 + nsAutoCString utf8String; 1.398 + nsresult rv = aUri->GetSpec(utf8String); 1.399 + NS_ENSURE_SUCCESS(rv, nullptr); 1.400 + 1.401 + return nsCSSValue::BufferFromString(NS_ConvertUTF8toUTF16(utf8String)); 1.402 +} 1.403 + 1.404 +// CLASS METHODS 1.405 +// ------------- 1.406 + 1.407 +bool 1.408 +nsStyleAnimation::ComputeDistance(nsCSSProperty aProperty, 1.409 + const Value& aStartValue, 1.410 + const Value& aEndValue, 1.411 + double& aDistance) 1.412 +{ 1.413 + Unit commonUnit = 1.414 + GetCommonUnit(aProperty, aStartValue.GetUnit(), aEndValue.GetUnit()); 1.415 + 1.416 + switch (commonUnit) { 1.417 + case eUnit_Null: 1.418 + case eUnit_Auto: 1.419 + case eUnit_None: 1.420 + case eUnit_Normal: 1.421 + case eUnit_UnparsedString: 1.422 + return false; 1.423 + 1.424 + case eUnit_Enumerated: 1.425 + switch (aProperty) { 1.426 + case eCSSProperty_font_stretch: { 1.427 + // just like eUnit_Integer. 1.428 + int32_t startInt = aStartValue.GetIntValue(); 1.429 + int32_t endInt = aEndValue.GetIntValue(); 1.430 + aDistance = Abs(endInt - startInt); 1.431 + return true; 1.432 + } 1.433 + default: 1.434 + return false; 1.435 + } 1.436 + case eUnit_Visibility: { 1.437 + int32_t startEnum = aStartValue.GetIntValue(); 1.438 + int32_t endEnum = aEndValue.GetIntValue(); 1.439 + if (startEnum == endEnum) { 1.440 + aDistance = 0; 1.441 + return true; 1.442 + } 1.443 + if ((startEnum == NS_STYLE_VISIBILITY_VISIBLE) == 1.444 + (endEnum == NS_STYLE_VISIBILITY_VISIBLE)) { 1.445 + return false; 1.446 + } 1.447 + aDistance = 1; 1.448 + return true; 1.449 + } 1.450 + case eUnit_Integer: { 1.451 + int32_t startInt = aStartValue.GetIntValue(); 1.452 + int32_t endInt = aEndValue.GetIntValue(); 1.453 + aDistance = Abs(double(endInt) - double(startInt)); 1.454 + return true; 1.455 + } 1.456 + case eUnit_Coord: { 1.457 + nscoord startCoord = aStartValue.GetCoordValue(); 1.458 + nscoord endCoord = aEndValue.GetCoordValue(); 1.459 + aDistance = Abs(double(endCoord) - double(startCoord)); 1.460 + return true; 1.461 + } 1.462 + case eUnit_Percent: { 1.463 + float startPct = aStartValue.GetPercentValue(); 1.464 + float endPct = aEndValue.GetPercentValue(); 1.465 + aDistance = Abs(double(endPct) - double(startPct)); 1.466 + return true; 1.467 + } 1.468 + case eUnit_Float: { 1.469 + // Special case for flex-grow and flex-shrink: animations are 1.470 + // disallowed between 0 and other values. 1.471 + if ((aProperty == eCSSProperty_flex_grow || 1.472 + aProperty == eCSSProperty_flex_shrink) && 1.473 + (aStartValue.GetFloatValue() == 0.0f || 1.474 + aEndValue.GetFloatValue() == 0.0f) && 1.475 + aStartValue.GetFloatValue() != aEndValue.GetFloatValue()) { 1.476 + return false; 1.477 + } 1.478 + 1.479 + float startFloat = aStartValue.GetFloatValue(); 1.480 + float endFloat = aEndValue.GetFloatValue(); 1.481 + aDistance = Abs(double(endFloat) - double(startFloat)); 1.482 + return true; 1.483 + } 1.484 + case eUnit_Color: { 1.485 + // http://www.w3.org/TR/smil-animation/#animateColorElement says 1.486 + // that we should use Euclidean RGB cube distance. However, we 1.487 + // have to extend that to RGBA. For now, we'll just use the 1.488 + // Euclidean distance in the (part of the) 4-cube of premultiplied 1.489 + // colors. 1.490 + // FIXME (spec): The CSS transitions spec doesn't say whether 1.491 + // colors are premultiplied, but things work better when they are, 1.492 + // so use premultiplication. Spec issue is still open per 1.493 + // http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html 1.494 + nscolor startColor = aStartValue.GetColorValue(); 1.495 + nscolor endColor = aEndValue.GetColorValue(); 1.496 + 1.497 + // Get a color component on a 0-1 scale, which is much easier to 1.498 + // deal with when working with alpha. 1.499 + #define GET_COMPONENT(component_, color_) \ 1.500 + (NS_GET_##component_(color_) * (1.0 / 255.0)) 1.501 + 1.502 + double startA = GET_COMPONENT(A, startColor); 1.503 + double startR = GET_COMPONENT(R, startColor) * startA; 1.504 + double startG = GET_COMPONENT(G, startColor) * startA; 1.505 + double startB = GET_COMPONENT(B, startColor) * startA; 1.506 + double endA = GET_COMPONENT(A, endColor); 1.507 + double endR = GET_COMPONENT(R, endColor) * endA; 1.508 + double endG = GET_COMPONENT(G, endColor) * endA; 1.509 + double endB = GET_COMPONENT(B, endColor) * endA; 1.510 + 1.511 + #undef GET_COMPONENT 1.512 + 1.513 + double diffA = startA - endA; 1.514 + double diffR = startR - endR; 1.515 + double diffG = startG - endG; 1.516 + double diffB = startB - endB; 1.517 + aDistance = sqrt(diffA * diffA + diffR * diffR + 1.518 + diffG * diffG + diffB * diffB); 1.519 + return true; 1.520 + } 1.521 + case eUnit_Calc: { 1.522 + CalcValue v1 = ExtractCalcValue(aStartValue); 1.523 + CalcValue v2 = ExtractCalcValue(aEndValue); 1.524 + float difflen = v2.mLength - v1.mLength; 1.525 + float diffpct = v2.mPercent - v1.mPercent; 1.526 + aDistance = sqrt(difflen * difflen + diffpct * diffpct); 1.527 + return true; 1.528 + } 1.529 + case eUnit_CSSValuePair: { 1.530 + const nsCSSValuePair *pair1 = aStartValue.GetCSSValuePairValue(); 1.531 + const nsCSSValuePair *pair2 = aEndValue.GetCSSValuePairValue(); 1.532 + nsCSSUnit unit[2]; 1.533 + unit[0] = GetCommonUnit(aProperty, pair1->mXValue.GetUnit(), 1.534 + pair2->mXValue.GetUnit()); 1.535 + unit[1] = GetCommonUnit(aProperty, pair1->mYValue.GetUnit(), 1.536 + pair2->mYValue.GetUnit()); 1.537 + if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null || 1.538 + unit[0] == eCSSUnit_URL || unit[0] == eCSSUnit_Enumerated) { 1.539 + return false; 1.540 + } 1.541 + 1.542 + double squareDistance = 0.0; 1.543 + static nsCSSValue nsCSSValuePair::* const pairValues[2] = { 1.544 + &nsCSSValuePair::mXValue, &nsCSSValuePair::mYValue 1.545 + }; 1.546 + for (uint32_t i = 0; i < 2; ++i) { 1.547 + nsCSSValue nsCSSValuePair::*member = pairValues[i]; 1.548 + double diffsquared; 1.549 + switch (unit[i]) { 1.550 + case eCSSUnit_Pixel: { 1.551 + float diff = (pair1->*member).GetFloatValue() - 1.552 + (pair2->*member).GetFloatValue(); 1.553 + diffsquared = diff * diff; 1.554 + break; 1.555 + } 1.556 + case eCSSUnit_Percent: { 1.557 + float diff = (pair1->*member).GetPercentValue() - 1.558 + (pair2->*member).GetPercentValue(); 1.559 + diffsquared = diff * diff; 1.560 + break; 1.561 + } 1.562 + case eCSSUnit_Calc: { 1.563 + CalcValue v1 = ExtractCalcValue(pair1->*member); 1.564 + CalcValue v2 = ExtractCalcValue(pair2->*member); 1.565 + float difflen = v2.mLength - v1.mLength; 1.566 + float diffpct = v2.mPercent - v1.mPercent; 1.567 + diffsquared = difflen * difflen + diffpct * diffpct; 1.568 + break; 1.569 + } 1.570 + default: 1.571 + NS_ABORT_IF_FALSE(false, "unexpected unit"); 1.572 + return false; 1.573 + } 1.574 + squareDistance += diffsquared; 1.575 + } 1.576 + 1.577 + aDistance = sqrt(squareDistance); 1.578 + return true; 1.579 + } 1.580 + case eUnit_CSSValueTriplet: { 1.581 + const nsCSSValueTriplet *triplet1 = aStartValue.GetCSSValueTripletValue(); 1.582 + const nsCSSValueTriplet *triplet2 = aEndValue.GetCSSValueTripletValue(); 1.583 + nsCSSUnit unit[3]; 1.584 + unit[0] = GetCommonUnit(aProperty, triplet1->mXValue.GetUnit(), 1.585 + triplet2->mXValue.GetUnit()); 1.586 + unit[1] = GetCommonUnit(aProperty, triplet1->mYValue.GetUnit(), 1.587 + triplet2->mYValue.GetUnit()); 1.588 + unit[2] = GetCommonUnit(aProperty, triplet1->mZValue.GetUnit(), 1.589 + triplet2->mZValue.GetUnit()); 1.590 + if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null || 1.591 + unit[2] == eCSSUnit_Null) { 1.592 + return false; 1.593 + } 1.594 + 1.595 + double squareDistance = 0.0; 1.596 + static nsCSSValue nsCSSValueTriplet::* const pairValues[3] = { 1.597 + &nsCSSValueTriplet::mXValue, &nsCSSValueTriplet::mYValue, &nsCSSValueTriplet::mZValue 1.598 + }; 1.599 + for (uint32_t i = 0; i < 3; ++i) { 1.600 + nsCSSValue nsCSSValueTriplet::*member = pairValues[i]; 1.601 + double diffsquared; 1.602 + switch (unit[i]) { 1.603 + case eCSSUnit_Pixel: { 1.604 + float diff = (triplet1->*member).GetFloatValue() - 1.605 + (triplet2->*member).GetFloatValue(); 1.606 + diffsquared = diff * diff; 1.607 + break; 1.608 + } 1.609 + case eCSSUnit_Percent: { 1.610 + float diff = (triplet1->*member).GetPercentValue() - 1.611 + (triplet2->*member).GetPercentValue(); 1.612 + diffsquared = diff * diff; 1.613 + break; 1.614 + } 1.615 + case eCSSUnit_Calc: { 1.616 + CalcValue v1 = ExtractCalcValue(triplet1->*member); 1.617 + CalcValue v2 = ExtractCalcValue(triplet2->*member); 1.618 + float difflen = v2.mLength - v1.mLength; 1.619 + float diffpct = v2.mPercent - v1.mPercent; 1.620 + diffsquared = difflen * difflen + diffpct * diffpct; 1.621 + break; 1.622 + } 1.623 + case eCSSUnit_Null: 1.624 + diffsquared = 0; 1.625 + break; 1.626 + default: 1.627 + NS_ABORT_IF_FALSE(false, "unexpected unit"); 1.628 + return false; 1.629 + } 1.630 + squareDistance += diffsquared; 1.631 + } 1.632 + 1.633 + aDistance = sqrt(squareDistance); 1.634 + return true; 1.635 + } 1.636 + case eUnit_CSSRect: { 1.637 + const nsCSSRect *rect1 = aStartValue.GetCSSRectValue(); 1.638 + const nsCSSRect *rect2 = aEndValue.GetCSSRectValue(); 1.639 + if (rect1->mTop.GetUnit() != rect2->mTop.GetUnit() || 1.640 + rect1->mRight.GetUnit() != rect2->mRight.GetUnit() || 1.641 + rect1->mBottom.GetUnit() != rect2->mBottom.GetUnit() || 1.642 + rect1->mLeft.GetUnit() != rect2->mLeft.GetUnit()) { 1.643 + // At least until we have calc() 1.644 + return false; 1.645 + } 1.646 + 1.647 + double squareDistance = 0.0; 1.648 + for (uint32_t i = 0; i < ArrayLength(nsCSSRect::sides); ++i) { 1.649 + nsCSSValue nsCSSRect::*member = nsCSSRect::sides[i]; 1.650 + NS_ABORT_IF_FALSE((rect1->*member).GetUnit() == 1.651 + (rect2->*member).GetUnit(), 1.652 + "should have returned above"); 1.653 + double diff; 1.654 + switch ((rect1->*member).GetUnit()) { 1.655 + case eCSSUnit_Pixel: 1.656 + diff = (rect1->*member).GetFloatValue() - 1.657 + (rect2->*member).GetFloatValue(); 1.658 + break; 1.659 + case eCSSUnit_Auto: 1.660 + diff = 0; 1.661 + break; 1.662 + default: 1.663 + NS_ABORT_IF_FALSE(false, "unexpected unit"); 1.664 + return false; 1.665 + } 1.666 + squareDistance += diff * diff; 1.667 + } 1.668 + 1.669 + aDistance = sqrt(squareDistance); 1.670 + return true; 1.671 + } 1.672 + case eUnit_Dasharray: { 1.673 + // NOTE: This produces results on substantially different scales 1.674 + // for length values and percentage values, which might even be 1.675 + // mixed in the same property value. This means the result isn't 1.676 + // particularly useful for paced animation. 1.677 + 1.678 + // Call AddWeighted to make us lists of the same length. 1.679 + Value normValue1, normValue2; 1.680 + if (!AddWeighted(aProperty, 1.0, aStartValue, 0.0, aEndValue, 1.681 + normValue1) || 1.682 + !AddWeighted(aProperty, 0.0, aStartValue, 1.0, aEndValue, 1.683 + normValue2)) { 1.684 + return false; 1.685 + } 1.686 + 1.687 + double squareDistance = 0.0; 1.688 + const nsCSSValueList *list1 = normValue1.GetCSSValueListValue(); 1.689 + const nsCSSValueList *list2 = normValue2.GetCSSValueListValue(); 1.690 + 1.691 + NS_ABORT_IF_FALSE(!list1 == !list2, "lists should be same length"); 1.692 + while (list1) { 1.693 + const nsCSSValue &val1 = list1->mValue; 1.694 + const nsCSSValue &val2 = list2->mValue; 1.695 + 1.696 + NS_ABORT_IF_FALSE(val1.GetUnit() == val2.GetUnit(), 1.697 + "unit match should be assured by AddWeighted"); 1.698 + double diff; 1.699 + switch (val1.GetUnit()) { 1.700 + case eCSSUnit_Percent: 1.701 + diff = val1.GetPercentValue() - val2.GetPercentValue(); 1.702 + break; 1.703 + case eCSSUnit_Number: 1.704 + diff = val1.GetFloatValue() - val2.GetFloatValue(); 1.705 + break; 1.706 + default: 1.707 + NS_ABORT_IF_FALSE(false, "unexpected unit"); 1.708 + return false; 1.709 + } 1.710 + squareDistance += diff * diff; 1.711 + 1.712 + list1 = list1->mNext; 1.713 + list2 = list2->mNext; 1.714 + NS_ABORT_IF_FALSE(!list1 == !list2, "lists should be same length"); 1.715 + } 1.716 + 1.717 + aDistance = sqrt(squareDistance); 1.718 + return true; 1.719 + } 1.720 + case eUnit_Shadow: { 1.721 + // Call AddWeighted to make us lists of the same length. 1.722 + Value normValue1, normValue2; 1.723 + if (!AddWeighted(aProperty, 1.0, aStartValue, 0.0, aEndValue, 1.724 + normValue1) || 1.725 + !AddWeighted(aProperty, 0.0, aStartValue, 1.0, aEndValue, 1.726 + normValue2)) { 1.727 + return false; 1.728 + } 1.729 + 1.730 + const nsCSSValueList *shadow1 = normValue1.GetCSSValueListValue(); 1.731 + const nsCSSValueList *shadow2 = normValue2.GetCSSValueListValue(); 1.732 + 1.733 + double squareDistance = 0.0; 1.734 + NS_ABORT_IF_FALSE(!shadow1 == !shadow2, "lists should be same length"); 1.735 + while (shadow1) { 1.736 + nsCSSValue::Array *array1 = shadow1->mValue.GetArrayValue(); 1.737 + nsCSSValue::Array *array2 = shadow2->mValue.GetArrayValue(); 1.738 + for (size_t i = 0; i < 4; ++i) { 1.739 + NS_ABORT_IF_FALSE(array1->Item(i).GetUnit() == eCSSUnit_Pixel, 1.740 + "unexpected unit"); 1.741 + NS_ABORT_IF_FALSE(array2->Item(i).GetUnit() == eCSSUnit_Pixel, 1.742 + "unexpected unit"); 1.743 + double diff = array1->Item(i).GetFloatValue() - 1.744 + array2->Item(i).GetFloatValue(); 1.745 + squareDistance += diff * diff; 1.746 + } 1.747 + 1.748 + const nsCSSValue &color1 = array1->Item(4); 1.749 + const nsCSSValue &color2 = array2->Item(4); 1.750 +#ifdef DEBUG 1.751 + { 1.752 + const nsCSSValue &inset1 = array1->Item(5); 1.753 + const nsCSSValue &inset2 = array2->Item(5); 1.754 + // There are only two possible states of the inset value: 1.755 + // (1) GetUnit() == eCSSUnit_Null 1.756 + // (2) GetUnit() == eCSSUnit_Enumerated && 1.757 + // GetIntValue() == NS_STYLE_BOX_SHADOW_INSET 1.758 + NS_ABORT_IF_FALSE(((color1.IsNumericColorUnit() && 1.759 + color2.IsNumericColorUnit()) || 1.760 + (color1.GetUnit() == color2.GetUnit())) && 1.761 + inset1 == inset2, 1.762 + "AddWeighted should have failed"); 1.763 + } 1.764 +#endif 1.765 + 1.766 + if (color1.GetUnit() != eCSSUnit_Null) { 1.767 + nsStyleAnimation::Value color1Value 1.768 + (color1.GetColorValue(), nsStyleAnimation::Value::ColorConstructor); 1.769 + nsStyleAnimation::Value color2Value 1.770 + (color2.GetColorValue(), nsStyleAnimation::Value::ColorConstructor); 1.771 + double colorDistance; 1.772 + 1.773 + #ifdef DEBUG 1.774 + bool ok = 1.775 + #endif 1.776 + nsStyleAnimation::ComputeDistance(eCSSProperty_color, 1.777 + color1Value, color2Value, 1.778 + colorDistance); 1.779 + NS_ABORT_IF_FALSE(ok, "should not fail"); 1.780 + squareDistance += colorDistance * colorDistance; 1.781 + } 1.782 + 1.783 + shadow1 = shadow1->mNext; 1.784 + shadow2 = shadow2->mNext; 1.785 + NS_ABORT_IF_FALSE(!shadow1 == !shadow2, "lists should be same length"); 1.786 + } 1.787 + aDistance = sqrt(squareDistance); 1.788 + return true; 1.789 + } 1.790 + case eUnit_Filter: 1.791 + // FIXME: Support paced animations for filter function interpolation. 1.792 + case eUnit_Transform: { 1.793 + return false; 1.794 + } 1.795 + case eUnit_BackgroundPosition: { 1.796 + const nsCSSValueList *position1 = aStartValue.GetCSSValueListValue(); 1.797 + const nsCSSValueList *position2 = aEndValue.GetCSSValueListValue(); 1.798 + 1.799 + double squareDistance = 0.0; 1.800 + NS_ABORT_IF_FALSE(!position1 == !position2, "lists should be same length"); 1.801 + 1.802 + while (position1 && position2) { 1.803 + NS_ASSERTION(position1->mValue.GetUnit() == eCSSUnit_Array && 1.804 + position2->mValue.GetUnit() == eCSSUnit_Array, 1.805 + "Expected two arrays"); 1.806 + 1.807 + CalcValue calcVal[4]; 1.808 + 1.809 + nsCSSValue::Array* bgArray = position1->mValue.GetArrayValue(); 1.810 + NS_ABORT_IF_FALSE(bgArray->Count() == 4, "Invalid background-position"); 1.811 + NS_ASSERTION(bgArray->Item(0).GetUnit() == eCSSUnit_Null && 1.812 + bgArray->Item(2).GetUnit() == eCSSUnit_Null, 1.813 + "Invalid list used"); 1.814 + for (int i = 0; i < 2; ++i) { 1.815 + NS_ABORT_IF_FALSE(bgArray->Item(i*2+1).GetUnit() != eCSSUnit_Null, 1.816 + "Invalid background-position"); 1.817 + calcVal[i] = ExtractCalcValue(bgArray->Item(i*2+1)); 1.818 + } 1.819 + 1.820 + bgArray = position2->mValue.GetArrayValue(); 1.821 + NS_ABORT_IF_FALSE(bgArray->Count() == 4, "Invalid background-position"); 1.822 + NS_ASSERTION(bgArray->Item(0).GetUnit() == eCSSUnit_Null && 1.823 + bgArray->Item(2).GetUnit() == eCSSUnit_Null, 1.824 + "Invalid list used"); 1.825 + for (int i = 0; i < 2; ++i) { 1.826 + NS_ABORT_IF_FALSE(bgArray->Item(i*2+1).GetUnit() != eCSSUnit_Null, 1.827 + "Invalid background-position"); 1.828 + calcVal[i+2] = ExtractCalcValue(bgArray->Item(i*2+1)); 1.829 + } 1.830 + 1.831 + for (int i = 0; i < 2; ++i) { 1.832 + float difflen = calcVal[i+2].mLength - calcVal[i].mLength; 1.833 + float diffpct = calcVal[i+2].mPercent - calcVal[i].mPercent; 1.834 + squareDistance += difflen * difflen + diffpct * diffpct; 1.835 + } 1.836 + 1.837 + position1 = position1->mNext; 1.838 + position2 = position2->mNext; 1.839 + } 1.840 + // fail if lists differ in length. 1.841 + if (position1 || position2) { 1.842 + return false; 1.843 + } 1.844 + 1.845 + aDistance = sqrt(squareDistance); 1.846 + return true; 1.847 + } 1.848 + case eUnit_CSSValuePairList: { 1.849 + const nsCSSValuePairList *list1 = aStartValue.GetCSSValuePairListValue(); 1.850 + const nsCSSValuePairList *list2 = aEndValue.GetCSSValuePairListValue(); 1.851 + double squareDistance = 0.0; 1.852 + do { 1.853 + static nsCSSValue nsCSSValuePairList::* const pairListValues[] = { 1.854 + &nsCSSValuePairList::mXValue, 1.855 + &nsCSSValuePairList::mYValue, 1.856 + }; 1.857 + for (uint32_t i = 0; i < ArrayLength(pairListValues); ++i) { 1.858 + const nsCSSValue &v1 = list1->*(pairListValues[i]); 1.859 + const nsCSSValue &v2 = list2->*(pairListValues[i]); 1.860 + nsCSSUnit unit = 1.861 + GetCommonUnit(aProperty, v1.GetUnit(), v2.GetUnit()); 1.862 + if (unit == eCSSUnit_Null) { 1.863 + return false; 1.864 + } 1.865 + double diffsquared = 0.0; 1.866 + switch (unit) { 1.867 + case eCSSUnit_Pixel: { 1.868 + float diff = v1.GetFloatValue() - v2.GetFloatValue(); 1.869 + diffsquared = diff * diff; 1.870 + break; 1.871 + } 1.872 + case eCSSUnit_Percent: { 1.873 + float diff = v1.GetPercentValue() - v2.GetPercentValue(); 1.874 + diffsquared = diff * diff; 1.875 + break; 1.876 + } 1.877 + case eCSSUnit_Calc: { 1.878 + CalcValue val1 = ExtractCalcValue(v1); 1.879 + CalcValue val2 = ExtractCalcValue(v2); 1.880 + float difflen = val2.mLength - val1.mLength; 1.881 + float diffpct = val2.mPercent - val1.mPercent; 1.882 + diffsquared = difflen * difflen + diffpct * diffpct; 1.883 + break; 1.884 + } 1.885 + default: 1.886 + if (v1 != v2) { 1.887 + return false; 1.888 + } 1.889 + break; 1.890 + } 1.891 + squareDistance += diffsquared; 1.892 + } 1.893 + list1 = list1->mNext; 1.894 + list2 = list2->mNext; 1.895 + } while (list1 && list2); 1.896 + if (list1 || list2) { 1.897 + // We can't interpolate lists of different lengths. 1.898 + return false; 1.899 + } 1.900 + aDistance = sqrt(squareDistance); 1.901 + return true; 1.902 + } 1.903 + } 1.904 + 1.905 + NS_ABORT_IF_FALSE(false, "Can't compute distance using the given common unit"); 1.906 + return false; 1.907 +} 1.908 + 1.909 +#define MAX_PACKED_COLOR_COMPONENT 255 1.910 + 1.911 +inline uint8_t ClampColor(double aColor) 1.912 +{ 1.913 + if (aColor >= MAX_PACKED_COLOR_COMPONENT) 1.914 + return MAX_PACKED_COLOR_COMPONENT; 1.915 + if (aColor <= 0.0) 1.916 + return 0; 1.917 + return NSToIntRound(aColor); 1.918 +} 1.919 + 1.920 +// Ensure that a float/double value isn't NaN by returning zero instead 1.921 +// (NaN doesn't have a sign) as a general restriction for floating point 1.922 +// values in RestrictValue. 1.923 +template<typename T> 1.924 +MOZ_ALWAYS_INLINE T 1.925 +EnsureNotNan(T aValue) 1.926 +{ 1.927 + return aValue; 1.928 +} 1.929 +template<> 1.930 +MOZ_ALWAYS_INLINE float 1.931 +EnsureNotNan(float aValue) 1.932 +{ 1.933 + // This would benefit from a MOZ_FLOAT_IS_NaN if we had one. 1.934 + return MOZ_LIKELY(!mozilla::IsNaN(aValue)) ? aValue : 0; 1.935 +} 1.936 +template<> 1.937 +MOZ_ALWAYS_INLINE double 1.938 +EnsureNotNan(double aValue) 1.939 +{ 1.940 + return MOZ_LIKELY(!mozilla::IsNaN(aValue)) ? aValue : 0; 1.941 +} 1.942 + 1.943 +template <typename T> 1.944 +T 1.945 +RestrictValue(uint32_t aRestrictions, T aValue) 1.946 +{ 1.947 + T result = EnsureNotNan(aValue); 1.948 + switch (aRestrictions) { 1.949 + case 0: 1.950 + break; 1.951 + case CSS_PROPERTY_VALUE_NONNEGATIVE: 1.952 + if (result < 0) { 1.953 + result = 0; 1.954 + } 1.955 + break; 1.956 + case CSS_PROPERTY_VALUE_AT_LEAST_ONE: 1.957 + if (result < 1) { 1.958 + result = 1; 1.959 + } 1.960 + break; 1.961 + default: 1.962 + NS_ABORT_IF_FALSE(false, "bad value restriction"); 1.963 + break; 1.964 + } 1.965 + return result; 1.966 +} 1.967 + 1.968 +template <typename T> 1.969 +T 1.970 +RestrictValue(nsCSSProperty aProperty, T aValue) 1.971 +{ 1.972 + return RestrictValue(nsCSSProps::ValueRestrictions(aProperty), aValue); 1.973 +} 1.974 + 1.975 +static inline void 1.976 +AddCSSValuePixel(double aCoeff1, const nsCSSValue &aValue1, 1.977 + double aCoeff2, const nsCSSValue &aValue2, 1.978 + nsCSSValue &aResult, uint32_t aValueRestrictions = 0) 1.979 +{ 1.980 + NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Pixel, "unexpected unit"); 1.981 + NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Pixel, "unexpected unit"); 1.982 + aResult.SetFloatValue(RestrictValue(aValueRestrictions, 1.983 + aCoeff1 * aValue1.GetFloatValue() + 1.984 + aCoeff2 * aValue2.GetFloatValue()), 1.985 + eCSSUnit_Pixel); 1.986 +} 1.987 + 1.988 +static inline void 1.989 +AddCSSValueNumber(double aCoeff1, const nsCSSValue &aValue1, 1.990 + double aCoeff2, const nsCSSValue &aValue2, 1.991 + nsCSSValue &aResult, uint32_t aValueRestrictions = 0) 1.992 +{ 1.993 + NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Number, "unexpected unit"); 1.994 + NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Number, "unexpected unit"); 1.995 + aResult.SetFloatValue(RestrictValue(aValueRestrictions, 1.996 + aCoeff1 * aValue1.GetFloatValue() + 1.997 + aCoeff2 * aValue2.GetFloatValue()), 1.998 + eCSSUnit_Number); 1.999 +} 1.1000 + 1.1001 +static inline void 1.1002 +AddCSSValuePercent(double aCoeff1, const nsCSSValue &aValue1, 1.1003 + double aCoeff2, const nsCSSValue &aValue2, 1.1004 + nsCSSValue &aResult, uint32_t aValueRestrictions = 0) 1.1005 +{ 1.1006 + NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Percent, "unexpected unit"); 1.1007 + NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Percent, "unexpected unit"); 1.1008 + aResult.SetPercentValue(RestrictValue(aValueRestrictions, 1.1009 + aCoeff1 * aValue1.GetPercentValue() + 1.1010 + aCoeff2 * aValue2.GetPercentValue())); 1.1011 +} 1.1012 + 1.1013 +// Add two canonical-form calc values (eUnit_Calc) to make another 1.1014 +// canonical-form calc value. 1.1015 +static void 1.1016 +AddCSSValueCanonicalCalc(double aCoeff1, const nsCSSValue &aValue1, 1.1017 + double aCoeff2, const nsCSSValue &aValue2, 1.1018 + nsCSSValue &aResult) 1.1019 +{ 1.1020 + CalcValue v1 = ExtractCalcValue(aValue1); 1.1021 + CalcValue v2 = ExtractCalcValue(aValue2); 1.1022 + CalcValue result; 1.1023 + result.mLength = aCoeff1 * v1.mLength + aCoeff2 * v2.mLength; 1.1024 + result.mPercent = aCoeff1 * v1.mPercent + aCoeff2 * v2.mPercent; 1.1025 + result.mHasPercent = v1.mHasPercent || v2.mHasPercent; 1.1026 + MOZ_ASSERT(result.mHasPercent || result.mPercent == 0.0f, 1.1027 + "can't have a nonzero percentage part without having percentages"); 1.1028 + SetCalcValue(result, aResult); 1.1029 +} 1.1030 + 1.1031 +static void 1.1032 +AddCSSValueAngle(double aCoeff1, const nsCSSValue &aValue1, 1.1033 + double aCoeff2, const nsCSSValue &aValue2, 1.1034 + nsCSSValue &aResult) 1.1035 +{ 1.1036 + aResult.SetFloatValue(aCoeff1 * aValue1.GetAngleValueInRadians() + 1.1037 + aCoeff2 * aValue2.GetAngleValueInRadians(), 1.1038 + eCSSUnit_Radian); 1.1039 +} 1.1040 + 1.1041 +static bool 1.1042 +AddCSSValuePixelPercentCalc(const uint32_t aValueRestrictions, 1.1043 + const nsCSSUnit aCommonUnit, 1.1044 + double aCoeff1, const nsCSSValue &aValue1, 1.1045 + double aCoeff2, const nsCSSValue &aValue2, 1.1046 + nsCSSValue &aResult) 1.1047 +{ 1.1048 + switch (aCommonUnit) { 1.1049 + case eCSSUnit_Pixel: 1.1050 + AddCSSValuePixel(aCoeff1, aValue1, 1.1051 + aCoeff2, aValue2, 1.1052 + aResult, aValueRestrictions); 1.1053 + break; 1.1054 + case eCSSUnit_Percent: 1.1055 + AddCSSValuePercent(aCoeff1, aValue1, 1.1056 + aCoeff2, aValue2, 1.1057 + aResult, aValueRestrictions); 1.1058 + break; 1.1059 + case eCSSUnit_Calc: 1.1060 + AddCSSValueCanonicalCalc(aCoeff1, aValue1, 1.1061 + aCoeff2, aValue2, 1.1062 + aResult); 1.1063 + break; 1.1064 + default: 1.1065 + return false; 1.1066 + } 1.1067 + 1.1068 + return true; 1.1069 +} 1.1070 + 1.1071 +static inline float 1.1072 +GetNumberOrPercent(const nsCSSValue &aValue) 1.1073 +{ 1.1074 + nsCSSUnit unit = aValue.GetUnit(); 1.1075 + NS_ABORT_IF_FALSE(unit == eCSSUnit_Number || unit == eCSSUnit_Percent, 1.1076 + "unexpected unit"); 1.1077 + return (unit == eCSSUnit_Number) ? 1.1078 + aValue.GetFloatValue() : aValue.GetPercentValue(); 1.1079 +} 1.1080 + 1.1081 +static inline void 1.1082 +AddCSSValuePercentNumber(const uint32_t aValueRestrictions, 1.1083 + double aCoeff1, const nsCSSValue &aValue1, 1.1084 + double aCoeff2, const nsCSSValue &aValue2, 1.1085 + nsCSSValue &aResult, float aInitialVal) 1.1086 +{ 1.1087 + float n1 = GetNumberOrPercent(aValue1); 1.1088 + float n2 = GetNumberOrPercent(aValue2); 1.1089 + 1.1090 + // Rather than interpolating aValue1 and aValue2 directly, we 1.1091 + // interpolate their *distances from aInitialVal* (the initial value, 1.1092 + // which is either 1 or 0 for "filter" functions). This matters in 1.1093 + // cases where aInitialVal is nonzero and the coefficients don't add 1.1094 + // up to 1. For example, if initialVal is 1, aCoeff1 is 0.5, and 1.1095 + // aCoeff2 is 0, then we'll return the value halfway between 1 and 1.1096 + // aValue1, rather than the value halfway between 0 and aValue1. 1.1097 + // Note that we do something similar in AddTransformScale(). 1.1098 + float result = (n1 - aInitialVal) * aCoeff1 + (n2 - aInitialVal) * aCoeff2; 1.1099 + aResult.SetFloatValue(RestrictValue(aValueRestrictions, result + aInitialVal), 1.1100 + eCSSUnit_Number); 1.1101 +} 1.1102 + 1.1103 +static bool 1.1104 +AddShadowItems(double aCoeff1, const nsCSSValue &aValue1, 1.1105 + double aCoeff2, const nsCSSValue &aValue2, 1.1106 + nsCSSValueList **&aResultTail) 1.1107 +{ 1.1108 + // X, Y, Radius, Spread, Color, Inset 1.1109 + NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Array, 1.1110 + "wrong unit"); 1.1111 + NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Array, 1.1112 + "wrong unit"); 1.1113 + nsCSSValue::Array *array1 = aValue1.GetArrayValue(); 1.1114 + nsCSSValue::Array *array2 = aValue2.GetArrayValue(); 1.1115 + nsRefPtr<nsCSSValue::Array> resultArray = nsCSSValue::Array::Create(6); 1.1116 + 1.1117 + for (size_t i = 0; i < 4; ++i) { 1.1118 + AddCSSValuePixel(aCoeff1, array1->Item(i), aCoeff2, array2->Item(i), 1.1119 + resultArray->Item(i), 1.1120 + // blur radius must be nonnegative 1.1121 + (i == 2) ? CSS_PROPERTY_VALUE_NONNEGATIVE : 0); 1.1122 + } 1.1123 + 1.1124 + const nsCSSValue& color1 = array1->Item(4); 1.1125 + const nsCSSValue& color2 = array2->Item(4); 1.1126 + const nsCSSValue& inset1 = array1->Item(5); 1.1127 + const nsCSSValue& inset2 = array2->Item(5); 1.1128 + if (color1.GetUnit() != color2.GetUnit() || 1.1129 + inset1.GetUnit() != inset2.GetUnit()) { 1.1130 + // We don't know how to animate between color and no-color, or 1.1131 + // between inset and not-inset. 1.1132 + return false; 1.1133 + } 1.1134 + 1.1135 + if (color1.GetUnit() != eCSSUnit_Null) { 1.1136 + nsStyleAnimation::Value color1Value 1.1137 + (color1.GetColorValue(), nsStyleAnimation::Value::ColorConstructor); 1.1138 + nsStyleAnimation::Value color2Value 1.1139 + (color2.GetColorValue(), nsStyleAnimation::Value::ColorConstructor); 1.1140 + nsStyleAnimation::Value resultColorValue; 1.1141 + #ifdef DEBUG 1.1142 + bool ok = 1.1143 + #endif 1.1144 + nsStyleAnimation::AddWeighted(eCSSProperty_color, aCoeff1, color1Value, 1.1145 + aCoeff2, color2Value, resultColorValue); 1.1146 + NS_ABORT_IF_FALSE(ok, "should not fail"); 1.1147 + resultArray->Item(4).SetColorValue(resultColorValue.GetColorValue()); 1.1148 + } 1.1149 + 1.1150 + NS_ABORT_IF_FALSE(inset1 == inset2, "should match"); 1.1151 + resultArray->Item(5) = inset1; 1.1152 + 1.1153 + nsCSSValueList *resultItem = new nsCSSValueList; 1.1154 + if (!resultItem) { 1.1155 + return false; 1.1156 + } 1.1157 + resultItem->mValue.SetArrayValue(resultArray, eCSSUnit_Array); 1.1158 + *aResultTail = resultItem; 1.1159 + aResultTail = &resultItem->mNext; 1.1160 + return true; 1.1161 +} 1.1162 + 1.1163 +static void 1.1164 +AddTransformTranslate(double aCoeff1, const nsCSSValue &aValue1, 1.1165 + double aCoeff2, const nsCSSValue &aValue2, 1.1166 + nsCSSValue &aResult) 1.1167 +{ 1.1168 + NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Percent || 1.1169 + aValue1.GetUnit() == eCSSUnit_Pixel || 1.1170 + aValue1.IsCalcUnit(), 1.1171 + "unexpected unit"); 1.1172 + NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Percent || 1.1173 + aValue2.GetUnit() == eCSSUnit_Pixel || 1.1174 + aValue2.IsCalcUnit(), 1.1175 + "unexpected unit"); 1.1176 + 1.1177 + if (aValue1.GetUnit() != aValue2.GetUnit() || aValue1.IsCalcUnit()) { 1.1178 + // different units; create a calc() expression 1.1179 + AddCSSValueCanonicalCalc(aCoeff1, aValue1, aCoeff2, aValue2, aResult); 1.1180 + } else if (aValue1.GetUnit() == eCSSUnit_Percent) { 1.1181 + // both percent 1.1182 + AddCSSValuePercent(aCoeff1, aValue1, aCoeff2, aValue2, aResult); 1.1183 + } else { 1.1184 + // both pixels 1.1185 + AddCSSValuePixel(aCoeff1, aValue1, aCoeff2, aValue2, aResult); 1.1186 + } 1.1187 +} 1.1188 + 1.1189 +static void 1.1190 +AddTransformScale(double aCoeff1, const nsCSSValue &aValue1, 1.1191 + double aCoeff2, const nsCSSValue &aValue2, 1.1192 + nsCSSValue &aResult) 1.1193 +{ 1.1194 + // Handle scale, and the two matrix components where identity is 1, by 1.1195 + // subtracting 1, multiplying by the coefficients, and then adding 1 1.1196 + // back. This gets the right AddWeighted behavior and gets us the 1.1197 + // interpolation-against-identity behavior for free. 1.1198 + NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Number, "unexpected unit"); 1.1199 + NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Number, "unexpected unit"); 1.1200 + 1.1201 + float v1 = aValue1.GetFloatValue() - 1.0f, 1.1202 + v2 = aValue2.GetFloatValue() - 1.0f; 1.1203 + float result = v1 * aCoeff1 + v2 * aCoeff2; 1.1204 + aResult.SetFloatValue(result + 1.0f, eCSSUnit_Number); 1.1205 +} 1.1206 + 1.1207 +/* static */ already_AddRefed<nsCSSValue::Array> 1.1208 +nsStyleAnimation::AppendTransformFunction(nsCSSKeyword aTransformFunction, 1.1209 + nsCSSValueList**& aListTail) 1.1210 +{ 1.1211 + nsRefPtr<nsCSSValue::Array> arr = AppendFunction(aTransformFunction); 1.1212 + nsCSSValueList *item = new nsCSSValueList; 1.1213 + item->mValue.SetArrayValue(arr, eCSSUnit_Function); 1.1214 + 1.1215 + *aListTail = item; 1.1216 + aListTail = &item->mNext; 1.1217 + 1.1218 + return arr.forget(); 1.1219 +} 1.1220 + 1.1221 +/* 1.1222 + * The relevant section of the transitions specification: 1.1223 + * http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types- 1.1224 + * defers all of the details to the 2-D and 3-D transforms specifications. 1.1225 + * For the 2-D transforms specification (all that's relevant for us, right 1.1226 + * now), the relevant section is: 1.1227 + * http://dev.w3.org/csswg/css3-2d-transforms/#animation 1.1228 + * This, in turn, refers to the unmatrix program in Graphics Gems, 1.1229 + * available from http://tog.acm.org/resources/GraphicsGems/ , and in 1.1230 + * particular as the file GraphicsGems/gemsii/unmatrix.c 1.1231 + * in http://tog.acm.org/resources/GraphicsGems/AllGems.tar.gz 1.1232 + * 1.1233 + * The unmatrix reference is for general 3-D transform matrices (any of the 1.1234 + * 16 components can have any value). 1.1235 + * 1.1236 + * For CSS 2-D transforms, we have a 2-D matrix with the bottom row constant: 1.1237 + * 1.1238 + * [ A C E ] 1.1239 + * [ B D F ] 1.1240 + * [ 0 0 1 ] 1.1241 + * 1.1242 + * For that case, I believe the algorithm in unmatrix reduces to: 1.1243 + * 1.1244 + * (1) If A * D - B * C == 0, the matrix is singular. Fail. 1.1245 + * 1.1246 + * (2) Set translation components (Tx and Ty) to the translation parts of 1.1247 + * the matrix (E and F) and then ignore them for the rest of the time. 1.1248 + * (For us, E and F each actually consist of three constants: a 1.1249 + * length, a multiplier for the width, and a multiplier for the 1.1250 + * height. This actually requires its own decomposition, but I'll 1.1251 + * keep that separate.) 1.1252 + * 1.1253 + * (3) Let the X scale (Sx) be sqrt(A^2 + B^2). Then divide both A and B 1.1254 + * by it. 1.1255 + * 1.1256 + * (4) Let the XY shear (K) be A * C + B * D. From C, subtract A times 1.1257 + * the XY shear. From D, subtract B times the XY shear. 1.1258 + * 1.1259 + * (5) Let the Y scale (Sy) be sqrt(C^2 + D^2). Divide C, D, and the XY 1.1260 + * shear (K) by it. 1.1261 + * 1.1262 + * (6) At this point, A * D - B * C is either 1 or -1. If it is -1, 1.1263 + * negate the XY shear (K), the X scale (Sx), and A, B, C, and D. 1.1264 + * (Alternatively, we could negate the XY shear (K) and the Y scale 1.1265 + * (Sy).) 1.1266 + * 1.1267 + * (7) Let the rotation be R = atan2(B, A). 1.1268 + * 1.1269 + * Then the resulting decomposed transformation is: 1.1270 + * 1.1271 + * translate(Tx, Ty) rotate(R) skewX(atan(K)) scale(Sx, Sy) 1.1272 + * 1.1273 + * An interesting result of this is that all of the simple transform 1.1274 + * functions (i.e., all functions other than matrix()), in isolation, 1.1275 + * decompose back to themselves except for: 1.1276 + * 'skewY(φ)', which is 'matrix(1, tan(φ), 0, 1, 0, 0)', which decomposes 1.1277 + * to 'rotate(φ) skewX(φ) scale(sec(φ), cos(φ))' since (ignoring the 1.1278 + * alternate sign possibilities that would get fixed in step 6): 1.1279 + * In step 3, the X scale factor is sqrt(1+tan²(φ)) = sqrt(sec²(φ)) = sec(φ). 1.1280 + * Thus, after step 3, A = 1/sec(φ) = cos(φ) and B = tan(φ) / sec(φ) = sin(φ). 1.1281 + * In step 4, the XY shear is sin(φ). 1.1282 + * Thus, after step 4, C = -cos(φ)sin(φ) and D = 1 - sin²(φ) = cos²(φ). 1.1283 + * Thus, in step 5, the Y scale is sqrt(cos²(φ)(sin²(φ) + cos²(φ)) = cos(φ). 1.1284 + * Thus, after step 5, C = -sin(φ), D = cos(φ), and the XY shear is tan(φ). 1.1285 + * Thus, in step 6, A * D - B * C = cos²(φ) + sin²(φ) = 1. 1.1286 + * In step 7, the rotation is thus φ. 1.1287 + * 1.1288 + * skew(θ, φ), which is matrix(1, tan(φ), tan(θ), 1, 0, 0), which decomposes 1.1289 + * to 'rotate(φ) skewX(θ + φ) scale(sec(φ), cos(φ))' since (ignoring 1.1290 + * the alternate sign possibilities that would get fixed in step 6): 1.1291 + * In step 3, the X scale factor is sqrt(1+tan²(φ)) = sqrt(sec²(φ)) = sec(φ). 1.1292 + * Thus, after step 3, A = 1/sec(φ) = cos(φ) and B = tan(φ) / sec(φ) = sin(φ). 1.1293 + * In step 4, the XY shear is cos(φ)tan(θ) + sin(φ). 1.1294 + * Thus, after step 4, 1.1295 + * C = tan(θ) - cos(φ)(cos(φ)tan(θ) + sin(φ)) = tan(θ)sin²(φ) - cos(φ)sin(φ) 1.1296 + * D = 1 - sin(φ)(cos(φ)tan(θ) + sin(φ)) = cos²(φ) - sin(φ)cos(φ)tan(θ) 1.1297 + * Thus, in step 5, the Y scale is sqrt(C² + D²) = 1.1298 + * sqrt(tan²(θ)(sin⁴(φ) + sin²(φ)cos²(φ)) - 1.1299 + * 2 tan(θ)(sin³(φ)cos(φ) + sin(φ)cos³(φ)) + 1.1300 + * (sin²(φ)cos²(φ) + cos⁴(φ))) = 1.1301 + * sqrt(tan²(θ)sin²(φ) - 2 tan(θ)sin(φ)cos(φ) + cos²(φ)) = 1.1302 + * cos(φ) - tan(θ)sin(φ) (taking the negative of the obvious solution so 1.1303 + * we avoid flipping in step 6). 1.1304 + * After step 5, C = -sin(φ) and D = cos(φ), and the XY shear is 1.1305 + * (cos(φ)tan(θ) + sin(φ)) / (cos(φ) - tan(θ)sin(φ)) = 1.1306 + * (dividing both numerator and denominator by cos(φ)) 1.1307 + * (tan(θ) + tan(φ)) / (1 - tan(θ)tan(φ)) = tan(θ + φ). 1.1308 + * (See http://en.wikipedia.org/wiki/List_of_trigonometric_identities .) 1.1309 + * Thus, in step 6, A * D - B * C = cos²(φ) + sin²(φ) = 1. 1.1310 + * In step 7, the rotation is thus φ. 1.1311 + * 1.1312 + * To check this result, we can multiply things back together: 1.1313 + * 1.1314 + * [ cos(φ) -sin(φ) ] [ 1 tan(θ + φ) ] [ sec(φ) 0 ] 1.1315 + * [ sin(φ) cos(φ) ] [ 0 1 ] [ 0 cos(φ) ] 1.1316 + * 1.1317 + * [ cos(φ) cos(φ)tan(θ + φ) - sin(φ) ] [ sec(φ) 0 ] 1.1318 + * [ sin(φ) sin(φ)tan(θ + φ) + cos(φ) ] [ 0 cos(φ) ] 1.1319 + * 1.1320 + * but since tan(θ + φ) = (tan(θ) + tan(φ)) / (1 - tan(θ)tan(φ)), 1.1321 + * cos(φ)tan(θ + φ) - sin(φ) 1.1322 + * = cos(φ)(tan(θ) + tan(φ)) - sin(φ) + sin(φ)tan(θ)tan(φ) 1.1323 + * = cos(φ)tan(θ) + sin(φ) - sin(φ) + sin(φ)tan(θ)tan(φ) 1.1324 + * = cos(φ)tan(θ) + sin(φ)tan(θ)tan(φ) 1.1325 + * = tan(θ) (cos(φ) + sin(φ)tan(φ)) 1.1326 + * = tan(θ) sec(φ) (cos²(φ) + sin²(φ)) 1.1327 + * = tan(θ) sec(φ) 1.1328 + * and 1.1329 + * sin(φ)tan(θ + φ) + cos(φ) 1.1330 + * = sin(φ)(tan(θ) + tan(φ)) + cos(φ) - cos(φ)tan(θ)tan(φ) 1.1331 + * = tan(θ) (sin(φ) - sin(φ)) + sin(φ)tan(φ) + cos(φ) 1.1332 + * = sec(φ) (sin²(φ) + cos²(φ)) 1.1333 + * = sec(φ) 1.1334 + * so the above is: 1.1335 + * [ cos(φ) tan(θ) sec(φ) ] [ sec(φ) 0 ] 1.1336 + * [ sin(φ) sec(φ) ] [ 0 cos(φ) ] 1.1337 + * 1.1338 + * [ 1 tan(θ) ] 1.1339 + * [ tan(φ) 1 ] 1.1340 + */ 1.1341 + 1.1342 +/* 1.1343 + * Decompose2DMatrix implements the above decomposition algorithm. 1.1344 + */ 1.1345 + 1.1346 +#define XYSHEAR 0 1.1347 +#define XZSHEAR 1 1.1348 +#define YZSHEAR 2 1.1349 + 1.1350 +static bool 1.1351 +Decompose2DMatrix(const gfxMatrix &aMatrix, gfxPoint3D &aScale, 1.1352 + float aShear[3], gfxQuaternion &aRotate, 1.1353 + gfxPoint3D &aTranslate) 1.1354 +{ 1.1355 + float A = aMatrix.xx, 1.1356 + B = aMatrix.yx, 1.1357 + C = aMatrix.xy, 1.1358 + D = aMatrix.yy; 1.1359 + if (A * D == B * C) { 1.1360 + // singular matrix 1.1361 + return false; 1.1362 + } 1.1363 + 1.1364 + float scaleX = sqrt(A * A + B * B); 1.1365 + A /= scaleX; 1.1366 + B /= scaleX; 1.1367 + 1.1368 + float XYshear = A * C + B * D; 1.1369 + C -= A * XYshear; 1.1370 + D -= B * XYshear; 1.1371 + 1.1372 + float scaleY = sqrt(C * C + D * D); 1.1373 + C /= scaleY; 1.1374 + D /= scaleY; 1.1375 + XYshear /= scaleY; 1.1376 + 1.1377 + // A*D - B*C should now be 1 or -1 1.1378 + NS_ASSERTION(0.99 < Abs(A*D - B*C) && Abs(A*D - B*C) < 1.01, 1.1379 + "determinant should now be 1 or -1"); 1.1380 + if (A * D < B * C) { 1.1381 + A = -A; 1.1382 + B = -B; 1.1383 + C = -C; 1.1384 + D = -D; 1.1385 + XYshear = -XYshear; 1.1386 + scaleX = -scaleX; 1.1387 + } 1.1388 + 1.1389 + float rotate = atan2f(B, A); 1.1390 + aRotate = gfxQuaternion(0, 0, sin(rotate/2), cos(rotate/2)); 1.1391 + aShear[XYSHEAR] = XYshear; 1.1392 + aScale.x = scaleX; 1.1393 + aScale.y = scaleY; 1.1394 + aTranslate.x = aMatrix.x0; 1.1395 + aTranslate.y = aMatrix.y0; 1.1396 + return true; 1.1397 +} 1.1398 + 1.1399 +/** 1.1400 + * Implementation of the unmatrix algorithm, specified by: 1.1401 + * 1.1402 + * http://dev.w3.org/csswg/css3-2d-transforms/#unmatrix 1.1403 + * 1.1404 + * This, in turn, refers to the unmatrix program in Graphics Gems, 1.1405 + * available from http://tog.acm.org/resources/GraphicsGems/ , and in 1.1406 + * particular as the file GraphicsGems/gemsii/unmatrix.c 1.1407 + * in http://tog.acm.org/resources/GraphicsGems/AllGems.tar.gz 1.1408 + */ 1.1409 +static bool 1.1410 +Decompose3DMatrix(const gfx3DMatrix &aMatrix, gfxPoint3D &aScale, 1.1411 + float aShear[3], gfxQuaternion &aRotate, 1.1412 + gfxPoint3D &aTranslate, gfxPointH3D &aPerspective) 1.1413 +{ 1.1414 + gfx3DMatrix local = aMatrix; 1.1415 + 1.1416 + if (local[3][3] == 0) { 1.1417 + return false; 1.1418 + } 1.1419 + /* Normalize the matrix */ 1.1420 + local.Normalize(); 1.1421 + 1.1422 + /** 1.1423 + * perspective is used to solve for perspective, but it also provides 1.1424 + * an easy way to test for singularity of the upper 3x3 component. 1.1425 + */ 1.1426 + gfx3DMatrix perspective = local; 1.1427 + gfxPointH3D empty(0, 0, 0, 1); 1.1428 + perspective.SetTransposedVector(3, empty); 1.1429 + 1.1430 + if (perspective.Determinant() == 0.0) { 1.1431 + return false; 1.1432 + } 1.1433 + 1.1434 + /* First, isolate perspective. */ 1.1435 + if (local[0][3] != 0 || local[1][3] != 0 || 1.1436 + local[2][3] != 0) { 1.1437 + /* aPerspective is the right hand side of the equation. */ 1.1438 + aPerspective = local.TransposedVector(3); 1.1439 + 1.1440 + /** 1.1441 + * Solve the equation by inverting perspective and multiplying 1.1442 + * aPerspective by the inverse. 1.1443 + */ 1.1444 + perspective.Invert(); 1.1445 + aPerspective = perspective.TransposeTransform4D(aPerspective); 1.1446 + 1.1447 + /* Clear the perspective partition */ 1.1448 + local.SetTransposedVector(3, empty); 1.1449 + } else { 1.1450 + aPerspective = gfxPointH3D(0, 0, 0, 1); 1.1451 + } 1.1452 + 1.1453 + /* Next take care of translation */ 1.1454 + for (int i = 0; i < 3; i++) { 1.1455 + aTranslate[i] = local[3][i]; 1.1456 + local[3][i] = 0; 1.1457 + } 1.1458 + 1.1459 + /* Now get scale and shear. */ 1.1460 + 1.1461 + /* Compute X scale factor and normalize first row. */ 1.1462 + aScale.x = local[0].Length(); 1.1463 + local[0] /= aScale.x; 1.1464 + 1.1465 + /* Compute XY shear factor and make 2nd local orthogonal to 1st. */ 1.1466 + aShear[XYSHEAR] = local[0].DotProduct(local[1]); 1.1467 + local[1] -= local[0] * aShear[XYSHEAR]; 1.1468 + 1.1469 + /* Now, compute Y scale and normalize 2nd local. */ 1.1470 + aScale.y = local[1].Length(); 1.1471 + local[1] /= aScale.y; 1.1472 + aShear[XYSHEAR] /= aScale.y; 1.1473 + 1.1474 + /* Compute XZ and YZ shears, make 3rd local orthogonal */ 1.1475 + aShear[XZSHEAR] = local[0].DotProduct(local[2]); 1.1476 + local[2] -= local[0] * aShear[XZSHEAR]; 1.1477 + aShear[YZSHEAR] = local[1].DotProduct(local[2]); 1.1478 + local[2] -= local[1] * aShear[YZSHEAR]; 1.1479 + 1.1480 + /* Next, get Z scale and normalize 3rd local. */ 1.1481 + aScale.z = local[2].Length(); 1.1482 + local[2] /= aScale.z; 1.1483 + 1.1484 + aShear[XZSHEAR] /= aScale.z; 1.1485 + aShear[YZSHEAR] /= aScale.z; 1.1486 + 1.1487 + /** 1.1488 + * At this point, the matrix (in locals) is orthonormal. 1.1489 + * Check for a coordinate system flip. If the determinant 1.1490 + * is -1, then negate the matrix and the scaling factors. 1.1491 + */ 1.1492 + if (local[0].DotProduct(local[1].CrossProduct(local[2])) < 0) { 1.1493 + aScale *= -1; 1.1494 + for (int i = 0; i < 3; i++) { 1.1495 + local[i] *= -1; 1.1496 + } 1.1497 + } 1.1498 + 1.1499 + /* Now, get the rotations out */ 1.1500 + aRotate = gfxQuaternion(local); 1.1501 + 1.1502 + return true; 1.1503 +} 1.1504 + 1.1505 +template<typename T> 1.1506 +T InterpolateNumerically(const T& aOne, const T& aTwo, double aCoeff) 1.1507 +{ 1.1508 + return aOne + (aTwo - aOne) * aCoeff; 1.1509 +} 1.1510 + 1.1511 + 1.1512 +/* static */ gfx3DMatrix 1.1513 +nsStyleAnimation::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, 1.1514 + const gfx3DMatrix &aMatrix2, 1.1515 + double aProgress) 1.1516 +{ 1.1517 + // Decompose both matrices 1.1518 + 1.1519 + // TODO: What do we do if one of these returns false (singular matrix) 1.1520 + 1.1521 + gfxPoint3D scale1(1, 1, 1), translate1; 1.1522 + gfxPointH3D perspective1(0, 0, 0, 1); 1.1523 + gfxQuaternion rotate1; 1.1524 + float shear1[3] = { 0.0f, 0.0f, 0.0f}; 1.1525 + 1.1526 + gfxPoint3D scale2(1, 1, 1), translate2; 1.1527 + gfxPointH3D perspective2(0, 0, 0, 1); 1.1528 + gfxQuaternion rotate2; 1.1529 + float shear2[3] = { 0.0f, 0.0f, 0.0f}; 1.1530 + 1.1531 + gfxMatrix matrix2d1, matrix2d2; 1.1532 + if (aMatrix1.Is2D(&matrix2d1) && aMatrix2.Is2D(&matrix2d2)) { 1.1533 + Decompose2DMatrix(matrix2d1, scale1, shear1, rotate1, translate1); 1.1534 + Decompose2DMatrix(matrix2d2, scale2, shear2, rotate2, translate2); 1.1535 + } else { 1.1536 + Decompose3DMatrix(aMatrix1, scale1, shear1, 1.1537 + rotate1, translate1, perspective1); 1.1538 + Decompose3DMatrix(aMatrix2, scale2, shear2, 1.1539 + rotate2, translate2, perspective2); 1.1540 + } 1.1541 + 1.1542 + // Interpolate each of the pieces 1.1543 + gfx3DMatrix result; 1.1544 + 1.1545 + gfxPointH3D perspective = 1.1546 + InterpolateNumerically(perspective1, perspective2, aProgress); 1.1547 + result.SetTransposedVector(3, perspective); 1.1548 + 1.1549 + gfxPoint3D translate = 1.1550 + InterpolateNumerically(translate1, translate2, aProgress); 1.1551 + result.Translate(translate); 1.1552 + 1.1553 + gfxQuaternion q3 = rotate1.Slerp(rotate2, aProgress); 1.1554 + gfx3DMatrix rotate = q3.ToMatrix(); 1.1555 + if (!rotate.IsIdentity()) { 1.1556 + result = rotate * result; 1.1557 + } 1.1558 + 1.1559 + // TODO: Would it be better to interpolate these as angles? How do we convert back to angles? 1.1560 + float yzshear = 1.1561 + InterpolateNumerically(shear1[YZSHEAR], shear2[YZSHEAR], aProgress); 1.1562 + if (yzshear != 0.0) { 1.1563 + result.SkewYZ(yzshear); 1.1564 + } 1.1565 + 1.1566 + float xzshear = 1.1567 + InterpolateNumerically(shear1[XZSHEAR], shear2[XZSHEAR], aProgress); 1.1568 + if (xzshear != 0.0) { 1.1569 + result.SkewXZ(xzshear); 1.1570 + } 1.1571 + 1.1572 + float xyshear = 1.1573 + InterpolateNumerically(shear1[XYSHEAR], shear2[XYSHEAR], aProgress); 1.1574 + if (xyshear != 0.0) { 1.1575 + result.SkewXY(xyshear); 1.1576 + } 1.1577 + 1.1578 + gfxPoint3D scale = 1.1579 + InterpolateNumerically(scale1, scale2, aProgress); 1.1580 + if (scale != gfxPoint3D(1.0, 1.0, 1.0)) { 1.1581 + result.Scale(scale.x, scale.y, scale.z); 1.1582 + } 1.1583 + 1.1584 + return result; 1.1585 +} 1.1586 + 1.1587 +static nsCSSValueList* 1.1588 +AddDifferentTransformLists(double aCoeff1, const nsCSSValueList* aList1, 1.1589 + double aCoeff2, const nsCSSValueList* aList2) 1.1590 +{ 1.1591 + nsAutoPtr<nsCSSValueList> result; 1.1592 + nsCSSValueList **resultTail = getter_Transfers(result); 1.1593 + 1.1594 + nsRefPtr<nsCSSValue::Array> arr; 1.1595 + arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_interpolatematrix, resultTail); 1.1596 + 1.1597 + // FIXME: We should change the other transform code to also only 1.1598 + // take a single progress value, as having values that don't 1.1599 + // sum to 1 doesn't make sense for these. 1.1600 + if (aList1 == aList2) { 1.1601 + arr->Item(1).Reset(); 1.1602 + } else { 1.1603 + aList1->CloneInto(arr->Item(1).SetListValue()); 1.1604 + } 1.1605 + 1.1606 + aList2->CloneInto(arr->Item(2).SetListValue()); 1.1607 + arr->Item(3).SetPercentValue(aCoeff2); 1.1608 + 1.1609 + return result.forget(); 1.1610 +} 1.1611 + 1.1612 +static bool 1.1613 +TransformFunctionsMatch(nsCSSKeyword func1, nsCSSKeyword func2) 1.1614 +{ 1.1615 + return ToPrimitive(func1) == ToPrimitive(func2); 1.1616 +} 1.1617 + 1.1618 +static bool 1.1619 +AddFilterFunctionImpl(double aCoeff1, const nsCSSValueList* aList1, 1.1620 + double aCoeff2, const nsCSSValueList* aList2, 1.1621 + nsCSSValueList**& aResultTail) 1.1622 +{ 1.1623 + // AddFilterFunction should be our only caller, and it should ensure that both 1.1624 + // args are non-null. 1.1625 + NS_ABORT_IF_FALSE(aList1, "expected filter list"); 1.1626 + NS_ABORT_IF_FALSE(aList2, "expected filter list"); 1.1627 + NS_ABORT_IF_FALSE(aList1->mValue.GetUnit() == eCSSUnit_Function, 1.1628 + "expected function"); 1.1629 + NS_ABORT_IF_FALSE(aList2->mValue.GetUnit() == eCSSUnit_Function, 1.1630 + "expected function"); 1.1631 + nsRefPtr<nsCSSValue::Array> a1 = aList1->mValue.GetArrayValue(), 1.1632 + a2 = aList2->mValue.GetArrayValue(); 1.1633 + nsCSSKeyword filterFunction = a1->Item(0).GetKeywordValue(); 1.1634 + if (filterFunction != a2->Item(0).GetKeywordValue()) 1.1635 + return false; // Can't add two filters of different types. 1.1636 + 1.1637 + nsAutoPtr<nsCSSValueList> resultListEntry(new nsCSSValueList); 1.1638 + nsCSSValue::Array* result = 1.1639 + resultListEntry->mValue.InitFunction(filterFunction, 1); 1.1640 + 1.1641 + // "hue-rotate" is the only filter-function that accepts negative values, and 1.1642 + // we don't use this "restrictions" variable in its clause below. 1.1643 + const uint32_t restrictions = CSS_PROPERTY_VALUE_NONNEGATIVE; 1.1644 + const nsCSSValue& funcArg1 = a1->Item(1); 1.1645 + const nsCSSValue& funcArg2 = a2->Item(1); 1.1646 + nsCSSValue& resultArg = result->Item(1); 1.1647 + float initialVal = 1.0f; 1.1648 + switch (filterFunction) { 1.1649 + case eCSSKeyword_blur: { 1.1650 + nsCSSUnit unit; 1.1651 + if (funcArg1.GetUnit() == funcArg2.GetUnit()) { 1.1652 + unit = funcArg1.GetUnit(); 1.1653 + } else { 1.1654 + // If units differ, we'll just combine them with calc(). 1.1655 + unit = eCSSUnit_Calc; 1.1656 + } 1.1657 + if (!AddCSSValuePixelPercentCalc(restrictions, 1.1658 + unit, 1.1659 + aCoeff1, funcArg1, 1.1660 + aCoeff2, funcArg2, 1.1661 + resultArg)) { 1.1662 + return false; 1.1663 + } 1.1664 + break; 1.1665 + } 1.1666 + case eCSSKeyword_grayscale: 1.1667 + case eCSSKeyword_invert: 1.1668 + case eCSSKeyword_sepia: 1.1669 + initialVal = 0.0f; 1.1670 + case eCSSKeyword_brightness: 1.1671 + case eCSSKeyword_contrast: 1.1672 + case eCSSKeyword_opacity: 1.1673 + case eCSSKeyword_saturate: 1.1674 + AddCSSValuePercentNumber(restrictions, 1.1675 + aCoeff1, funcArg1, 1.1676 + aCoeff2, funcArg2, 1.1677 + resultArg, 1.1678 + initialVal); 1.1679 + break; 1.1680 + case eCSSKeyword_hue_rotate: 1.1681 + AddCSSValueAngle(aCoeff1, funcArg1, 1.1682 + aCoeff2, funcArg2, 1.1683 + resultArg); 1.1684 + break; 1.1685 + case eCSSKeyword_drop_shadow: { 1.1686 + nsCSSValueList* resultShadow = resultArg.SetListValue(); 1.1687 + nsAutoPtr<nsCSSValueList> shadowValue; 1.1688 + nsCSSValueList **shadowTail = getter_Transfers(shadowValue); 1.1689 + NS_ABORT_IF_FALSE(!funcArg1.GetListValue()->mNext && 1.1690 + !funcArg2.GetListValue()->mNext, 1.1691 + "drop-shadow filter func doesn't support lists"); 1.1692 + if (!AddShadowItems(aCoeff1, funcArg1.GetListValue()->mValue, 1.1693 + aCoeff2, funcArg2.GetListValue()->mValue, 1.1694 + shadowTail)) { 1.1695 + return false; 1.1696 + } 1.1697 + *resultShadow = *shadowValue; 1.1698 + break; 1.1699 + } 1.1700 + default: 1.1701 + NS_ABORT_IF_FALSE(false, "unknown filter function"); 1.1702 + return false; 1.1703 + } 1.1704 + 1.1705 + *aResultTail = resultListEntry.forget(); 1.1706 + aResultTail = &(*aResultTail)->mNext; 1.1707 + 1.1708 + return true; 1.1709 +} 1.1710 + 1.1711 +static bool 1.1712 +AddFilterFunction(double aCoeff1, const nsCSSValueList* aList1, 1.1713 + double aCoeff2, const nsCSSValueList* aList2, 1.1714 + nsCSSValueList**& aResultTail) 1.1715 +{ 1.1716 + NS_ABORT_IF_FALSE(aList1 || aList2, 1.1717 + "one function list item must not be null"); 1.1718 + // Note that one of our arguments could be null, indicating that 1.1719 + // it's the initial value. Rather than adding special null-handling 1.1720 + // logic, we just check for null values and replace them with 1.1721 + // 0 * the other value. That way, AddFilterFunctionImpl can assume 1.1722 + // its args are non-null. 1.1723 + if (!aList1) { 1.1724 + return AddFilterFunctionImpl(aCoeff2, aList2, 0, aList2, aResultTail); 1.1725 + } 1.1726 + if (!aList2) { 1.1727 + return AddFilterFunctionImpl(aCoeff1, aList1, 0, aList1, aResultTail); 1.1728 + } 1.1729 + 1.1730 + return AddFilterFunctionImpl(aCoeff1, aList1, aCoeff2, aList2, aResultTail); 1.1731 +} 1.1732 + 1.1733 +static nsCSSValueList* 1.1734 +AddTransformLists(double aCoeff1, const nsCSSValueList* aList1, 1.1735 + double aCoeff2, const nsCSSValueList* aList2) 1.1736 +{ 1.1737 + nsAutoPtr<nsCSSValueList> result; 1.1738 + nsCSSValueList **resultTail = getter_Transfers(result); 1.1739 + 1.1740 + do { 1.1741 + nsRefPtr<nsCSSValue::Array> a1 = ToPrimitive(aList1->mValue.GetArrayValue()), 1.1742 + a2 = ToPrimitive(aList2->mValue.GetArrayValue()); 1.1743 + NS_ABORT_IF_FALSE(TransformFunctionsMatch(nsStyleTransformMatrix::TransformFunctionOf(a1), 1.1744 + nsStyleTransformMatrix::TransformFunctionOf(a2)), 1.1745 + "transform function mismatch"); 1.1746 + NS_ABORT_IF_FALSE(!*resultTail, 1.1747 + "resultTail isn't pointing to the tail (may leak)"); 1.1748 + 1.1749 + nsCSSKeyword tfunc = nsStyleTransformMatrix::TransformFunctionOf(a1); 1.1750 + nsRefPtr<nsCSSValue::Array> arr; 1.1751 + if (tfunc != eCSSKeyword_matrix && 1.1752 + tfunc != eCSSKeyword_matrix3d && 1.1753 + tfunc != eCSSKeyword_interpolatematrix && 1.1754 + tfunc != eCSSKeyword_rotate3d && 1.1755 + tfunc != eCSSKeyword_perspective) { 1.1756 + arr = nsStyleAnimation::AppendTransformFunction(tfunc, resultTail); 1.1757 + } 1.1758 + 1.1759 + switch (tfunc) { 1.1760 + case eCSSKeyword_translate3d: { 1.1761 + NS_ABORT_IF_FALSE(a1->Count() == 4, "unexpected count"); 1.1762 + NS_ABORT_IF_FALSE(a2->Count() == 4, "unexpected count"); 1.1763 + AddTransformTranslate(aCoeff1, a1->Item(1), aCoeff2, a2->Item(1), 1.1764 + arr->Item(1)); 1.1765 + AddTransformTranslate(aCoeff1, a1->Item(2), aCoeff2, a2->Item(2), 1.1766 + arr->Item(2)); 1.1767 + AddTransformTranslate(aCoeff1, a1->Item(3), aCoeff2, a2->Item(3), 1.1768 + arr->Item(3)); 1.1769 + break; 1.1770 + } 1.1771 + case eCSSKeyword_scale3d: { 1.1772 + NS_ABORT_IF_FALSE(a1->Count() == 4, "unexpected count"); 1.1773 + NS_ABORT_IF_FALSE(a2->Count() == 4, "unexpected count"); 1.1774 + 1.1775 + AddTransformScale(aCoeff1, a1->Item(1), aCoeff2, a2->Item(1), 1.1776 + arr->Item(1)); 1.1777 + AddTransformScale(aCoeff1, a1->Item(2), aCoeff2, a2->Item(2), 1.1778 + arr->Item(2)); 1.1779 + AddTransformScale(aCoeff1, a1->Item(3), aCoeff2, a2->Item(3), 1.1780 + arr->Item(3)); 1.1781 + 1.1782 + break; 1.1783 + } 1.1784 + // It would probably be nicer to animate skew in tangent space 1.1785 + // rather than angle space. However, it's easy to specify 1.1786 + // skews with infinite tangents, and behavior changes pretty 1.1787 + // drastically when crossing such skews (since the direction of 1.1788 + // animation flips), so interop is probably more important here. 1.1789 + case eCSSKeyword_skew: { 1.1790 + NS_ABORT_IF_FALSE(a1->Count() == 2 || a1->Count() == 3, 1.1791 + "unexpected count"); 1.1792 + NS_ABORT_IF_FALSE(a2->Count() == 2 || a2->Count() == 3, 1.1793 + "unexpected count"); 1.1794 + 1.1795 + nsCSSValue zero(0.0f, eCSSUnit_Radian); 1.1796 + // Add Y component of skew. 1.1797 + AddCSSValueAngle(aCoeff1, 1.1798 + a1->Count() == 3 ? a1->Item(2) : zero, 1.1799 + aCoeff2, 1.1800 + a2->Count() == 3 ? a2->Item(2) : zero, 1.1801 + arr->Item(2)); 1.1802 + 1.1803 + // Add X component of skew (which can be merged with case below 1.1804 + // in non-DEBUG). 1.1805 + AddCSSValueAngle(aCoeff1, a1->Item(1), aCoeff2, a2->Item(1), 1.1806 + arr->Item(1)); 1.1807 + 1.1808 + break; 1.1809 + } 1.1810 + case eCSSKeyword_skewx: 1.1811 + case eCSSKeyword_skewy: 1.1812 + case eCSSKeyword_rotate: 1.1813 + case eCSSKeyword_rotatex: 1.1814 + case eCSSKeyword_rotatey: 1.1815 + case eCSSKeyword_rotatez: { 1.1816 + NS_ABORT_IF_FALSE(a1->Count() == 2, "unexpected count"); 1.1817 + NS_ABORT_IF_FALSE(a2->Count() == 2, "unexpected count"); 1.1818 + 1.1819 + AddCSSValueAngle(aCoeff1, a1->Item(1), aCoeff2, a2->Item(1), 1.1820 + arr->Item(1)); 1.1821 + 1.1822 + break; 1.1823 + } 1.1824 + case eCSSKeyword_matrix: 1.1825 + case eCSSKeyword_matrix3d: 1.1826 + case eCSSKeyword_interpolatematrix: 1.1827 + case eCSSKeyword_rotate3d: 1.1828 + case eCSSKeyword_perspective: { 1.1829 + // FIXME: If the matrix contains only numbers then we could decompose 1.1830 + // here. 1.1831 + 1.1832 + // Construct temporary lists with only this item in them. 1.1833 + nsCSSValueList tempList1, tempList2; 1.1834 + tempList1.mValue = aList1->mValue; 1.1835 + tempList2.mValue = aList2->mValue; 1.1836 + 1.1837 + if (aList1 == aList2) { 1.1838 + *resultTail = 1.1839 + AddDifferentTransformLists(aCoeff1, &tempList1, aCoeff2, &tempList1); 1.1840 + } else { 1.1841 + *resultTail = 1.1842 + AddDifferentTransformLists(aCoeff1, &tempList1, aCoeff2, &tempList2); 1.1843 + } 1.1844 + 1.1845 + // Now advance resultTail to point to the new tail slot. 1.1846 + while (*resultTail) { 1.1847 + resultTail = &(*resultTail)->mNext; 1.1848 + } 1.1849 + 1.1850 + break; 1.1851 + } 1.1852 + default: 1.1853 + NS_ABORT_IF_FALSE(false, "unknown transform function"); 1.1854 + } 1.1855 + 1.1856 + aList1 = aList1->mNext; 1.1857 + aList2 = aList2->mNext; 1.1858 + } while (aList1); 1.1859 + NS_ABORT_IF_FALSE(!aList2, "list length mismatch"); 1.1860 + NS_ABORT_IF_FALSE(!*resultTail, 1.1861 + "resultTail isn't pointing to the tail"); 1.1862 + 1.1863 + return result.forget(); 1.1864 +} 1.1865 + 1.1866 +bool 1.1867 +nsStyleAnimation::AddWeighted(nsCSSProperty aProperty, 1.1868 + double aCoeff1, const Value& aValue1, 1.1869 + double aCoeff2, const Value& aValue2, 1.1870 + Value& aResultValue) 1.1871 +{ 1.1872 + Unit commonUnit = 1.1873 + GetCommonUnit(aProperty, aValue1.GetUnit(), aValue2.GetUnit()); 1.1874 + // Maybe need a followup method to convert the inputs into the common 1.1875 + // unit-type, if they don't already match it. (Or would it make sense to do 1.1876 + // that in GetCommonUnit? in which case maybe ConvertToCommonUnit would be 1.1877 + // better.) 1.1878 + 1.1879 + switch (commonUnit) { 1.1880 + case eUnit_Null: 1.1881 + case eUnit_Auto: 1.1882 + case eUnit_None: 1.1883 + case eUnit_Normal: 1.1884 + case eUnit_UnparsedString: 1.1885 + return false; 1.1886 + 1.1887 + case eUnit_Enumerated: 1.1888 + switch (aProperty) { 1.1889 + case eCSSProperty_font_stretch: { 1.1890 + // Animate just like eUnit_Integer. 1.1891 + int32_t result = floor(aCoeff1 * double(aValue1.GetIntValue()) + 1.1892 + aCoeff2 * double(aValue2.GetIntValue())); 1.1893 + if (result < NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED) { 1.1894 + result = NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED; 1.1895 + } else if (result > NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED) { 1.1896 + result = NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED; 1.1897 + } 1.1898 + aResultValue.SetIntValue(result, eUnit_Enumerated); 1.1899 + return true; 1.1900 + } 1.1901 + default: 1.1902 + return false; 1.1903 + } 1.1904 + case eUnit_Visibility: { 1.1905 + int32_t enum1 = aValue1.GetIntValue(); 1.1906 + int32_t enum2 = aValue2.GetIntValue(); 1.1907 + if (enum1 == enum2) { 1.1908 + aResultValue.SetIntValue(enum1, eUnit_Visibility); 1.1909 + return true; 1.1910 + } 1.1911 + if ((enum1 == NS_STYLE_VISIBILITY_VISIBLE) == 1.1912 + (enum2 == NS_STYLE_VISIBILITY_VISIBLE)) { 1.1913 + return false; 1.1914 + } 1.1915 + int32_t val1 = enum1 == NS_STYLE_VISIBILITY_VISIBLE; 1.1916 + int32_t val2 = enum2 == NS_STYLE_VISIBILITY_VISIBLE; 1.1917 + double interp = aCoeff1 * val1 + aCoeff2 * val2; 1.1918 + int32_t result = interp > 0.0 ? NS_STYLE_VISIBILITY_VISIBLE 1.1919 + : (val1 ? enum2 : enum1); 1.1920 + aResultValue.SetIntValue(result, eUnit_Visibility); 1.1921 + return true; 1.1922 + } 1.1923 + case eUnit_Integer: { 1.1924 + // http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types- 1.1925 + // says we should use floor 1.1926 + int32_t result = floor(aCoeff1 * double(aValue1.GetIntValue()) + 1.1927 + aCoeff2 * double(aValue2.GetIntValue())); 1.1928 + if (aProperty == eCSSProperty_font_weight) { 1.1929 + if (result < 100) { 1.1930 + result = 100; 1.1931 + } else if (result > 900) { 1.1932 + result = 900; 1.1933 + } 1.1934 + result -= result % 100; 1.1935 + } else { 1.1936 + result = RestrictValue(aProperty, result); 1.1937 + } 1.1938 + aResultValue.SetIntValue(result, eUnit_Integer); 1.1939 + return true; 1.1940 + } 1.1941 + case eUnit_Coord: { 1.1942 + aResultValue.SetCoordValue(RestrictValue(aProperty, NSToCoordRound( 1.1943 + aCoeff1 * aValue1.GetCoordValue() + 1.1944 + aCoeff2 * aValue2.GetCoordValue()))); 1.1945 + return true; 1.1946 + } 1.1947 + case eUnit_Percent: { 1.1948 + aResultValue.SetPercentValue(RestrictValue(aProperty, 1.1949 + aCoeff1 * aValue1.GetPercentValue() + 1.1950 + aCoeff2 * aValue2.GetPercentValue())); 1.1951 + return true; 1.1952 + } 1.1953 + case eUnit_Float: { 1.1954 + // Special case for flex-grow and flex-shrink: animations are 1.1955 + // disallowed between 0 and other values. 1.1956 + if ((aProperty == eCSSProperty_flex_grow || 1.1957 + aProperty == eCSSProperty_flex_shrink) && 1.1958 + (aValue1.GetFloatValue() == 0.0f || 1.1959 + aValue2.GetFloatValue() == 0.0f) && 1.1960 + aValue1.GetFloatValue() != aValue2.GetFloatValue()) { 1.1961 + return false; 1.1962 + } 1.1963 + 1.1964 + aResultValue.SetFloatValue(RestrictValue(aProperty, 1.1965 + aCoeff1 * aValue1.GetFloatValue() + 1.1966 + aCoeff2 * aValue2.GetFloatValue())); 1.1967 + return true; 1.1968 + } 1.1969 + case eUnit_Color: { 1.1970 + nscolor color1 = aValue1.GetColorValue(); 1.1971 + nscolor color2 = aValue2.GetColorValue(); 1.1972 + // FIXME (spec): The CSS transitions spec doesn't say whether 1.1973 + // colors are premultiplied, but things work better when they are, 1.1974 + // so use premultiplication. Spec issue is still open per 1.1975 + // http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html 1.1976 + 1.1977 + // To save some math, scale the alpha down to a 0-1 scale, but 1.1978 + // leave the color components on a 0-255 scale. 1.1979 + double A1 = NS_GET_A(color1) * (1.0 / 255.0); 1.1980 + double R1 = NS_GET_R(color1) * A1; 1.1981 + double G1 = NS_GET_G(color1) * A1; 1.1982 + double B1 = NS_GET_B(color1) * A1; 1.1983 + double A2 = NS_GET_A(color2) * (1.0 / 255.0); 1.1984 + double R2 = NS_GET_R(color2) * A2; 1.1985 + double G2 = NS_GET_G(color2) * A2; 1.1986 + double B2 = NS_GET_B(color2) * A2; 1.1987 + double Aresf = (A1 * aCoeff1 + A2 * aCoeff2); 1.1988 + nscolor resultColor; 1.1989 + if (Aresf <= 0.0) { 1.1990 + resultColor = NS_RGBA(0, 0, 0, 0); 1.1991 + } else { 1.1992 + if (Aresf > 1.0) { 1.1993 + Aresf = 1.0; 1.1994 + } 1.1995 + double factor = 1.0 / Aresf; 1.1996 + uint8_t Ares = NSToIntRound(Aresf * 255.0); 1.1997 + uint8_t Rres = ClampColor((R1 * aCoeff1 + R2 * aCoeff2) * factor); 1.1998 + uint8_t Gres = ClampColor((G1 * aCoeff1 + G2 * aCoeff2) * factor); 1.1999 + uint8_t Bres = ClampColor((B1 * aCoeff1 + B2 * aCoeff2) * factor); 1.2000 + resultColor = NS_RGBA(Rres, Gres, Bres, Ares); 1.2001 + } 1.2002 + aResultValue.SetColorValue(resultColor); 1.2003 + return true; 1.2004 + } 1.2005 + case eUnit_Calc: { 1.2006 + CalcValue v1 = ExtractCalcValue(aValue1); 1.2007 + CalcValue v2 = ExtractCalcValue(aValue2); 1.2008 + double len = aCoeff1 * v1.mLength + aCoeff2 * v2.mLength; 1.2009 + double pct = aCoeff1 * v1.mPercent + aCoeff2 * v2.mPercent; 1.2010 + bool hasPct = (aCoeff1 != 0.0 && v1.mHasPercent) || 1.2011 + (aCoeff2 != 0.0 && v2.mHasPercent); 1.2012 + nsCSSValue *val = new nsCSSValue(); 1.2013 + nsCSSValue::Array *arr = nsCSSValue::Array::Create(1); 1.2014 + val->SetArrayValue(arr, eCSSUnit_Calc); 1.2015 + if (hasPct) { 1.2016 + nsCSSValue::Array *arr2 = nsCSSValue::Array::Create(2); 1.2017 + arr2->Item(0).SetFloatValue(len, eCSSUnit_Pixel); 1.2018 + arr2->Item(1).SetPercentValue(pct); 1.2019 + arr->Item(0).SetArrayValue(arr2, eCSSUnit_Calc_Plus); 1.2020 + } else { 1.2021 + arr->Item(0).SetFloatValue(len, eCSSUnit_Pixel); 1.2022 + } 1.2023 + aResultValue.SetAndAdoptCSSValueValue(val, eUnit_Calc); 1.2024 + return true; 1.2025 + } 1.2026 + case eUnit_CSSValuePair: { 1.2027 + const nsCSSValuePair *pair1 = aValue1.GetCSSValuePairValue(); 1.2028 + const nsCSSValuePair *pair2 = aValue2.GetCSSValuePairValue(); 1.2029 + nsCSSUnit unit[2]; 1.2030 + unit[0] = GetCommonUnit(aProperty, pair1->mXValue.GetUnit(), 1.2031 + pair2->mXValue.GetUnit()); 1.2032 + unit[1] = GetCommonUnit(aProperty, pair1->mYValue.GetUnit(), 1.2033 + pair2->mYValue.GetUnit()); 1.2034 + if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null || 1.2035 + unit[0] == eCSSUnit_URL || unit[0] == eCSSUnit_Enumerated) { 1.2036 + return false; 1.2037 + } 1.2038 + 1.2039 + nsAutoPtr<nsCSSValuePair> result(new nsCSSValuePair); 1.2040 + static nsCSSValue nsCSSValuePair::* const pairValues[2] = { 1.2041 + &nsCSSValuePair::mXValue, &nsCSSValuePair::mYValue 1.2042 + }; 1.2043 + uint32_t restrictions = nsCSSProps::ValueRestrictions(aProperty); 1.2044 + for (uint32_t i = 0; i < 2; ++i) { 1.2045 + nsCSSValue nsCSSValuePair::*member = pairValues[i]; 1.2046 + if (!AddCSSValuePixelPercentCalc(restrictions, unit[i], 1.2047 + aCoeff1, pair1->*member, 1.2048 + aCoeff2, pair2->*member, 1.2049 + result->*member) ) { 1.2050 + NS_ABORT_IF_FALSE(false, "unexpected unit"); 1.2051 + return false; 1.2052 + } 1.2053 + } 1.2054 + 1.2055 + aResultValue.SetAndAdoptCSSValuePairValue(result.forget(), 1.2056 + eUnit_CSSValuePair); 1.2057 + return true; 1.2058 + } 1.2059 + case eUnit_CSSValueTriplet: { 1.2060 + nsCSSValueTriplet triplet1(*aValue1.GetCSSValueTripletValue()); 1.2061 + nsCSSValueTriplet triplet2(*aValue2.GetCSSValueTripletValue()); 1.2062 + 1.2063 + nsCSSUnit unit[3]; 1.2064 + unit[0] = GetCommonUnit(aProperty, triplet1.mXValue.GetUnit(), 1.2065 + triplet2.mXValue.GetUnit()); 1.2066 + unit[1] = GetCommonUnit(aProperty, triplet1.mYValue.GetUnit(), 1.2067 + triplet2.mYValue.GetUnit()); 1.2068 + unit[2] = GetCommonUnit(aProperty, triplet1.mZValue.GetUnit(), 1.2069 + triplet2.mZValue.GetUnit()); 1.2070 + if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null || 1.2071 + unit[2] == eCSSUnit_Null) { 1.2072 + return false; 1.2073 + } 1.2074 + 1.2075 + nsAutoPtr<nsCSSValueTriplet> result(new nsCSSValueTriplet); 1.2076 + static nsCSSValue nsCSSValueTriplet::* const tripletValues[3] = { 1.2077 + &nsCSSValueTriplet::mXValue, &nsCSSValueTriplet::mYValue, &nsCSSValueTriplet::mZValue 1.2078 + }; 1.2079 + uint32_t restrictions = nsCSSProps::ValueRestrictions(aProperty); 1.2080 + for (uint32_t i = 0; i < 3; ++i) { 1.2081 + nsCSSValue nsCSSValueTriplet::*member = tripletValues[i]; 1.2082 + if (!AddCSSValuePixelPercentCalc(restrictions, unit[i], 1.2083 + aCoeff1, &triplet1->*member, 1.2084 + aCoeff2, &triplet2->*member, 1.2085 + result->*member) ) { 1.2086 + NS_ABORT_IF_FALSE(false, "unexpected unit"); 1.2087 + return false; 1.2088 + } 1.2089 + } 1.2090 + 1.2091 + aResultValue.SetAndAdoptCSSValueTripletValue(result.forget(), 1.2092 + eUnit_CSSValueTriplet); 1.2093 + return true; 1.2094 + } 1.2095 + case eUnit_CSSRect: { 1.2096 + NS_ABORT_IF_FALSE(nsCSSProps::ValueRestrictions(aProperty) == 0, 1.2097 + "must add code for handling value restrictions"); 1.2098 + const nsCSSRect *rect1 = aValue1.GetCSSRectValue(); 1.2099 + const nsCSSRect *rect2 = aValue2.GetCSSRectValue(); 1.2100 + if (rect1->mTop.GetUnit() != rect2->mTop.GetUnit() || 1.2101 + rect1->mRight.GetUnit() != rect2->mRight.GetUnit() || 1.2102 + rect1->mBottom.GetUnit() != rect2->mBottom.GetUnit() || 1.2103 + rect1->mLeft.GetUnit() != rect2->mLeft.GetUnit()) { 1.2104 + // At least until we have calc() 1.2105 + return false; 1.2106 + } 1.2107 + 1.2108 + nsAutoPtr<nsCSSRect> result(new nsCSSRect); 1.2109 + for (uint32_t i = 0; i < ArrayLength(nsCSSRect::sides); ++i) { 1.2110 + nsCSSValue nsCSSRect::*member = nsCSSRect::sides[i]; 1.2111 + NS_ABORT_IF_FALSE((rect1->*member).GetUnit() == 1.2112 + (rect2->*member).GetUnit(), 1.2113 + "should have returned above"); 1.2114 + switch ((rect1->*member).GetUnit()) { 1.2115 + case eCSSUnit_Pixel: 1.2116 + AddCSSValuePixel(aCoeff1, rect1->*member, aCoeff2, rect2->*member, 1.2117 + result->*member); 1.2118 + break; 1.2119 + case eCSSUnit_Auto: 1.2120 + if (float(aCoeff1 + aCoeff2) != 1.0f) { 1.2121 + // Interpolating between two auto values makes sense; 1.2122 + // adding in other ratios does not. 1.2123 + return false; 1.2124 + } 1.2125 + (result->*member).SetAutoValue(); 1.2126 + break; 1.2127 + default: 1.2128 + NS_ABORT_IF_FALSE(false, "unexpected unit"); 1.2129 + return false; 1.2130 + } 1.2131 + } 1.2132 + 1.2133 + aResultValue.SetAndAdoptCSSRectValue(result.forget(), eUnit_CSSRect); 1.2134 + return true; 1.2135 + } 1.2136 + case eUnit_Dasharray: { 1.2137 + const nsCSSValueList *list1 = aValue1.GetCSSValueListValue(); 1.2138 + const nsCSSValueList *list2 = aValue2.GetCSSValueListValue(); 1.2139 + 1.2140 + uint32_t len1 = 0, len2 = 0; 1.2141 + for (const nsCSSValueList *v = list1; v; v = v->mNext) { 1.2142 + ++len1; 1.2143 + } 1.2144 + for (const nsCSSValueList *v = list2; v; v = v->mNext) { 1.2145 + ++len2; 1.2146 + } 1.2147 + NS_ABORT_IF_FALSE(len1 > 0 && len2 > 0, "unexpected length"); 1.2148 + if (list1->mValue.GetUnit() == eCSSUnit_None || 1.2149 + list2->mValue.GetUnit() == eCSSUnit_None) { 1.2150 + // One of our values is "none". Can't do addition with that. 1.2151 + NS_ABORT_IF_FALSE( 1.2152 + (list1->mValue.GetUnit() != eCSSUnit_None || len1 == 1) && 1.2153 + (list2->mValue.GetUnit() != eCSSUnit_None || len2 == 1), 1.2154 + "multi-value valuelist with 'none' as first element"); 1.2155 + return false; 1.2156 + } 1.2157 + 1.2158 + nsAutoPtr<nsCSSValueList> result; 1.2159 + nsCSSValueList **resultTail = getter_Transfers(result); 1.2160 + for (uint32_t i = 0, i_end = EuclidLCM<uint32_t>(len1, len2); i != i_end; ++i) { 1.2161 + const nsCSSValue &v1 = list1->mValue; 1.2162 + const nsCSSValue &v2 = list2->mValue; 1.2163 + NS_ABORT_IF_FALSE(v1.GetUnit() == eCSSUnit_Number || 1.2164 + v1.GetUnit() == eCSSUnit_Percent, "unexpected"); 1.2165 + NS_ABORT_IF_FALSE(v2.GetUnit() == eCSSUnit_Number || 1.2166 + v2.GetUnit() == eCSSUnit_Percent, "unexpected"); 1.2167 + if (v1.GetUnit() != v2.GetUnit()) { 1.2168 + // Can't animate between lengths and percentages (until calc()). 1.2169 + return false; 1.2170 + } 1.2171 + 1.2172 + nsCSSValueList *item = new nsCSSValueList; 1.2173 + if (!item) { 1.2174 + return false; 1.2175 + } 1.2176 + *resultTail = item; 1.2177 + resultTail = &item->mNext; 1.2178 + 1.2179 + if (v1.GetUnit() == eCSSUnit_Number) { 1.2180 + AddCSSValueNumber(aCoeff1, v1, aCoeff2, v2, item->mValue, 1.2181 + CSS_PROPERTY_VALUE_NONNEGATIVE); 1.2182 + } else { 1.2183 + AddCSSValuePercent(aCoeff1, v1, aCoeff2, v2, item->mValue, 1.2184 + CSS_PROPERTY_VALUE_NONNEGATIVE); 1.2185 + } 1.2186 + 1.2187 + list1 = list1->mNext; 1.2188 + if (!list1) { 1.2189 + list1 = aValue1.GetCSSValueListValue(); 1.2190 + } 1.2191 + list2 = list2->mNext; 1.2192 + if (!list2) { 1.2193 + list2 = aValue2.GetCSSValueListValue(); 1.2194 + } 1.2195 + } 1.2196 + 1.2197 + aResultValue.SetAndAdoptCSSValueListValue(result.forget(), 1.2198 + eUnit_Dasharray); 1.2199 + return true; 1.2200 + } 1.2201 + case eUnit_Shadow: { 1.2202 + // This is implemented according to: 1.2203 + // http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types- 1.2204 + // and the third item in the summary of: 1.2205 + // http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html 1.2206 + const nsCSSValueList *shadow1 = aValue1.GetCSSValueListValue(); 1.2207 + const nsCSSValueList *shadow2 = aValue2.GetCSSValueListValue(); 1.2208 + nsAutoPtr<nsCSSValueList> result; 1.2209 + nsCSSValueList **resultTail = getter_Transfers(result); 1.2210 + while (shadow1 && shadow2) { 1.2211 + if (!AddShadowItems(aCoeff1, shadow1->mValue, 1.2212 + aCoeff2, shadow2->mValue, 1.2213 + resultTail)) { 1.2214 + return false; 1.2215 + } 1.2216 + shadow1 = shadow1->mNext; 1.2217 + shadow2 = shadow2->mNext; 1.2218 + } 1.2219 + if (shadow1 || shadow2) { 1.2220 + const nsCSSValueList *longShadow; 1.2221 + double longCoeff; 1.2222 + if (shadow1) { 1.2223 + longShadow = shadow1; 1.2224 + longCoeff = aCoeff1; 1.2225 + } else { 1.2226 + longShadow = shadow2; 1.2227 + longCoeff = aCoeff2; 1.2228 + } 1.2229 + 1.2230 + while (longShadow) { 1.2231 + // Passing coefficients that add to less than 1 produces the 1.2232 + // desired result of interpolating "0 0 0 transparent" with 1.2233 + // the current shadow. 1.2234 + if (!AddShadowItems(longCoeff, longShadow->mValue, 1.2235 + 0.0, longShadow->mValue, 1.2236 + resultTail)) { 1.2237 + return false; 1.2238 + } 1.2239 + 1.2240 + longShadow = longShadow->mNext; 1.2241 + } 1.2242 + } 1.2243 + aResultValue.SetAndAdoptCSSValueListValue(result.forget(), eUnit_Shadow); 1.2244 + return true; 1.2245 + } 1.2246 + 1.2247 + case eUnit_Filter: { 1.2248 + const nsCSSValueList *list1 = aValue1.GetCSSValueListValue(); 1.2249 + const nsCSSValueList *list2 = aValue2.GetCSSValueListValue(); 1.2250 + 1.2251 + nsAutoPtr<nsCSSValueList> result; 1.2252 + nsCSSValueList **resultTail = getter_Transfers(result); 1.2253 + while (list1 || list2) { 1.2254 + NS_ABORT_IF_FALSE(!*resultTail, 1.2255 + "resultTail isn't pointing to the tail (may leak)"); 1.2256 + if ((list1 && list1->mValue.GetUnit() != eCSSUnit_Function) || 1.2257 + (list2 && list2->mValue.GetUnit() != eCSSUnit_Function)) { 1.2258 + // If we don't have filter-functions, we must have filter-URLs, which 1.2259 + // we can't add or interpolate. 1.2260 + return false; 1.2261 + } 1.2262 + 1.2263 + if (!AddFilterFunction(aCoeff1, list1, aCoeff2, list2, resultTail)) { 1.2264 + // filter function mismatch 1.2265 + return false; 1.2266 + } 1.2267 + 1.2268 + // move to next list items 1.2269 + if (list1) { 1.2270 + list1 = list1->mNext; 1.2271 + } 1.2272 + if (list2) { 1.2273 + list2 = list2->mNext; 1.2274 + } 1.2275 + } 1.2276 + NS_ABORT_IF_FALSE(!*resultTail, 1.2277 + "resultTail isn't pointing to the tail (may leak)"); 1.2278 + 1.2279 + aResultValue.SetAndAdoptCSSValueListValue(result.forget(), 1.2280 + eUnit_Filter); 1.2281 + return true; 1.2282 + } 1.2283 + 1.2284 + case eUnit_Transform: { 1.2285 + const nsCSSValueList* list1 = aValue1.GetCSSValueSharedListValue()->mHead; 1.2286 + const nsCSSValueList* list2 = aValue2.GetCSSValueSharedListValue()->mHead; 1.2287 + 1.2288 + MOZ_ASSERT(list1); 1.2289 + MOZ_ASSERT(list2); 1.2290 + 1.2291 + // We want to avoid the matrix decomposition when we can, since 1.2292 + // avoiding it can produce better results both for compound 1.2293 + // transforms and for skew and skewY (see below). We can do this 1.2294 + // in two cases: 1.2295 + // (1) if one of the transforms is 'none' 1.2296 + // (2) if the lists have the same length and the transform 1.2297 + // functions match 1.2298 + nsAutoPtr<nsCSSValueList> result; 1.2299 + if (list1->mValue.GetUnit() == eCSSUnit_None) { 1.2300 + if (list2->mValue.GetUnit() == eCSSUnit_None) { 1.2301 + result = new nsCSSValueList; 1.2302 + if (result) { 1.2303 + result->mValue.SetNoneValue(); 1.2304 + } 1.2305 + } else { 1.2306 + result = AddTransformLists(0, list2, aCoeff2, list2); 1.2307 + } 1.2308 + } else { 1.2309 + if (list2->mValue.GetUnit() == eCSSUnit_None) { 1.2310 + result = AddTransformLists(0, list1, aCoeff1, list1); 1.2311 + } else { 1.2312 + bool match = true; 1.2313 + 1.2314 + { 1.2315 + const nsCSSValueList *item1 = list1, *item2 = list2; 1.2316 + do { 1.2317 + nsCSSKeyword func1 = nsStyleTransformMatrix::TransformFunctionOf( 1.2318 + item1->mValue.GetArrayValue()); 1.2319 + nsCSSKeyword func2 = nsStyleTransformMatrix::TransformFunctionOf( 1.2320 + item2->mValue.GetArrayValue()); 1.2321 + 1.2322 + if (!TransformFunctionsMatch(func1, func2)) { 1.2323 + break; 1.2324 + } 1.2325 + 1.2326 + item1 = item1->mNext; 1.2327 + item2 = item2->mNext; 1.2328 + } while (item1 && item2); 1.2329 + if (item1 || item2) { 1.2330 + // Either |break| above or length mismatch. 1.2331 + match = false; 1.2332 + } 1.2333 + } 1.2334 + 1.2335 + if (match) { 1.2336 + result = AddTransformLists(aCoeff1, list1, aCoeff2, list2); 1.2337 + } else { 1.2338 + result = AddDifferentTransformLists(aCoeff1, list1, aCoeff2, list2); 1.2339 + } 1.2340 + } 1.2341 + } 1.2342 + 1.2343 + aResultValue.SetTransformValue(new nsCSSValueSharedList(result.forget())); 1.2344 + return true; 1.2345 + } 1.2346 + case eUnit_BackgroundPosition: { 1.2347 + const nsCSSValueList *position1 = aValue1.GetCSSValueListValue(); 1.2348 + const nsCSSValueList *position2 = aValue2.GetCSSValueListValue(); 1.2349 + nsAutoPtr<nsCSSValueList> result; 1.2350 + nsCSSValueList **resultTail = getter_Transfers(result); 1.2351 + while (position1 && position2) { 1.2352 + nsCSSValueList *item = new nsCSSValueList; 1.2353 + if (!item) { 1.2354 + return false; 1.2355 + } 1.2356 + *resultTail = item; 1.2357 + resultTail = &item->mNext; 1.2358 + 1.2359 + nsCSSValue::Array* bgPos1 = position1->mValue.GetArrayValue(); 1.2360 + nsCSSValue::Array* bgPos2 = position2->mValue.GetArrayValue(); 1.2361 + nsCSSValue::Array* bgPosRes = nsCSSValue::Array::Create(4); 1.2362 + item->mValue.SetArrayValue(bgPosRes, eCSSUnit_Array); 1.2363 + 1.2364 + uint32_t restrictions = nsCSSProps::ValueRestrictions(aProperty); 1.2365 + 1.2366 + /* Only iterate over elements 1 and 3. The background position is 1.2367 + * 'uncomputed' to only those elements. 1.2368 + */ 1.2369 + for (int i = 1; i < 4; i+=2) { 1.2370 + const nsCSSValue& v1 = bgPos1->Item(i); 1.2371 + const nsCSSValue& v2 = bgPos2->Item(i); 1.2372 + nsCSSValue& vr = bgPosRes->Item(i); 1.2373 + 1.2374 + nsCSSUnit unit = GetCommonUnit(aProperty, v1.GetUnit(), v2.GetUnit()); 1.2375 + 1.2376 + if (!AddCSSValuePixelPercentCalc(restrictions, unit, aCoeff1, v1, 1.2377 + aCoeff2, v2, vr) ) { 1.2378 + if (v1 != v2) { 1.2379 + return false; 1.2380 + } 1.2381 + vr = v1; 1.2382 + } 1.2383 + } 1.2384 + 1.2385 + position1 = position1->mNext; 1.2386 + position2 = position2->mNext; 1.2387 + } 1.2388 + 1.2389 + // Check for different lengths 1.2390 + if (position1 || position2) { 1.2391 + return false; 1.2392 + } 1.2393 + 1.2394 + aResultValue.SetAndAdoptCSSValueListValue(result.forget(), 1.2395 + eUnit_BackgroundPosition); 1.2396 + return true; 1.2397 + } 1.2398 + case eUnit_CSSValuePairList: { 1.2399 + const nsCSSValuePairList *list1 = aValue1.GetCSSValuePairListValue(); 1.2400 + const nsCSSValuePairList *list2 = aValue2.GetCSSValuePairListValue(); 1.2401 + nsAutoPtr<nsCSSValuePairList> result; 1.2402 + nsCSSValuePairList **resultTail = getter_Transfers(result); 1.2403 + do { 1.2404 + nsCSSValuePairList *item = new nsCSSValuePairList; 1.2405 + if (!item) { 1.2406 + return false; 1.2407 + } 1.2408 + *resultTail = item; 1.2409 + resultTail = &item->mNext; 1.2410 + 1.2411 + static nsCSSValue nsCSSValuePairList::* const pairListValues[] = { 1.2412 + &nsCSSValuePairList::mXValue, 1.2413 + &nsCSSValuePairList::mYValue, 1.2414 + }; 1.2415 + uint32_t restrictions = nsCSSProps::ValueRestrictions(aProperty); 1.2416 + for (uint32_t i = 0; i < ArrayLength(pairListValues); ++i) { 1.2417 + const nsCSSValue &v1 = list1->*(pairListValues[i]); 1.2418 + const nsCSSValue &v2 = list2->*(pairListValues[i]); 1.2419 + nsCSSValue &vr = item->*(pairListValues[i]); 1.2420 + nsCSSUnit unit = 1.2421 + GetCommonUnit(aProperty, v1.GetUnit(), v2.GetUnit()); 1.2422 + if (unit == eCSSUnit_Null) { 1.2423 + return false; 1.2424 + } 1.2425 + if (!AddCSSValuePixelPercentCalc(restrictions, unit, aCoeff1, v1, 1.2426 + aCoeff2, v2, vr) ) { 1.2427 + if (v1 != v2) { 1.2428 + return false; 1.2429 + } 1.2430 + vr = v1; 1.2431 + } 1.2432 + } 1.2433 + list1 = list1->mNext; 1.2434 + list2 = list2->mNext; 1.2435 + } while (list1 && list2); 1.2436 + if (list1 || list2) { 1.2437 + // We can't interpolate lists of different lengths. 1.2438 + return false; 1.2439 + } 1.2440 + 1.2441 + aResultValue.SetAndAdoptCSSValuePairListValue(result.forget()); 1.2442 + return true; 1.2443 + } 1.2444 + } 1.2445 + 1.2446 + NS_ABORT_IF_FALSE(false, "Can't interpolate using the given common unit"); 1.2447 + return false; 1.2448 +} 1.2449 + 1.2450 +already_AddRefed<css::StyleRule> 1.2451 +BuildStyleRule(nsCSSProperty aProperty, 1.2452 + dom::Element* aTargetElement, 1.2453 + const nsAString& aSpecifiedValue, 1.2454 + bool aUseSVGMode) 1.2455 +{ 1.2456 + // Set up an empty CSS Declaration 1.2457 + nsAutoPtr<css::Declaration> declaration(new css::Declaration()); 1.2458 + declaration->InitializeEmpty(); 1.2459 + 1.2460 + bool changed; // ignored, but needed as outparam for ParseProperty 1.2461 + nsIDocument* doc = aTargetElement->OwnerDoc(); 1.2462 + nsCOMPtr<nsIURI> baseURI = aTargetElement->GetBaseURI(); 1.2463 + nsCSSParser parser(doc->CSSLoader()); 1.2464 + 1.2465 + nsCSSProperty propertyToCheck = nsCSSProps::IsShorthand(aProperty) ? 1.2466 + nsCSSProps::SubpropertyEntryFor(aProperty)[0] : aProperty; 1.2467 + 1.2468 + // Get a parser, parse the property, and check for CSS parsing errors. 1.2469 + // If any of these steps fails, we bail out and delete the declaration. 1.2470 + if (NS_FAILED(parser.ParseProperty(aProperty, aSpecifiedValue, 1.2471 + doc->GetDocumentURI(), baseURI, 1.2472 + aTargetElement->NodePrincipal(), 1.2473 + declaration, &changed, false, 1.2474 + aUseSVGMode)) || 1.2475 + // check whether property parsed without CSS parsing errors 1.2476 + !declaration->HasNonImportantValueFor(propertyToCheck)) { 1.2477 + NS_WARNING("failure in BuildStyleRule"); 1.2478 + return nullptr; 1.2479 + } 1.2480 + 1.2481 + nsRefPtr<css::StyleRule> rule = new css::StyleRule(nullptr, declaration.forget()); 1.2482 + return rule.forget(); 1.2483 +} 1.2484 + 1.2485 +inline 1.2486 +already_AddRefed<nsStyleContext> 1.2487 +LookupStyleContext(dom::Element* aElement) 1.2488 +{ 1.2489 + nsIDocument* doc = aElement->GetCurrentDoc(); 1.2490 + nsIPresShell* shell = doc->GetShell(); 1.2491 + if (!shell) { 1.2492 + return nullptr; 1.2493 + } 1.2494 + return nsComputedDOMStyle::GetStyleContextForElement(aElement, nullptr, shell); 1.2495 +} 1.2496 + 1.2497 +bool 1.2498 +nsStyleAnimation::ComputeValue(nsCSSProperty aProperty, 1.2499 + dom::Element* aTargetElement, 1.2500 + const nsAString& aSpecifiedValue, 1.2501 + bool aUseSVGMode, 1.2502 + Value& aComputedValue, 1.2503 + bool* aIsContextSensitive) 1.2504 +{ 1.2505 + NS_ABORT_IF_FALSE(aTargetElement, "null target element"); 1.2506 + NS_ABORT_IF_FALSE(aTargetElement->GetCurrentDoc(), 1.2507 + "we should only be able to actively animate nodes that " 1.2508 + "are in a document"); 1.2509 + 1.2510 + nsCSSProperty propToParse = 1.2511 + nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_REPORT_OTHER_NAME) 1.2512 + ? nsCSSProps::OtherNameFor(aProperty) : aProperty; 1.2513 + 1.2514 + // Parse specified value into a temporary css::StyleRule 1.2515 + nsRefPtr<css::StyleRule> styleRule = 1.2516 + BuildStyleRule(propToParse, aTargetElement, aSpecifiedValue, aUseSVGMode); 1.2517 + if (!styleRule) { 1.2518 + return false; 1.2519 + } 1.2520 + 1.2521 + if (nsCSSProps::IsShorthand(aProperty) || 1.2522 + nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) { 1.2523 + // Just capture the specified value 1.2524 + aComputedValue.SetUnparsedStringValue(nsString(aSpecifiedValue)); 1.2525 + if (aIsContextSensitive) { 1.2526 + // Since we're just returning the string as-is, aComputedValue isn't going 1.2527 + // to change depending on the context 1.2528 + *aIsContextSensitive = false; 1.2529 + } 1.2530 + return true; 1.2531 + } 1.2532 + 1.2533 + // Look up style context for our target element 1.2534 + nsRefPtr<nsStyleContext> styleContext = LookupStyleContext(aTargetElement); 1.2535 + if (!styleContext) { 1.2536 + return false; 1.2537 + } 1.2538 + nsStyleSet* styleSet = styleContext->PresContext()->StyleSet(); 1.2539 + 1.2540 + nsRefPtr<nsStyleContext> tmpStyleContext; 1.2541 + if (aIsContextSensitive) { 1.2542 + nsCOMArray<nsIStyleRule> ruleArray; 1.2543 + ruleArray.AppendObject(styleSet->InitialStyleRule()); 1.2544 + ruleArray.AppendObject(styleRule); 1.2545 + styleRule->RuleMatched(); 1.2546 + tmpStyleContext = 1.2547 + styleSet->ResolveStyleByAddingRules(styleContext, ruleArray); 1.2548 + if (!tmpStyleContext) { 1.2549 + return false; 1.2550 + } 1.2551 + 1.2552 + // Force walk of rule tree 1.2553 + nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty]; 1.2554 + tmpStyleContext->StyleData(sid); 1.2555 + 1.2556 + // If the rule node will have cached style data if the value is not 1.2557 + // context-sensitive. So if there's nothing cached, it's not context 1.2558 + // sensitive. 1.2559 + *aIsContextSensitive = 1.2560 + !tmpStyleContext->RuleNode()->NodeHasCachedData(sid); 1.2561 + } 1.2562 + 1.2563 + // If we're not concerned whether the property is context sensitive then just 1.2564 + // add the rule to a new temporary style context alongside the target 1.2565 + // element's style context. 1.2566 + // Also, if we previously discovered that this property IS context-sensitive 1.2567 + // then we need to throw the temporary style context out since the property's 1.2568 + // value may have been biased by the 'initial' values supplied. 1.2569 + if (!aIsContextSensitive || *aIsContextSensitive) { 1.2570 + nsCOMArray<nsIStyleRule> ruleArray; 1.2571 + ruleArray.AppendObject(styleRule); 1.2572 + styleRule->RuleMatched(); 1.2573 + tmpStyleContext = 1.2574 + styleSet->ResolveStyleByAddingRules(styleContext, ruleArray); 1.2575 + if (!tmpStyleContext) { 1.2576 + return false; 1.2577 + } 1.2578 + } 1.2579 + 1.2580 + // Extract computed value of our property from the temporary style rule 1.2581 + return ExtractComputedValue(aProperty, tmpStyleContext, aComputedValue); 1.2582 +} 1.2583 + 1.2584 +bool 1.2585 +nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty, 1.2586 + const Value& aComputedValue, 1.2587 + nsCSSValue& aSpecifiedValue) 1.2588 +{ 1.2589 + switch (aComputedValue.GetUnit()) { 1.2590 + case eUnit_Normal: 1.2591 + aSpecifiedValue.SetNormalValue(); 1.2592 + break; 1.2593 + case eUnit_Auto: 1.2594 + aSpecifiedValue.SetAutoValue(); 1.2595 + break; 1.2596 + case eUnit_None: 1.2597 + aSpecifiedValue.SetNoneValue(); 1.2598 + break; 1.2599 + case eUnit_Enumerated: 1.2600 + case eUnit_Visibility: 1.2601 + aSpecifiedValue. 1.2602 + SetIntValue(aComputedValue.GetIntValue(), eCSSUnit_Enumerated); 1.2603 + break; 1.2604 + case eUnit_Integer: 1.2605 + aSpecifiedValue. 1.2606 + SetIntValue(aComputedValue.GetIntValue(), eCSSUnit_Integer); 1.2607 + break; 1.2608 + case eUnit_Coord: 1.2609 + nscoordToCSSValue(aComputedValue.GetCoordValue(), aSpecifiedValue); 1.2610 + break; 1.2611 + case eUnit_Percent: 1.2612 + aSpecifiedValue.SetPercentValue(aComputedValue.GetPercentValue()); 1.2613 + break; 1.2614 + case eUnit_Float: 1.2615 + aSpecifiedValue. 1.2616 + SetFloatValue(aComputedValue.GetFloatValue(), eCSSUnit_Number); 1.2617 + break; 1.2618 + case eUnit_Color: 1.2619 + // colors can be alone, or part of a paint server 1.2620 + aSpecifiedValue.SetColorValue(aComputedValue.GetColorValue()); 1.2621 + break; 1.2622 + case eUnit_Calc: { 1.2623 + nsCSSValue *val = aComputedValue.GetCSSValueValue(); 1.2624 + NS_ABORT_IF_FALSE(val->GetUnit() == eCSSUnit_Calc, "unexpected unit"); 1.2625 + aSpecifiedValue = *val; 1.2626 + break; 1.2627 + } 1.2628 + case eUnit_CSSValuePair: { 1.2629 + // Rule node processing expects pair values to be collapsed to a 1.2630 + // single value if both halves would be equal, for most but not 1.2631 + // all properties. At present, all animatable properties that 1.2632 + // use pairs do expect collapsing. 1.2633 + const nsCSSValuePair* pair = aComputedValue.GetCSSValuePairValue(); 1.2634 + if (pair->mXValue == pair->mYValue) { 1.2635 + aSpecifiedValue = pair->mXValue; 1.2636 + } else { 1.2637 + aSpecifiedValue.SetPairValue(pair); 1.2638 + } 1.2639 + } break; 1.2640 + case eUnit_CSSValueTriplet: { 1.2641 + // Rule node processing expects triplet values to be collapsed to a 1.2642 + // single value if both halves would be equal, for most but not 1.2643 + // all properties. At present, all animatable properties that 1.2644 + // use pairs do expect collapsing. 1.2645 + const nsCSSValueTriplet* triplet = aComputedValue.GetCSSValueTripletValue(); 1.2646 + if (triplet->mXValue == triplet->mYValue && triplet->mYValue == triplet->mZValue) { 1.2647 + aSpecifiedValue = triplet->mXValue; 1.2648 + } else { 1.2649 + aSpecifiedValue.SetTripletValue(triplet); 1.2650 + } 1.2651 + } break; 1.2652 + case eUnit_CSSRect: { 1.2653 + nsCSSRect& rect = aSpecifiedValue.SetRectValue(); 1.2654 + rect = *aComputedValue.GetCSSRectValue(); 1.2655 + } break; 1.2656 + case eUnit_Dasharray: 1.2657 + case eUnit_Shadow: 1.2658 + case eUnit_Filter: 1.2659 + case eUnit_BackgroundPosition: 1.2660 + aSpecifiedValue. 1.2661 + SetDependentListValue(aComputedValue.GetCSSValueListValue()); 1.2662 + break; 1.2663 + case eUnit_Transform: 1.2664 + aSpecifiedValue. 1.2665 + SetSharedListValue(aComputedValue.GetCSSValueSharedListValue()); 1.2666 + break; 1.2667 + case eUnit_CSSValuePairList: 1.2668 + aSpecifiedValue. 1.2669 + SetDependentPairListValue(aComputedValue.GetCSSValuePairListValue()); 1.2670 + break; 1.2671 + default: 1.2672 + return false; 1.2673 + } 1.2674 + return true; 1.2675 +} 1.2676 + 1.2677 +bool 1.2678 +nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty, 1.2679 + const Value& aComputedValue, 1.2680 + nsAString& aSpecifiedValue) 1.2681 +{ 1.2682 + aSpecifiedValue.Truncate(); // Clear outparam, if it's not already empty 1.2683 + 1.2684 + if (aComputedValue.GetUnit() == eUnit_UnparsedString) { 1.2685 + aComputedValue.GetStringValue(aSpecifiedValue); 1.2686 + return true; 1.2687 + } 1.2688 + nsCSSValue val; 1.2689 + if (!nsStyleAnimation::UncomputeValue(aProperty, aComputedValue, val)) { 1.2690 + return false; 1.2691 + } 1.2692 + 1.2693 + val.AppendToString(aProperty, aSpecifiedValue, nsCSSValue::eNormalized); 1.2694 + return true; 1.2695 +} 1.2696 + 1.2697 +inline const void* 1.2698 +StyleDataAtOffset(const void* aStyleStruct, ptrdiff_t aOffset) 1.2699 +{ 1.2700 + return reinterpret_cast<const char*>(aStyleStruct) + aOffset; 1.2701 +} 1.2702 + 1.2703 +inline void* 1.2704 +StyleDataAtOffset(void* aStyleStruct, ptrdiff_t aOffset) 1.2705 +{ 1.2706 + return reinterpret_cast<char*>(aStyleStruct) + aOffset; 1.2707 +} 1.2708 + 1.2709 +static void 1.2710 +ExtractBorderColor(nsStyleContext* aStyleContext, const void* aStyleBorder, 1.2711 + mozilla::css::Side aSide, nsStyleAnimation::Value& aComputedValue) 1.2712 +{ 1.2713 + nscolor color; 1.2714 + bool foreground; 1.2715 + static_cast<const nsStyleBorder*>(aStyleBorder)-> 1.2716 + GetBorderColor(aSide, color, foreground); 1.2717 + if (foreground) { 1.2718 + // FIXME: should add test for this 1.2719 + color = aStyleContext->StyleColor()->mColor; 1.2720 + } 1.2721 + aComputedValue.SetColorValue(color); 1.2722 +} 1.2723 + 1.2724 +static bool 1.2725 +StyleCoordToValue(const nsStyleCoord& aCoord, nsStyleAnimation::Value& aValue) 1.2726 +{ 1.2727 + switch (aCoord.GetUnit()) { 1.2728 + case eStyleUnit_Normal: 1.2729 + aValue.SetNormalValue(); 1.2730 + break; 1.2731 + case eStyleUnit_Auto: 1.2732 + aValue.SetAutoValue(); 1.2733 + break; 1.2734 + case eStyleUnit_None: 1.2735 + aValue.SetNoneValue(); 1.2736 + break; 1.2737 + case eStyleUnit_Percent: 1.2738 + aValue.SetPercentValue(aCoord.GetPercentValue()); 1.2739 + break; 1.2740 + case eStyleUnit_Factor: 1.2741 + aValue.SetFloatValue(aCoord.GetFactorValue()); 1.2742 + break; 1.2743 + case eStyleUnit_Coord: 1.2744 + aValue.SetCoordValue(aCoord.GetCoordValue()); 1.2745 + break; 1.2746 + case eStyleUnit_Enumerated: 1.2747 + aValue.SetIntValue(aCoord.GetIntValue(), 1.2748 + nsStyleAnimation::eUnit_Enumerated); 1.2749 + break; 1.2750 + case eStyleUnit_Integer: 1.2751 + aValue.SetIntValue(aCoord.GetIntValue(), 1.2752 + nsStyleAnimation::eUnit_Integer); 1.2753 + break; 1.2754 + case eStyleUnit_Calc: { 1.2755 + nsAutoPtr<nsCSSValue> val(new nsCSSValue); 1.2756 + SetCalcValue(aCoord.GetCalcValue(), *val); 1.2757 + aValue.SetAndAdoptCSSValueValue(val.forget(), 1.2758 + nsStyleAnimation::eUnit_Calc); 1.2759 + break; 1.2760 + } 1.2761 + default: 1.2762 + return false; 1.2763 + } 1.2764 + return true; 1.2765 +} 1.2766 + 1.2767 +static bool 1.2768 +StyleCoordToCSSValue(const nsStyleCoord& aCoord, nsCSSValue& aCSSValue) 1.2769 +{ 1.2770 + switch (aCoord.GetUnit()) { 1.2771 + case eStyleUnit_Coord: 1.2772 + nscoordToCSSValue(aCoord.GetCoordValue(), aCSSValue); 1.2773 + break; 1.2774 + case eStyleUnit_Factor: 1.2775 + aCSSValue.SetFloatValue(aCoord.GetFactorValue(), eCSSUnit_Number); 1.2776 + break; 1.2777 + case eStyleUnit_Percent: 1.2778 + aCSSValue.SetPercentValue(aCoord.GetPercentValue()); 1.2779 + break; 1.2780 + case eStyleUnit_Calc: 1.2781 + SetCalcValue(aCoord.GetCalcValue(), aCSSValue); 1.2782 + break; 1.2783 + case eStyleUnit_Degree: 1.2784 + aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Degree); 1.2785 + break; 1.2786 + case eStyleUnit_Grad: 1.2787 + aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Grad); 1.2788 + break; 1.2789 + case eStyleUnit_Radian: 1.2790 + aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Radian); 1.2791 + break; 1.2792 + case eStyleUnit_Turn: 1.2793 + aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Turn); 1.2794 + break; 1.2795 + default: 1.2796 + NS_ABORT_IF_FALSE(false, "unexpected unit"); 1.2797 + return false; 1.2798 + } 1.2799 + return true; 1.2800 +} 1.2801 + 1.2802 +/* 1.2803 + * Assign |aOutput = aInput|, except with any non-pixel lengths 1.2804 + * replaced with the equivalent in pixels, and any non-canonical calc() 1.2805 + * expressions replaced with canonical ones. 1.2806 + */ 1.2807 +static void 1.2808 +SubstitutePixelValues(nsStyleContext* aStyleContext, 1.2809 + const nsCSSValue& aInput, nsCSSValue& aOutput) 1.2810 +{ 1.2811 + if (aInput.IsCalcUnit()) { 1.2812 + bool canStoreInRuleTree = true; 1.2813 + nsRuleNode::ComputedCalc c = 1.2814 + nsRuleNode::SpecifiedCalcToComputedCalc(aInput, aStyleContext, 1.2815 + aStyleContext->PresContext(), 1.2816 + canStoreInRuleTree); 1.2817 + nsStyleCoord::Calc c2; 1.2818 + c2.mLength = c.mLength; 1.2819 + c2.mPercent = c.mPercent; 1.2820 + c2.mHasPercent = true; // doesn't matter for transform translate 1.2821 + SetCalcValue(&c2, aOutput); 1.2822 + } else if (aInput.UnitHasArrayValue()) { 1.2823 + const nsCSSValue::Array *inputArray = aInput.GetArrayValue(); 1.2824 + nsRefPtr<nsCSSValue::Array> outputArray = 1.2825 + nsCSSValue::Array::Create(inputArray->Count()); 1.2826 + for (size_t i = 0, i_end = inputArray->Count(); i < i_end; ++i) { 1.2827 + SubstitutePixelValues(aStyleContext, 1.2828 + inputArray->Item(i), outputArray->Item(i)); 1.2829 + } 1.2830 + aOutput.SetArrayValue(outputArray, aInput.GetUnit()); 1.2831 + } else if (aInput.IsLengthUnit() && 1.2832 + aInput.GetUnit() != eCSSUnit_Pixel) { 1.2833 + bool canStoreInRuleTree = true; 1.2834 + nscoord len = nsRuleNode::CalcLength(aInput, aStyleContext, 1.2835 + aStyleContext->PresContext(), 1.2836 + canStoreInRuleTree); 1.2837 + aOutput.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(len), 1.2838 + eCSSUnit_Pixel); 1.2839 + } else { 1.2840 + aOutput = aInput; 1.2841 + } 1.2842 +} 1.2843 + 1.2844 +bool 1.2845 +nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty, 1.2846 + nsStyleContext* aStyleContext, 1.2847 + Value& aComputedValue) 1.2848 +{ 1.2849 + NS_ABORT_IF_FALSE(0 <= aProperty && 1.2850 + aProperty < eCSSProperty_COUNT_no_shorthands, 1.2851 + "bad property"); 1.2852 + const void* styleStruct = 1.2853 + aStyleContext->StyleData(nsCSSProps::kSIDTable[aProperty]); 1.2854 + ptrdiff_t ssOffset = nsCSSProps::kStyleStructOffsetTable[aProperty]; 1.2855 + nsStyleAnimType animType = nsCSSProps::kAnimTypeTable[aProperty]; 1.2856 + NS_ABORT_IF_FALSE(0 <= ssOffset || animType == eStyleAnimType_Custom, 1.2857 + "must be dealing with animatable property"); 1.2858 + switch (animType) { 1.2859 + case eStyleAnimType_Custom: 1.2860 + switch (aProperty) { 1.2861 + // For border-width, ignore the border-image business (which 1.2862 + // only exists until we update our implementation to the current 1.2863 + // spec) and use GetComputedBorder 1.2864 + 1.2865 + #define BORDER_WIDTH_CASE(prop_, side_) \ 1.2866 + case prop_: \ 1.2867 + aComputedValue.SetCoordValue( \ 1.2868 + static_cast<const nsStyleBorder*>(styleStruct)-> \ 1.2869 + GetComputedBorder().side_); \ 1.2870 + break; 1.2871 + BORDER_WIDTH_CASE(eCSSProperty_border_bottom_width, bottom) 1.2872 + BORDER_WIDTH_CASE(eCSSProperty_border_left_width_value, left) 1.2873 + BORDER_WIDTH_CASE(eCSSProperty_border_right_width_value, right) 1.2874 + BORDER_WIDTH_CASE(eCSSProperty_border_top_width, top) 1.2875 + #undef BORDER_WIDTH_CASE 1.2876 + 1.2877 + case eCSSProperty__moz_column_rule_width: 1.2878 + aComputedValue.SetCoordValue( 1.2879 + static_cast<const nsStyleColumn*>(styleStruct)-> 1.2880 + GetComputedColumnRuleWidth()); 1.2881 + break; 1.2882 + 1.2883 + case eCSSProperty_border_bottom_color: 1.2884 + ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_BOTTOM, 1.2885 + aComputedValue); 1.2886 + break; 1.2887 + case eCSSProperty_border_left_color_value: 1.2888 + ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_LEFT, 1.2889 + aComputedValue); 1.2890 + break; 1.2891 + case eCSSProperty_border_right_color_value: 1.2892 + ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_RIGHT, 1.2893 + aComputedValue); 1.2894 + break; 1.2895 + case eCSSProperty_border_top_color: 1.2896 + ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_TOP, 1.2897 + aComputedValue); 1.2898 + break; 1.2899 + 1.2900 + case eCSSProperty_outline_color: { 1.2901 + const nsStyleOutline *styleOutline = 1.2902 + static_cast<const nsStyleOutline*>(styleStruct); 1.2903 + nscolor color; 1.2904 + if (!styleOutline->GetOutlineColor(color)) 1.2905 + color = aStyleContext->StyleColor()->mColor; 1.2906 + aComputedValue.SetColorValue(color); 1.2907 + break; 1.2908 + } 1.2909 + 1.2910 + case eCSSProperty__moz_column_rule_color: { 1.2911 + const nsStyleColumn *styleColumn = 1.2912 + static_cast<const nsStyleColumn*>(styleStruct); 1.2913 + nscolor color; 1.2914 + if (styleColumn->mColumnRuleColorIsForeground) { 1.2915 + color = aStyleContext->StyleColor()->mColor; 1.2916 + } else { 1.2917 + color = styleColumn->mColumnRuleColor; 1.2918 + } 1.2919 + aComputedValue.SetColorValue(color); 1.2920 + break; 1.2921 + } 1.2922 + 1.2923 + case eCSSProperty__moz_column_count: { 1.2924 + const nsStyleColumn *styleColumn = 1.2925 + static_cast<const nsStyleColumn*>(styleStruct); 1.2926 + if (styleColumn->mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) { 1.2927 + aComputedValue.SetAutoValue(); 1.2928 + } else { 1.2929 + aComputedValue.SetIntValue(styleColumn->mColumnCount, 1.2930 + eUnit_Integer); 1.2931 + } 1.2932 + break; 1.2933 + } 1.2934 + 1.2935 + case eCSSProperty_order: { 1.2936 + const nsStylePosition *stylePosition = 1.2937 + static_cast<const nsStylePosition*>(styleStruct); 1.2938 + aComputedValue.SetIntValue(stylePosition->mOrder, 1.2939 + eUnit_Integer); 1.2940 + break; 1.2941 + } 1.2942 + 1.2943 + case eCSSProperty_text_decoration_color: { 1.2944 + const nsStyleTextReset *styleTextReset = 1.2945 + static_cast<const nsStyleTextReset*>(styleStruct); 1.2946 + nscolor color; 1.2947 + bool isForeground; 1.2948 + styleTextReset->GetDecorationColor(color, isForeground); 1.2949 + if (isForeground) { 1.2950 + color = aStyleContext->StyleColor()->mColor; 1.2951 + } 1.2952 + aComputedValue.SetColorValue(color); 1.2953 + break; 1.2954 + } 1.2955 + 1.2956 + case eCSSProperty_text_decoration_style: { 1.2957 + uint8_t decorationStyle = 1.2958 + static_cast<const nsStyleTextReset*>(styleStruct)-> 1.2959 + GetDecorationStyle(); 1.2960 + aComputedValue.SetIntValue(decorationStyle, eUnit_Enumerated); 1.2961 + break; 1.2962 + } 1.2963 + 1.2964 + case eCSSProperty_border_spacing: { 1.2965 + const nsStyleTableBorder *styleTableBorder = 1.2966 + static_cast<const nsStyleTableBorder*>(styleStruct); 1.2967 + nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair); 1.2968 + if (!pair) { 1.2969 + return false; 1.2970 + } 1.2971 + nscoordToCSSValue(styleTableBorder->mBorderSpacingX, pair->mXValue); 1.2972 + nscoordToCSSValue(styleTableBorder->mBorderSpacingY, pair->mYValue); 1.2973 + aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(), 1.2974 + eUnit_CSSValuePair); 1.2975 + break; 1.2976 + } 1.2977 + 1.2978 + case eCSSProperty_transform_origin: { 1.2979 + const nsStyleDisplay *styleDisplay = 1.2980 + static_cast<const nsStyleDisplay*>(styleStruct); 1.2981 + nsAutoPtr<nsCSSValueTriplet> triplet(new nsCSSValueTriplet); 1.2982 + if (!triplet || 1.2983 + !StyleCoordToCSSValue(styleDisplay->mTransformOrigin[0], 1.2984 + triplet->mXValue) || 1.2985 + !StyleCoordToCSSValue(styleDisplay->mTransformOrigin[1], 1.2986 + triplet->mYValue) || 1.2987 + !StyleCoordToCSSValue(styleDisplay->mTransformOrigin[2], 1.2988 + triplet->mZValue)) { 1.2989 + return false; 1.2990 + } 1.2991 + aComputedValue.SetAndAdoptCSSValueTripletValue(triplet.forget(), 1.2992 + eUnit_CSSValueTriplet); 1.2993 + break; 1.2994 + } 1.2995 + 1.2996 + case eCSSProperty_perspective_origin: { 1.2997 + const nsStyleDisplay *styleDisplay = 1.2998 + static_cast<const nsStyleDisplay*>(styleStruct); 1.2999 + nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair); 1.3000 + if (!pair || 1.3001 + !StyleCoordToCSSValue(styleDisplay->mPerspectiveOrigin[0], 1.3002 + pair->mXValue) || 1.3003 + !StyleCoordToCSSValue(styleDisplay->mPerspectiveOrigin[1], 1.3004 + pair->mYValue)) { 1.3005 + return false; 1.3006 + } 1.3007 + aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(), 1.3008 + eUnit_CSSValuePair); 1.3009 + break; 1.3010 + } 1.3011 + 1.3012 + case eCSSProperty_stroke_dasharray: { 1.3013 + const nsStyleSVG *svg = static_cast<const nsStyleSVG*>(styleStruct); 1.3014 + NS_ABORT_IF_FALSE((svg->mStrokeDasharray != nullptr) == 1.3015 + (svg->mStrokeDasharrayLength != 0), 1.3016 + "pointer/length mismatch"); 1.3017 + nsAutoPtr<nsCSSValueList> result; 1.3018 + if (svg->mStrokeDasharray) { 1.3019 + NS_ABORT_IF_FALSE(svg->mStrokeDasharrayLength > 0, 1.3020 + "non-null list should have positive length"); 1.3021 + nsCSSValueList **resultTail = getter_Transfers(result); 1.3022 + for (uint32_t i = 0, i_end = svg->mStrokeDasharrayLength; 1.3023 + i != i_end; ++i) { 1.3024 + nsCSSValueList *item = new nsCSSValueList; 1.3025 + if (!item) { 1.3026 + return false; 1.3027 + } 1.3028 + *resultTail = item; 1.3029 + resultTail = &item->mNext; 1.3030 + 1.3031 + const nsStyleCoord &coord = svg->mStrokeDasharray[i]; 1.3032 + nsCSSValue &value = item->mValue; 1.3033 + switch (coord.GetUnit()) { 1.3034 + case eStyleUnit_Coord: 1.3035 + // Number means the same thing as length; we want to 1.3036 + // animate them the same way. Normalize both to number 1.3037 + // since it has more accuracy (float vs nscoord). 1.3038 + value.SetFloatValue(nsPresContext:: 1.3039 + AppUnitsToFloatCSSPixels(coord.GetCoordValue()), 1.3040 + eCSSUnit_Number); 1.3041 + break; 1.3042 + case eStyleUnit_Factor: 1.3043 + value.SetFloatValue(coord.GetFactorValue(), 1.3044 + eCSSUnit_Number); 1.3045 + break; 1.3046 + case eStyleUnit_Percent: 1.3047 + value.SetPercentValue(coord.GetPercentValue()); 1.3048 + break; 1.3049 + default: 1.3050 + NS_ABORT_IF_FALSE(false, "unexpected unit"); 1.3051 + return false; 1.3052 + } 1.3053 + } 1.3054 + } else { 1.3055 + result = new nsCSSValueList; 1.3056 + if (!result) { 1.3057 + return false; 1.3058 + } 1.3059 + result->mValue.SetNoneValue(); 1.3060 + } 1.3061 + aComputedValue.SetAndAdoptCSSValueListValue(result.forget(), 1.3062 + eUnit_Dasharray); 1.3063 + break; 1.3064 + } 1.3065 + 1.3066 + case eCSSProperty_font_stretch: { 1.3067 + int16_t stretch = 1.3068 + static_cast<const nsStyleFont*>(styleStruct)->mFont.stretch; 1.3069 + static_assert(NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED == -4 && 1.3070 + NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED == 4, 1.3071 + "font stretch constants not as expected"); 1.3072 + if (stretch < NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED || 1.3073 + stretch > NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED) { 1.3074 + return false; 1.3075 + } 1.3076 + aComputedValue.SetIntValue(stretch, eUnit_Enumerated); 1.3077 + return true; 1.3078 + } 1.3079 + 1.3080 + case eCSSProperty_font_weight: { 1.3081 + uint16_t weight = 1.3082 + static_cast<const nsStyleFont*>(styleStruct)->mFont.weight; 1.3083 + if (weight % 100 != 0) { 1.3084 + return false; 1.3085 + } 1.3086 + aComputedValue.SetIntValue(weight, eUnit_Integer); 1.3087 + return true; 1.3088 + } 1.3089 + 1.3090 + case eCSSProperty_image_region: { 1.3091 + const nsStyleList *list = 1.3092 + static_cast<const nsStyleList*>(styleStruct); 1.3093 + const nsRect &srect = list->mImageRegion; 1.3094 + if (srect.IsEmpty()) { 1.3095 + aComputedValue.SetAutoValue(); 1.3096 + break; 1.3097 + } 1.3098 + 1.3099 + nsCSSRect *vrect = new nsCSSRect; 1.3100 + nscoordToCSSValue(srect.x, vrect->mLeft); 1.3101 + nscoordToCSSValue(srect.y, vrect->mTop); 1.3102 + nscoordToCSSValue(srect.XMost(), vrect->mRight); 1.3103 + nscoordToCSSValue(srect.YMost(), vrect->mBottom); 1.3104 + aComputedValue.SetAndAdoptCSSRectValue(vrect, eUnit_CSSRect); 1.3105 + break; 1.3106 + } 1.3107 + 1.3108 + case eCSSProperty_clip: { 1.3109 + const nsStyleDisplay *display = 1.3110 + static_cast<const nsStyleDisplay*>(styleStruct); 1.3111 + if (!(display->mClipFlags & NS_STYLE_CLIP_RECT)) { 1.3112 + aComputedValue.SetAutoValue(); 1.3113 + } else { 1.3114 + nsCSSRect *vrect = new nsCSSRect; 1.3115 + const nsRect &srect = display->mClip; 1.3116 + if (display->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) { 1.3117 + vrect->mTop.SetAutoValue(); 1.3118 + } else { 1.3119 + nscoordToCSSValue(srect.y, vrect->mTop); 1.3120 + } 1.3121 + if (display->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) { 1.3122 + vrect->mRight.SetAutoValue(); 1.3123 + } else { 1.3124 + nscoordToCSSValue(srect.XMost(), vrect->mRight); 1.3125 + } 1.3126 + if (display->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) { 1.3127 + vrect->mBottom.SetAutoValue(); 1.3128 + } else { 1.3129 + nscoordToCSSValue(srect.YMost(), vrect->mBottom); 1.3130 + } 1.3131 + if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) { 1.3132 + vrect->mLeft.SetAutoValue(); 1.3133 + } else { 1.3134 + nscoordToCSSValue(srect.x, vrect->mLeft); 1.3135 + } 1.3136 + aComputedValue.SetAndAdoptCSSRectValue(vrect, eUnit_CSSRect); 1.3137 + } 1.3138 + break; 1.3139 + } 1.3140 + 1.3141 + case eCSSProperty_background_position: { 1.3142 + const nsStyleBackground *bg = 1.3143 + static_cast<const nsStyleBackground*>(styleStruct); 1.3144 + nsAutoPtr<nsCSSValueList> result; 1.3145 + nsCSSValueList **resultTail = getter_Transfers(result); 1.3146 + NS_ABORT_IF_FALSE(bg->mPositionCount > 0, "unexpected count"); 1.3147 + for (uint32_t i = 0, i_end = bg->mPositionCount; i != i_end; ++i) { 1.3148 + nsCSSValueList *item = new nsCSSValueList; 1.3149 + *resultTail = item; 1.3150 + resultTail = &item->mNext; 1.3151 + nsRefPtr<nsCSSValue::Array> bgArray = nsCSSValue::Array::Create(4); 1.3152 + item->mValue.SetArrayValue(bgArray.get(), eCSSUnit_Array); 1.3153 + 1.3154 + const nsStyleBackground::Position &pos = bg->mLayers[i].mPosition; 1.3155 + // XXXbz is there a good reason we can't just 1.3156 + // SetCalcValue(&pos.mXPosition, item->mXValue) here? 1.3157 + nsCSSValue &xValue = bgArray->Item(1), 1.3158 + &yValue = bgArray->Item(3); 1.3159 + if (!pos.mXPosition.mHasPercent) { 1.3160 + NS_ABORT_IF_FALSE(pos.mXPosition.mPercent == 0.0f, 1.3161 + "Shouldn't have mPercent!"); 1.3162 + nscoordToCSSValue(pos.mXPosition.mLength, xValue); 1.3163 + } else if (pos.mXPosition.mLength == 0) { 1.3164 + xValue.SetPercentValue(pos.mXPosition.mPercent); 1.3165 + } else { 1.3166 + SetCalcValue(&pos.mXPosition, xValue); 1.3167 + } 1.3168 + 1.3169 + if (!pos.mYPosition.mHasPercent) { 1.3170 + NS_ABORT_IF_FALSE(pos.mYPosition.mPercent == 0.0f, 1.3171 + "Shouldn't have mPercent!"); 1.3172 + nscoordToCSSValue(pos.mYPosition.mLength, yValue); 1.3173 + } else if (pos.mYPosition.mLength == 0) { 1.3174 + yValue.SetPercentValue(pos.mYPosition.mPercent); 1.3175 + } else { 1.3176 + SetCalcValue(&pos.mYPosition, yValue); 1.3177 + } 1.3178 + } 1.3179 + 1.3180 + aComputedValue.SetAndAdoptCSSValueListValue(result.forget(), 1.3181 + eUnit_BackgroundPosition); 1.3182 + break; 1.3183 + } 1.3184 + 1.3185 + case eCSSProperty_background_size: { 1.3186 + const nsStyleBackground *bg = 1.3187 + static_cast<const nsStyleBackground*>(styleStruct); 1.3188 + nsAutoPtr<nsCSSValuePairList> result; 1.3189 + nsCSSValuePairList **resultTail = getter_Transfers(result); 1.3190 + NS_ABORT_IF_FALSE(bg->mSizeCount > 0, "unexpected count"); 1.3191 + for (uint32_t i = 0, i_end = bg->mSizeCount; i != i_end; ++i) { 1.3192 + nsCSSValuePairList *item = new nsCSSValuePairList; 1.3193 + *resultTail = item; 1.3194 + resultTail = &item->mNext; 1.3195 + 1.3196 + const nsStyleBackground::Size &size = bg->mLayers[i].mSize; 1.3197 + switch (size.mWidthType) { 1.3198 + case nsStyleBackground::Size::eContain: 1.3199 + case nsStyleBackground::Size::eCover: 1.3200 + item->mXValue.SetIntValue(size.mWidthType, 1.3201 + eCSSUnit_Enumerated); 1.3202 + break; 1.3203 + case nsStyleBackground::Size::eAuto: 1.3204 + item->mXValue.SetAutoValue(); 1.3205 + break; 1.3206 + case nsStyleBackground::Size::eLengthPercentage: 1.3207 + // XXXbz is there a good reason we can't just 1.3208 + // SetCalcValue(&size.mWidth, item->mXValue) here? 1.3209 + if (!size.mWidth.mHasPercent && 1.3210 + // negative values must have come from calc() 1.3211 + size.mWidth.mLength >= 0) { 1.3212 + NS_ABORT_IF_FALSE(size.mWidth.mPercent == 0.0f, 1.3213 + "Shouldn't have mPercent"); 1.3214 + nscoordToCSSValue(size.mWidth.mLength, item->mXValue); 1.3215 + } else if (size.mWidth.mLength == 0 && 1.3216 + // negative values must have come from calc() 1.3217 + size.mWidth.mPercent >= 0.0f) { 1.3218 + item->mXValue.SetPercentValue(size.mWidth.mPercent); 1.3219 + } else { 1.3220 + SetCalcValue(&size.mWidth, item->mXValue); 1.3221 + } 1.3222 + break; 1.3223 + } 1.3224 + 1.3225 + switch (size.mHeightType) { 1.3226 + case nsStyleBackground::Size::eContain: 1.3227 + case nsStyleBackground::Size::eCover: 1.3228 + // leave it null 1.3229 + break; 1.3230 + case nsStyleBackground::Size::eAuto: 1.3231 + item->mYValue.SetAutoValue(); 1.3232 + break; 1.3233 + case nsStyleBackground::Size::eLengthPercentage: 1.3234 + // XXXbz is there a good reason we can't just 1.3235 + // SetCalcValue(&size.mHeight, item->mYValue) here? 1.3236 + if (!size.mHeight.mHasPercent && 1.3237 + // negative values must have come from calc() 1.3238 + size.mHeight.mLength >= 0) { 1.3239 + NS_ABORT_IF_FALSE(size.mHeight.mPercent == 0.0f, 1.3240 + "Shouldn't have mPercent"); 1.3241 + nscoordToCSSValue(size.mHeight.mLength, item->mYValue); 1.3242 + } else if (size.mHeight.mLength == 0 && 1.3243 + // negative values must have come from calc() 1.3244 + size.mHeight.mPercent >= 0.0f) { 1.3245 + item->mYValue.SetPercentValue(size.mHeight.mPercent); 1.3246 + } else { 1.3247 + SetCalcValue(&size.mHeight, item->mYValue); 1.3248 + } 1.3249 + break; 1.3250 + } 1.3251 + } 1.3252 + 1.3253 + aComputedValue.SetAndAdoptCSSValuePairListValue(result.forget()); 1.3254 + break; 1.3255 + } 1.3256 + 1.3257 + case eCSSProperty_filter: { 1.3258 + const nsStyleSVGReset *svgReset = 1.3259 + static_cast<const nsStyleSVGReset*>(styleStruct); 1.3260 + const nsTArray<nsStyleFilter>& filters = svgReset->mFilters; 1.3261 + nsAutoPtr<nsCSSValueList> result; 1.3262 + nsCSSValueList **resultTail = getter_Transfers(result); 1.3263 + for (uint32_t i = 0; i < filters.Length(); ++i) { 1.3264 + nsCSSValueList *item = new nsCSSValueList; 1.3265 + *resultTail = item; 1.3266 + resultTail = &item->mNext; 1.3267 + const nsStyleFilter& filter = filters[i]; 1.3268 + int32_t type = filter.GetType(); 1.3269 + if (type == NS_STYLE_FILTER_URL) { 1.3270 + nsIDocument* doc = aStyleContext->PresContext()->Document(); 1.3271 + nsRefPtr<nsStringBuffer> uriAsStringBuffer = 1.3272 + GetURIAsUtf16StringBuffer(filter.GetURL()); 1.3273 + nsRefPtr<mozilla::css::URLValue> url = 1.3274 + new mozilla::css::URLValue(filter.GetURL(), 1.3275 + uriAsStringBuffer, 1.3276 + doc->GetDocumentURI(), 1.3277 + doc->NodePrincipal()); 1.3278 + item->mValue.SetURLValue(url); 1.3279 + } else { 1.3280 + nsCSSKeyword functionName = 1.3281 + nsCSSProps::ValueToKeywordEnum(type, 1.3282 + nsCSSProps::kFilterFunctionKTable); 1.3283 + nsCSSValue::Array* filterArray = 1.3284 + item->mValue.InitFunction(functionName, 1); 1.3285 + if (type >= NS_STYLE_FILTER_BLUR && type <= NS_STYLE_FILTER_HUE_ROTATE) { 1.3286 + if (!StyleCoordToCSSValue( 1.3287 + filter.GetFilterParameter(), 1.3288 + filterArray->Item(1))) { 1.3289 + return false; 1.3290 + } 1.3291 + } else if (type == NS_STYLE_FILTER_DROP_SHADOW) { 1.3292 + nsCSSValueList* shadowResult = filterArray->Item(1).SetListValue(); 1.3293 + nsAutoPtr<nsCSSValueList> tmpShadowValue; 1.3294 + nsCSSValueList **tmpShadowResultTail = getter_Transfers(tmpShadowValue); 1.3295 + nsCSSShadowArray* shadowArray = filter.GetDropShadow(); 1.3296 + NS_ABORT_IF_FALSE(shadowArray->Length() == 1, 1.3297 + "expected exactly one shadow"); 1.3298 + AppendCSSShadowValue(shadowArray->ShadowAt(0), tmpShadowResultTail); 1.3299 + *shadowResult = *tmpShadowValue; 1.3300 + } else { 1.3301 + // We checked all possible nsStyleFilter types but 1.3302 + // NS_STYLE_FILTER_NULL before. We should never enter this path. 1.3303 + NS_NOTREACHED("no other filter functions defined"); 1.3304 + return false; 1.3305 + } 1.3306 + } 1.3307 + } 1.3308 + 1.3309 + aComputedValue.SetAndAdoptCSSValueListValue(result.forget(), 1.3310 + eUnit_Filter); 1.3311 + break; 1.3312 + } 1.3313 + 1.3314 + case eCSSProperty_transform: { 1.3315 + const nsStyleDisplay *display = 1.3316 + static_cast<const nsStyleDisplay*>(styleStruct); 1.3317 + nsAutoPtr<nsCSSValueList> result; 1.3318 + if (display->mSpecifiedTransform) { 1.3319 + // Clone, and convert all lengths (not percents) to pixels. 1.3320 + nsCSSValueList **resultTail = getter_Transfers(result); 1.3321 + for (const nsCSSValueList *l = display->mSpecifiedTransform->mHead; 1.3322 + l; l = l->mNext) { 1.3323 + nsCSSValueList *clone = new nsCSSValueList; 1.3324 + *resultTail = clone; 1.3325 + resultTail = &clone->mNext; 1.3326 + 1.3327 + SubstitutePixelValues(aStyleContext, l->mValue, clone->mValue); 1.3328 + } 1.3329 + } else { 1.3330 + result = new nsCSSValueList(); 1.3331 + result->mValue.SetNoneValue(); 1.3332 + } 1.3333 + 1.3334 + aComputedValue.SetTransformValue( 1.3335 + new nsCSSValueSharedList(result.forget())); 1.3336 + break; 1.3337 + } 1.3338 + 1.3339 + default: 1.3340 + NS_ABORT_IF_FALSE(false, "missing property implementation"); 1.3341 + return false; 1.3342 + }; 1.3343 + return true; 1.3344 + case eStyleAnimType_Coord: 1.3345 + return StyleCoordToValue(*static_cast<const nsStyleCoord*>( 1.3346 + StyleDataAtOffset(styleStruct, ssOffset)), aComputedValue); 1.3347 + case eStyleAnimType_Sides_Top: 1.3348 + case eStyleAnimType_Sides_Right: 1.3349 + case eStyleAnimType_Sides_Bottom: 1.3350 + case eStyleAnimType_Sides_Left: { 1.3351 + static_assert( 1.3352 + NS_SIDE_TOP == eStyleAnimType_Sides_Top -eStyleAnimType_Sides_Top && 1.3353 + NS_SIDE_RIGHT == eStyleAnimType_Sides_Right -eStyleAnimType_Sides_Top && 1.3354 + NS_SIDE_BOTTOM == eStyleAnimType_Sides_Bottom-eStyleAnimType_Sides_Top && 1.3355 + NS_SIDE_LEFT == eStyleAnimType_Sides_Left -eStyleAnimType_Sides_Top, 1.3356 + "box side constants out of sync with animation side constants"); 1.3357 + 1.3358 + const nsStyleCoord &coord = static_cast<const nsStyleSides*>( 1.3359 + StyleDataAtOffset(styleStruct, ssOffset))-> 1.3360 + Get(mozilla::css::Side(animType - eStyleAnimType_Sides_Top)); 1.3361 + return StyleCoordToValue(coord, aComputedValue); 1.3362 + } 1.3363 + case eStyleAnimType_Corner_TopLeft: 1.3364 + case eStyleAnimType_Corner_TopRight: 1.3365 + case eStyleAnimType_Corner_BottomRight: 1.3366 + case eStyleAnimType_Corner_BottomLeft: { 1.3367 + static_assert( 1.3368 + NS_CORNER_TOP_LEFT == eStyleAnimType_Corner_TopLeft - 1.3369 + eStyleAnimType_Corner_TopLeft && 1.3370 + NS_CORNER_TOP_RIGHT == eStyleAnimType_Corner_TopRight - 1.3371 + eStyleAnimType_Corner_TopLeft && 1.3372 + NS_CORNER_BOTTOM_RIGHT == eStyleAnimType_Corner_BottomRight - 1.3373 + eStyleAnimType_Corner_TopLeft && 1.3374 + NS_CORNER_BOTTOM_LEFT == eStyleAnimType_Corner_BottomLeft - 1.3375 + eStyleAnimType_Corner_TopLeft, 1.3376 + "box corner constants out of sync with animation corner constants"); 1.3377 + 1.3378 + const nsStyleCorners *corners = static_cast<const nsStyleCorners*>( 1.3379 + StyleDataAtOffset(styleStruct, ssOffset)); 1.3380 + uint8_t fullCorner = animType - eStyleAnimType_Corner_TopLeft; 1.3381 + const nsStyleCoord &horiz = 1.3382 + corners->Get(NS_FULL_TO_HALF_CORNER(fullCorner, false)); 1.3383 + const nsStyleCoord &vert = 1.3384 + corners->Get(NS_FULL_TO_HALF_CORNER(fullCorner, true)); 1.3385 + nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair); 1.3386 + if (!pair || 1.3387 + !StyleCoordToCSSValue(horiz, pair->mXValue) || 1.3388 + !StyleCoordToCSSValue(vert, pair->mYValue)) { 1.3389 + return false; 1.3390 + } 1.3391 + aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(), 1.3392 + eUnit_CSSValuePair); 1.3393 + return true; 1.3394 + } 1.3395 + case eStyleAnimType_nscoord: 1.3396 + aComputedValue.SetCoordValue(*static_cast<const nscoord*>( 1.3397 + StyleDataAtOffset(styleStruct, ssOffset))); 1.3398 + return true; 1.3399 + case eStyleAnimType_EnumU8: 1.3400 + aComputedValue.SetIntValue(*static_cast<const uint8_t*>( 1.3401 + StyleDataAtOffset(styleStruct, ssOffset)), eUnit_Enumerated); 1.3402 + return true; 1.3403 + case eStyleAnimType_float: 1.3404 + aComputedValue.SetFloatValue(*static_cast<const float*>( 1.3405 + StyleDataAtOffset(styleStruct, ssOffset))); 1.3406 + if (aProperty == eCSSProperty_font_size_adjust && 1.3407 + aComputedValue.GetFloatValue() == 0.0f) { 1.3408 + // In nsStyleFont, we set mFont.sizeAdjust to 0 to represent 1.3409 + // font-size-adjust: none. Here, we have to treat this as a keyword 1.3410 + // instead of a float value, to make sure we don't end up doing 1.3411 + // interpolation with it. 1.3412 + aComputedValue.SetNoneValue(); 1.3413 + } 1.3414 + return true; 1.3415 + case eStyleAnimType_Color: 1.3416 + aComputedValue.SetColorValue(*static_cast<const nscolor*>( 1.3417 + StyleDataAtOffset(styleStruct, ssOffset))); 1.3418 + return true; 1.3419 + case eStyleAnimType_PaintServer: { 1.3420 + const nsStyleSVGPaint &paint = *static_cast<const nsStyleSVGPaint*>( 1.3421 + StyleDataAtOffset(styleStruct, ssOffset)); 1.3422 + if (paint.mType == eStyleSVGPaintType_Color) { 1.3423 + aComputedValue.SetColorValue(paint.mPaint.mColor); 1.3424 + return true; 1.3425 + } 1.3426 + if (paint.mType == eStyleSVGPaintType_Server) { 1.3427 + if (!paint.mPaint.mPaintServer) { 1.3428 + NS_WARNING("Null paint server"); 1.3429 + return false; 1.3430 + } 1.3431 + nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair); 1.3432 + nsRefPtr<nsStringBuffer> uriAsStringBuffer = 1.3433 + GetURIAsUtf16StringBuffer(paint.mPaint.mPaintServer); 1.3434 + NS_ENSURE_TRUE(!!uriAsStringBuffer, false); 1.3435 + nsIDocument* doc = aStyleContext->PresContext()->Document(); 1.3436 + nsRefPtr<mozilla::css::URLValue> url = 1.3437 + new mozilla::css::URLValue(paint.mPaint.mPaintServer, 1.3438 + uriAsStringBuffer, 1.3439 + doc->GetDocumentURI(), 1.3440 + doc->NodePrincipal()); 1.3441 + pair->mXValue.SetURLValue(url); 1.3442 + pair->mYValue.SetColorValue(paint.mFallbackColor); 1.3443 + aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(), 1.3444 + eUnit_CSSValuePair); 1.3445 + return true; 1.3446 + } 1.3447 + if (paint.mType == eStyleSVGPaintType_ContextFill || 1.3448 + paint.mType == eStyleSVGPaintType_ContextStroke) { 1.3449 + nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair); 1.3450 + pair->mXValue.SetIntValue(paint.mType == eStyleSVGPaintType_ContextFill ? 1.3451 + NS_COLOR_CONTEXT_FILL : NS_COLOR_CONTEXT_STROKE, 1.3452 + eCSSUnit_Enumerated); 1.3453 + pair->mYValue.SetColorValue(paint.mFallbackColor); 1.3454 + aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(), 1.3455 + eUnit_CSSValuePair); 1.3456 + return true; 1.3457 + } 1.3458 + NS_ABORT_IF_FALSE(paint.mType == eStyleSVGPaintType_None, 1.3459 + "Unexpected SVG paint type"); 1.3460 + aComputedValue.SetNoneValue(); 1.3461 + return true; 1.3462 + } 1.3463 + case eStyleAnimType_Shadow: { 1.3464 + const nsCSSShadowArray *shadowArray = 1.3465 + *static_cast<const nsRefPtr<nsCSSShadowArray>*>( 1.3466 + StyleDataAtOffset(styleStruct, ssOffset)); 1.3467 + if (!shadowArray) { 1.3468 + aComputedValue.SetAndAdoptCSSValueListValue(nullptr, eUnit_Shadow); 1.3469 + return true; 1.3470 + } 1.3471 + nsAutoPtr<nsCSSValueList> result; 1.3472 + nsCSSValueList **resultTail = getter_Transfers(result); 1.3473 + for (uint32_t i = 0, i_end = shadowArray->Length(); i < i_end; ++i) { 1.3474 + AppendCSSShadowValue(shadowArray->ShadowAt(i), resultTail); 1.3475 + } 1.3476 + aComputedValue.SetAndAdoptCSSValueListValue(result.forget(), 1.3477 + eUnit_Shadow); 1.3478 + return true; 1.3479 + } 1.3480 + case eStyleAnimType_None: 1.3481 + NS_NOTREACHED("shouldn't use on non-animatable properties"); 1.3482 + } 1.3483 + return false; 1.3484 +} 1.3485 + 1.3486 +nsStyleAnimation::Value::Value(int32_t aInt, Unit aUnit, 1.3487 + IntegerConstructorType) 1.3488 +{ 1.3489 + NS_ASSERTION(IsIntUnit(aUnit), "unit must be of integer type"); 1.3490 + mUnit = aUnit; 1.3491 + mValue.mInt = aInt; 1.3492 +} 1.3493 + 1.3494 +nsStyleAnimation::Value::Value(nscoord aLength, CoordConstructorType) 1.3495 +{ 1.3496 + mUnit = eUnit_Coord; 1.3497 + mValue.mCoord = aLength; 1.3498 +} 1.3499 + 1.3500 +nsStyleAnimation::Value::Value(float aPercent, PercentConstructorType) 1.3501 +{ 1.3502 + mUnit = eUnit_Percent; 1.3503 + mValue.mFloat = aPercent; 1.3504 + MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat)); 1.3505 +} 1.3506 + 1.3507 +nsStyleAnimation::Value::Value(float aFloat, FloatConstructorType) 1.3508 +{ 1.3509 + mUnit = eUnit_Float; 1.3510 + mValue.mFloat = aFloat; 1.3511 + MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat)); 1.3512 +} 1.3513 + 1.3514 +nsStyleAnimation::Value::Value(nscolor aColor, ColorConstructorType) 1.3515 +{ 1.3516 + mUnit = eUnit_Color; 1.3517 + mValue.mColor = aColor; 1.3518 +} 1.3519 + 1.3520 +nsStyleAnimation::Value& 1.3521 +nsStyleAnimation::Value::operator=(const Value& aOther) 1.3522 +{ 1.3523 + FreeValue(); 1.3524 + 1.3525 + mUnit = aOther.mUnit; 1.3526 + switch (mUnit) { 1.3527 + case eUnit_Null: 1.3528 + case eUnit_Normal: 1.3529 + case eUnit_Auto: 1.3530 + case eUnit_None: 1.3531 + break; 1.3532 + case eUnit_Enumerated: 1.3533 + case eUnit_Visibility: 1.3534 + case eUnit_Integer: 1.3535 + mValue.mInt = aOther.mValue.mInt; 1.3536 + break; 1.3537 + case eUnit_Coord: 1.3538 + mValue.mCoord = aOther.mValue.mCoord; 1.3539 + break; 1.3540 + case eUnit_Percent: 1.3541 + case eUnit_Float: 1.3542 + mValue.mFloat = aOther.mValue.mFloat; 1.3543 + MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat)); 1.3544 + break; 1.3545 + case eUnit_Color: 1.3546 + mValue.mColor = aOther.mValue.mColor; 1.3547 + break; 1.3548 + case eUnit_Calc: 1.3549 + NS_ABORT_IF_FALSE(aOther.mValue.mCSSValue, "values may not be null"); 1.3550 + mValue.mCSSValue = new nsCSSValue(*aOther.mValue.mCSSValue); 1.3551 + if (!mValue.mCSSValue) { 1.3552 + mUnit = eUnit_Null; 1.3553 + } 1.3554 + break; 1.3555 + case eUnit_CSSValuePair: 1.3556 + NS_ABORT_IF_FALSE(aOther.mValue.mCSSValuePair, 1.3557 + "value pairs may not be null"); 1.3558 + mValue.mCSSValuePair = new nsCSSValuePair(*aOther.mValue.mCSSValuePair); 1.3559 + if (!mValue.mCSSValuePair) { 1.3560 + mUnit = eUnit_Null; 1.3561 + } 1.3562 + break; 1.3563 + case eUnit_CSSValueTriplet: 1.3564 + NS_ABORT_IF_FALSE(aOther.mValue.mCSSValueTriplet, 1.3565 + "value triplets may not be null"); 1.3566 + mValue.mCSSValueTriplet = new nsCSSValueTriplet(*aOther.mValue.mCSSValueTriplet); 1.3567 + if (!mValue.mCSSValueTriplet) { 1.3568 + mUnit = eUnit_Null; 1.3569 + } 1.3570 + break; 1.3571 + case eUnit_CSSRect: 1.3572 + NS_ABORT_IF_FALSE(aOther.mValue.mCSSRect, "rects may not be null"); 1.3573 + mValue.mCSSRect = new nsCSSRect(*aOther.mValue.mCSSRect); 1.3574 + if (!mValue.mCSSRect) { 1.3575 + mUnit = eUnit_Null; 1.3576 + } 1.3577 + break; 1.3578 + case eUnit_Filter: 1.3579 + case eUnit_Dasharray: 1.3580 + case eUnit_Shadow: 1.3581 + case eUnit_BackgroundPosition: 1.3582 + NS_ABORT_IF_FALSE(mUnit == eUnit_Shadow || mUnit == eUnit_Filter || 1.3583 + aOther.mValue.mCSSValueList, 1.3584 + "value lists other than shadows and filters may not be null"); 1.3585 + if (aOther.mValue.mCSSValueList) { 1.3586 + mValue.mCSSValueList = aOther.mValue.mCSSValueList->Clone(); 1.3587 + if (!mValue.mCSSValueList) { 1.3588 + mUnit = eUnit_Null; 1.3589 + } 1.3590 + } else { 1.3591 + mValue.mCSSValueList = nullptr; 1.3592 + } 1.3593 + break; 1.3594 + case eUnit_Transform: 1.3595 + mValue.mCSSValueSharedList = aOther.mValue.mCSSValueSharedList; 1.3596 + mValue.mCSSValueSharedList->AddRef(); 1.3597 + break; 1.3598 + case eUnit_CSSValuePairList: 1.3599 + NS_ABORT_IF_FALSE(aOther.mValue.mCSSValuePairList, 1.3600 + "value pair lists may not be null"); 1.3601 + mValue.mCSSValuePairList = aOther.mValue.mCSSValuePairList->Clone(); 1.3602 + if (!mValue.mCSSValuePairList) { 1.3603 + mUnit = eUnit_Null; 1.3604 + } 1.3605 + break; 1.3606 + case eUnit_UnparsedString: 1.3607 + NS_ABORT_IF_FALSE(aOther.mValue.mString, "expecting non-null string"); 1.3608 + mValue.mString = aOther.mValue.mString; 1.3609 + mValue.mString->AddRef(); 1.3610 + break; 1.3611 + } 1.3612 + 1.3613 + return *this; 1.3614 +} 1.3615 + 1.3616 +void 1.3617 +nsStyleAnimation::Value::SetNormalValue() 1.3618 +{ 1.3619 + FreeValue(); 1.3620 + mUnit = eUnit_Normal; 1.3621 +} 1.3622 + 1.3623 +void 1.3624 +nsStyleAnimation::Value::SetAutoValue() 1.3625 +{ 1.3626 + FreeValue(); 1.3627 + mUnit = eUnit_Auto; 1.3628 +} 1.3629 + 1.3630 +void 1.3631 +nsStyleAnimation::Value::SetNoneValue() 1.3632 +{ 1.3633 + FreeValue(); 1.3634 + mUnit = eUnit_None; 1.3635 +} 1.3636 + 1.3637 +void 1.3638 +nsStyleAnimation::Value::SetIntValue(int32_t aInt, Unit aUnit) 1.3639 +{ 1.3640 + NS_ASSERTION(IsIntUnit(aUnit), "unit must be of integer type"); 1.3641 + FreeValue(); 1.3642 + mUnit = aUnit; 1.3643 + mValue.mInt = aInt; 1.3644 +} 1.3645 + 1.3646 +void 1.3647 +nsStyleAnimation::Value::SetCoordValue(nscoord aLength) 1.3648 +{ 1.3649 + FreeValue(); 1.3650 + mUnit = eUnit_Coord; 1.3651 + mValue.mCoord = aLength; 1.3652 +} 1.3653 + 1.3654 +void 1.3655 +nsStyleAnimation::Value::SetPercentValue(float aPercent) 1.3656 +{ 1.3657 + FreeValue(); 1.3658 + mUnit = eUnit_Percent; 1.3659 + mValue.mFloat = aPercent; 1.3660 + MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat)); 1.3661 +} 1.3662 + 1.3663 +void 1.3664 +nsStyleAnimation::Value::SetFloatValue(float aFloat) 1.3665 +{ 1.3666 + FreeValue(); 1.3667 + mUnit = eUnit_Float; 1.3668 + mValue.mFloat = aFloat; 1.3669 + MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat)); 1.3670 +} 1.3671 + 1.3672 +void 1.3673 +nsStyleAnimation::Value::SetColorValue(nscolor aColor) 1.3674 +{ 1.3675 + FreeValue(); 1.3676 + mUnit = eUnit_Color; 1.3677 + mValue.mColor = aColor; 1.3678 +} 1.3679 + 1.3680 +void 1.3681 +nsStyleAnimation::Value::SetUnparsedStringValue(const nsString& aString) 1.3682 +{ 1.3683 + FreeValue(); 1.3684 + mUnit = eUnit_UnparsedString; 1.3685 + mValue.mString = nsCSSValue::BufferFromString(aString).take(); 1.3686 +} 1.3687 + 1.3688 +void 1.3689 +nsStyleAnimation::Value::SetAndAdoptCSSValueValue(nsCSSValue *aValue, 1.3690 + Unit aUnit) 1.3691 +{ 1.3692 + FreeValue(); 1.3693 + NS_ABORT_IF_FALSE(IsCSSValueUnit(aUnit), "bad unit"); 1.3694 + NS_ABORT_IF_FALSE(aValue != nullptr, "values may not be null"); 1.3695 + mUnit = aUnit; 1.3696 + mValue.mCSSValue = aValue; // take ownership 1.3697 +} 1.3698 + 1.3699 +void 1.3700 +nsStyleAnimation::Value::SetAndAdoptCSSValuePairValue( 1.3701 + nsCSSValuePair *aValuePair, Unit aUnit) 1.3702 +{ 1.3703 + FreeValue(); 1.3704 + NS_ABORT_IF_FALSE(IsCSSValuePairUnit(aUnit), "bad unit"); 1.3705 + NS_ABORT_IF_FALSE(aValuePair != nullptr, "value pairs may not be null"); 1.3706 + mUnit = aUnit; 1.3707 + mValue.mCSSValuePair = aValuePair; // take ownership 1.3708 +} 1.3709 + 1.3710 +void 1.3711 +nsStyleAnimation::Value::SetAndAdoptCSSValueTripletValue( 1.3712 + nsCSSValueTriplet *aValueTriplet, Unit aUnit) 1.3713 +{ 1.3714 + FreeValue(); 1.3715 + NS_ABORT_IF_FALSE(IsCSSValueTripletUnit(aUnit), "bad unit"); 1.3716 + NS_ABORT_IF_FALSE(aValueTriplet != nullptr, "value pairs may not be null"); 1.3717 + mUnit = aUnit; 1.3718 + mValue.mCSSValueTriplet = aValueTriplet; // take ownership 1.3719 +} 1.3720 + 1.3721 +void 1.3722 +nsStyleAnimation::Value::SetAndAdoptCSSRectValue(nsCSSRect *aRect, Unit aUnit) 1.3723 +{ 1.3724 + FreeValue(); 1.3725 + NS_ABORT_IF_FALSE(IsCSSRectUnit(aUnit), "bad unit"); 1.3726 + NS_ABORT_IF_FALSE(aRect != nullptr, "value pairs may not be null"); 1.3727 + mUnit = aUnit; 1.3728 + mValue.mCSSRect = aRect; // take ownership 1.3729 +} 1.3730 + 1.3731 +void 1.3732 +nsStyleAnimation::Value::SetAndAdoptCSSValueListValue( 1.3733 + nsCSSValueList *aValueList, Unit aUnit) 1.3734 +{ 1.3735 + FreeValue(); 1.3736 + NS_ABORT_IF_FALSE(IsCSSValueListUnit(aUnit), "bad unit"); 1.3737 + NS_ABORT_IF_FALSE(aUnit == eUnit_Shadow || aUnit == eUnit_Filter || 1.3738 + aValueList != nullptr, 1.3739 + "value lists other than shadows and filters may not be null"); 1.3740 + mUnit = aUnit; 1.3741 + mValue.mCSSValueList = aValueList; // take ownership 1.3742 +} 1.3743 + 1.3744 +void 1.3745 +nsStyleAnimation::Value::SetTransformValue(nsCSSValueSharedList* aList) 1.3746 +{ 1.3747 + FreeValue(); 1.3748 + mUnit = eUnit_Transform; 1.3749 + mValue.mCSSValueSharedList = aList; 1.3750 + mValue.mCSSValueSharedList->AddRef(); 1.3751 +} 1.3752 + 1.3753 +void 1.3754 +nsStyleAnimation::Value::SetAndAdoptCSSValuePairListValue( 1.3755 + nsCSSValuePairList *aValuePairList) 1.3756 +{ 1.3757 + FreeValue(); 1.3758 + NS_ABORT_IF_FALSE(aValuePairList, "may not be null"); 1.3759 + mUnit = eUnit_CSSValuePairList; 1.3760 + mValue.mCSSValuePairList = aValuePairList; // take ownership 1.3761 +} 1.3762 + 1.3763 +void 1.3764 +nsStyleAnimation::Value::FreeValue() 1.3765 +{ 1.3766 + if (IsCSSValueUnit(mUnit)) { 1.3767 + delete mValue.mCSSValue; 1.3768 + } else if (IsCSSValueListUnit(mUnit)) { 1.3769 + delete mValue.mCSSValueList; 1.3770 + } else if (IsCSSValueSharedListValue(mUnit)) { 1.3771 + mValue.mCSSValueSharedList->Release(); 1.3772 + } else if (IsCSSValuePairUnit(mUnit)) { 1.3773 + delete mValue.mCSSValuePair; 1.3774 + } else if (IsCSSValueTripletUnit(mUnit)) { 1.3775 + delete mValue.mCSSValueTriplet; 1.3776 + } else if (IsCSSRectUnit(mUnit)) { 1.3777 + delete mValue.mCSSRect; 1.3778 + } else if (IsCSSValuePairListUnit(mUnit)) { 1.3779 + delete mValue.mCSSValuePairList; 1.3780 + } else if (IsStringUnit(mUnit)) { 1.3781 + NS_ABORT_IF_FALSE(mValue.mString, "expecting non-null string"); 1.3782 + mValue.mString->Release(); 1.3783 + } 1.3784 +} 1.3785 + 1.3786 +bool 1.3787 +nsStyleAnimation::Value::operator==(const Value& aOther) const 1.3788 +{ 1.3789 + if (mUnit != aOther.mUnit) { 1.3790 + return false; 1.3791 + } 1.3792 + 1.3793 + switch (mUnit) { 1.3794 + case eUnit_Null: 1.3795 + case eUnit_Normal: 1.3796 + case eUnit_Auto: 1.3797 + case eUnit_None: 1.3798 + return true; 1.3799 + case eUnit_Enumerated: 1.3800 + case eUnit_Visibility: 1.3801 + case eUnit_Integer: 1.3802 + return mValue.mInt == aOther.mValue.mInt; 1.3803 + case eUnit_Coord: 1.3804 + return mValue.mCoord == aOther.mValue.mCoord; 1.3805 + case eUnit_Percent: 1.3806 + case eUnit_Float: 1.3807 + return mValue.mFloat == aOther.mValue.mFloat; 1.3808 + case eUnit_Color: 1.3809 + return mValue.mColor == aOther.mValue.mColor; 1.3810 + case eUnit_Calc: 1.3811 + return *mValue.mCSSValue == *aOther.mValue.mCSSValue; 1.3812 + case eUnit_CSSValuePair: 1.3813 + return *mValue.mCSSValuePair == *aOther.mValue.mCSSValuePair; 1.3814 + case eUnit_CSSValueTriplet: 1.3815 + return *mValue.mCSSValueTriplet == *aOther.mValue.mCSSValueTriplet; 1.3816 + case eUnit_CSSRect: 1.3817 + return *mValue.mCSSRect == *aOther.mValue.mCSSRect; 1.3818 + case eUnit_Dasharray: 1.3819 + case eUnit_Filter: 1.3820 + case eUnit_Shadow: 1.3821 + case eUnit_BackgroundPosition: 1.3822 + return *mValue.mCSSValueList == *aOther.mValue.mCSSValueList; 1.3823 + case eUnit_Transform: 1.3824 + return *mValue.mCSSValueSharedList == *aOther.mValue.mCSSValueSharedList; 1.3825 + case eUnit_CSSValuePairList: 1.3826 + return *mValue.mCSSValuePairList == *aOther.mValue.mCSSValuePairList; 1.3827 + case eUnit_UnparsedString: 1.3828 + return (NS_strcmp(GetStringBufferValue(), 1.3829 + aOther.GetStringBufferValue()) == 0); 1.3830 + } 1.3831 + 1.3832 + NS_NOTREACHED("incomplete case"); 1.3833 + return false; 1.3834 +} 1.3835 +