LCOV - code coverage report
Current view: directory - layout/style - nsStyleAnimation.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1657 25 1.5 %
Date: 2012-06-02 Functions: 70 5 7.1 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is nsStyleAnimation.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * The Mozilla Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Daniel Holbert <dholbert@mozilla.com>, Mozilla Corporation
      24                 :  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /* Utilities for animation of computed style values */
      41                 : 
      42                 : #include "mozilla/Util.h"
      43                 : 
      44                 : #include "nsStyleAnimation.h"
      45                 : #include "nsCOMArray.h"
      46                 : #include "nsIStyleRule.h"
      47                 : #include "mozilla/css/StyleRule.h"
      48                 : #include "nsString.h"
      49                 : #include "nsStyleContext.h"
      50                 : #include "nsStyleSet.h"
      51                 : #include "nsComputedDOMStyle.h"
      52                 : #include "nsCSSParser.h"
      53                 : #include "mozilla/css/Declaration.h"
      54                 : #include "mozilla/dom/Element.h"
      55                 : #include "prlog.h"
      56                 : #include <math.h>
      57                 : #include "gfxMatrix.h"
      58                 : #include "gfxQuaternion.h"
      59                 : #include "nsPrintfCString.h"
      60                 : 
      61                 : using namespace mozilla;
      62                 : 
      63                 : // HELPER METHODS
      64                 : // --------------
      65                 : /*
      66                 :  * Given two units, this method returns a common unit that they can both be
      67                 :  * converted into, if possible.  This is intended to facilitate
      68                 :  * interpolation, distance-computation, and addition between "similar" units.
      69                 :  *
      70                 :  * The ordering of the arguments should not affect the output of this method.
      71                 :  *
      72                 :  * If there's no sensible common unit, this method returns eUnit_Null.
      73                 :  *
      74                 :  * @param   aFirstUnit One unit to resolve.
      75                 :  * @param   aFirstUnit The other unit to resolve.
      76                 :  * @return  A "common" unit that both source units can be converted into, or
      77                 :  *          eUnit_Null if that's not possible.
      78                 :  */
      79                 : static
      80                 : nsStyleAnimation::Unit
      81               0 : GetCommonUnit(nsCSSProperty aProperty,
      82                 :               nsStyleAnimation::Unit aFirstUnit,
      83                 :               nsStyleAnimation::Unit aSecondUnit)
      84                 : {
      85               0 :   if (aFirstUnit != aSecondUnit) {
      86               0 :     if (nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_STORES_CALC) &&
      87                 :         (aFirstUnit == nsStyleAnimation::eUnit_Coord ||
      88                 :          aFirstUnit == nsStyleAnimation::eUnit_Percent ||
      89                 :          aFirstUnit == nsStyleAnimation::eUnit_Calc) &&
      90                 :         (aSecondUnit == nsStyleAnimation::eUnit_Coord ||
      91                 :          aSecondUnit == nsStyleAnimation::eUnit_Percent ||
      92                 :          aSecondUnit == nsStyleAnimation::eUnit_Calc)) {
      93                 :       // We can use calc() as the common unit.
      94               0 :       return nsStyleAnimation::eUnit_Calc;
      95                 :     }
      96               0 :     return nsStyleAnimation::eUnit_Null;
      97                 :   }
      98               0 :   return aFirstUnit;
      99                 : }
     100                 : 
     101                 : static
     102                 : nsCSSUnit
     103               0 : GetCommonUnit(nsCSSProperty aProperty,
     104                 :               nsCSSUnit aFirstUnit,
     105                 :               nsCSSUnit aSecondUnit)
     106                 : {
     107               0 :   if (aFirstUnit != aSecondUnit) {
     108               0 :     if (nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_STORES_CALC) &&
     109                 :         (aFirstUnit == eCSSUnit_Pixel ||
     110                 :          aFirstUnit == eCSSUnit_Percent ||
     111                 :          aFirstUnit == eCSSUnit_Calc) &&
     112                 :         (aSecondUnit == eCSSUnit_Pixel ||
     113                 :          aSecondUnit == eCSSUnit_Percent ||
     114                 :          aSecondUnit == eCSSUnit_Calc)) {
     115                 :       // We can use calc() as the common unit.
     116               0 :       return eCSSUnit_Calc;
     117                 :     }
     118               0 :     return eCSSUnit_Null;
     119                 :   }
     120               0 :   return aFirstUnit;
     121                 : }
     122                 : 
     123                 : 
     124                 : // Greatest Common Divisor
     125                 : static PRUint32
     126               0 : gcd(PRUint32 a, PRUint32 b)
     127                 : {
     128                 :   // Euclid's algorithm; O(N) in the worst case.  (There are better
     129                 :   // ways, but we don't need them for stroke-dasharray animation.)
     130               0 :   NS_ABORT_IF_FALSE(a > 0 && b > 0, "positive numbers expected");
     131                 : 
     132               0 :   while (a != b) {
     133               0 :     if (a > b) {
     134               0 :       a = a - b;
     135                 :     } else {
     136               0 :       b = b - a;
     137                 :     }
     138                 :   }
     139                 : 
     140               0 :   return a;
     141                 : }
     142                 : 
     143                 : // Least Common Multiple
     144                 : static PRUint32
     145               0 : lcm(PRUint32 a, PRUint32 b)
     146                 : {
     147                 :   // Divide first to reduce overflow risk.
     148               0 :   return (a / gcd(a, b)) * b;
     149                 : }
     150                 : 
     151                 : inline void
     152               0 : nscoordToCSSValue(nscoord aCoord, nsCSSValue& aCSSValue)
     153                 : {
     154                 :   aCSSValue.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(aCoord),
     155               0 :                           eCSSUnit_Pixel);
     156               0 : }
     157                 : 
     158                 : // Like nsStyleCoord::Calc, but with length in float pixels instead of nscoord.
     159                 : struct CalcValue {
     160                 :   float mLength, mPercent;
     161                 :   bool mHasPercent;
     162                 : };
     163                 : 
     164                 : // Requires a canonical calc() value that we generated.
     165                 : static CalcValue
     166               0 : ExtractCalcValueInternal(const nsCSSValue& aValue)
     167                 : {
     168               0 :   NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Calc, "unexpected unit");
     169               0 :   nsCSSValue::Array *arr = aValue.GetArrayValue();
     170               0 :   NS_ABORT_IF_FALSE(arr->Count() == 1, "unexpected length");
     171                 : 
     172               0 :   const nsCSSValue &topval = arr->Item(0);
     173                 :   CalcValue result;
     174               0 :   if (topval.GetUnit() == eCSSUnit_Pixel) {
     175               0 :     result.mLength = topval.GetFloatValue();
     176               0 :     result.mPercent = 0.0f;
     177               0 :     result.mHasPercent = false;
     178                 :   } else {
     179               0 :     NS_ABORT_IF_FALSE(topval.GetUnit() == eCSSUnit_Calc_Plus,
     180                 :                       "unexpected unit");
     181               0 :     nsCSSValue::Array *arr2 = topval.GetArrayValue();
     182               0 :     const nsCSSValue &len = arr2->Item(0);
     183               0 :     const nsCSSValue &pct = arr2->Item(1);
     184               0 :     NS_ABORT_IF_FALSE(len.GetUnit() == eCSSUnit_Pixel, "unexpected unit");
     185               0 :     NS_ABORT_IF_FALSE(pct.GetUnit() == eCSSUnit_Percent, "unexpected unit");
     186               0 :     result.mLength = len.GetFloatValue();
     187               0 :     result.mPercent = pct.GetPercentValue();
     188               0 :     result.mHasPercent = true;
     189                 :   }
     190                 : 
     191                 :   return result;
     192                 : }
     193                 : 
     194                 : // Requires a canonical calc() value that we generated.
     195                 : static CalcValue
     196               0 : ExtractCalcValue(const nsStyleAnimation::Value& aValue)
     197                 : {
     198                 :   CalcValue result;
     199               0 :   if (aValue.GetUnit() == nsStyleAnimation::eUnit_Coord) {
     200                 :     result.mLength =
     201               0 :       nsPresContext::AppUnitsToFloatCSSPixels(aValue.GetCoordValue());
     202               0 :     result.mPercent = 0.0f;
     203               0 :     result.mHasPercent = false;
     204               0 :     return result;
     205                 :   }
     206               0 :   if (aValue.GetUnit() == nsStyleAnimation::eUnit_Percent) {
     207               0 :     result.mLength = 0.0f;
     208               0 :     result.mPercent = aValue.GetPercentValue();
     209               0 :     result.mHasPercent = true;
     210               0 :     return result;
     211                 :   }
     212               0 :   NS_ABORT_IF_FALSE(aValue.GetUnit() == nsStyleAnimation::eUnit_Calc,
     213                 :                     "unexpected unit");
     214               0 :   nsCSSValue *val = aValue.GetCSSValueValue();
     215               0 :   return ExtractCalcValueInternal(*val);
     216                 : }
     217                 : 
     218                 : static CalcValue
     219               0 : ExtractCalcValue(const nsCSSValue& aValue)
     220                 : {
     221                 :   CalcValue result;
     222               0 :   if (aValue.GetUnit() == eCSSUnit_Pixel) {
     223               0 :     result.mLength = aValue.GetFloatValue();
     224               0 :     result.mPercent = 0.0f;
     225               0 :     result.mHasPercent = false;
     226               0 :     return result;
     227                 :   }
     228               0 :   if (aValue.GetUnit() == eCSSUnit_Percent) {
     229               0 :     result.mLength = 0.0f;
     230               0 :     result.mPercent = aValue.GetPercentValue();
     231               0 :     result.mHasPercent = true;
     232               0 :     return result;
     233                 :   }
     234               0 :   return ExtractCalcValueInternal(aValue);
     235                 : }
     236                 : 
     237                 : static void
     238               0 : SetCalcValue(const nsStyleCoord::Calc* aCalc, nsCSSValue& aValue)
     239                 : {
     240               0 :   nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(1);
     241               0 :   if (!aCalc->mHasPercent) {
     242               0 :     nscoordToCSSValue(aCalc->mLength, arr->Item(0));
     243                 :   } else {
     244               0 :     nsCSSValue::Array *arr2 = nsCSSValue::Array::Create(2);
     245               0 :     arr->Item(0).SetArrayValue(arr2, eCSSUnit_Calc_Plus);
     246               0 :     nscoordToCSSValue(aCalc->mLength, arr2->Item(0));
     247               0 :     arr2->Item(1).SetPercentValue(aCalc->mPercent);
     248                 :   }
     249                 : 
     250               0 :   aValue.SetArrayValue(arr, eCSSUnit_Calc);
     251               0 : }
     252                 : 
     253                 : static already_AddRefed<nsStringBuffer>
     254               0 : GetURIAsUtf16StringBuffer(nsIURI* aUri)
     255                 : {
     256               0 :   nsCAutoString utf8String;
     257               0 :   nsresult rv = aUri->GetSpec(utf8String);
     258               0 :   NS_ENSURE_SUCCESS(rv, nsnull);
     259                 : 
     260               0 :   return nsCSSValue::BufferFromString(NS_ConvertUTF8toUTF16(utf8String));
     261                 : }
     262                 : 
     263                 : // CLASS METHODS
     264                 : // -------------
     265                 : 
     266                 : bool
     267               0 : nsStyleAnimation::ComputeDistance(nsCSSProperty aProperty,
     268                 :                                   const Value& aStartValue,
     269                 :                                   const Value& aEndValue,
     270                 :                                   double& aDistance)
     271                 : {
     272                 :   Unit commonUnit =
     273               0 :     GetCommonUnit(aProperty, aStartValue.GetUnit(), aEndValue.GetUnit());
     274                 : 
     275               0 :   switch (commonUnit) {
     276                 :     case eUnit_Null:
     277                 :     case eUnit_Auto:
     278                 :     case eUnit_None:
     279                 :     case eUnit_Normal:
     280                 :     case eUnit_UnparsedString:
     281               0 :       return false;
     282                 : 
     283                 :     case eUnit_Enumerated:
     284               0 :       switch (aProperty) {
     285                 :         case eCSSProperty_font_stretch: {
     286                 :           // just like eUnit_Integer.
     287               0 :           PRInt32 startInt = aStartValue.GetIntValue();
     288               0 :           PRInt32 endInt = aEndValue.GetIntValue();
     289               0 :           aDistance = NS_ABS(endInt - startInt);
     290               0 :           return true;
     291                 :         }
     292                 :         default:
     293               0 :           return false;
     294                 :       }
     295                 :    case eUnit_Visibility: {
     296                 :       PRInt32 startVal =
     297               0 :         aStartValue.GetIntValue() == NS_STYLE_VISIBILITY_VISIBLE;
     298                 :       PRInt32 endVal =
     299               0 :         aEndValue.GetIntValue() == NS_STYLE_VISIBILITY_VISIBLE;
     300               0 :       aDistance = NS_ABS(startVal - endVal);
     301               0 :       return true;
     302                 :     }
     303                 :     case eUnit_Integer: {
     304               0 :       PRInt32 startInt = aStartValue.GetIntValue();
     305               0 :       PRInt32 endInt = aEndValue.GetIntValue();
     306               0 :       aDistance = NS_ABS(endInt - startInt);
     307               0 :       return true;
     308                 :     }
     309                 :     case eUnit_Coord: {
     310               0 :       nscoord startCoord = aStartValue.GetCoordValue();
     311               0 :       nscoord endCoord = aEndValue.GetCoordValue();
     312               0 :       aDistance = fabs(double(endCoord - startCoord));
     313               0 :       return true;
     314                 :     }
     315                 :     case eUnit_Percent: {
     316               0 :       float startPct = aStartValue.GetPercentValue();
     317               0 :       float endPct = aEndValue.GetPercentValue();
     318               0 :       aDistance = fabs(double(endPct - startPct));
     319               0 :       return true;
     320                 :     }
     321                 :     case eUnit_Float: {
     322               0 :       float startFloat = aStartValue.GetFloatValue();
     323               0 :       float endFloat = aEndValue.GetFloatValue();
     324               0 :       aDistance = fabs(double(endFloat - startFloat));
     325               0 :       return true;
     326                 :     }
     327                 :     case eUnit_Color: {
     328                 :       // http://www.w3.org/TR/smil-animation/#animateColorElement says
     329                 :       // that we should use Euclidean RGB cube distance.  However, we
     330                 :       // have to extend that to RGBA.  For now, we'll just use the
     331                 :       // Euclidean distance in the (part of the) 4-cube of premultiplied
     332                 :       // colors.
     333                 :       // FIXME (spec): The CSS transitions spec doesn't say whether
     334                 :       // colors are premultiplied, but things work better when they are,
     335                 :       // so use premultiplication.  Spec issue is still open per
     336                 :       // http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html
     337               0 :       nscolor startColor = aStartValue.GetColorValue();
     338               0 :       nscolor endColor = aEndValue.GetColorValue();
     339                 : 
     340                 :       // Get a color component on a 0-1 scale, which is much easier to
     341                 :       // deal with when working with alpha.
     342                 :       #define GET_COMPONENT(component_, color_) \
     343                 :         (NS_GET_##component_(color_) * (1.0 / 255.0))
     344                 : 
     345               0 :       double startA = GET_COMPONENT(A, startColor);
     346               0 :       double startR = GET_COMPONENT(R, startColor) * startA;
     347               0 :       double startG = GET_COMPONENT(G, startColor) * startA;
     348               0 :       double startB = GET_COMPONENT(B, startColor) * startA;
     349               0 :       double endA = GET_COMPONENT(A, endColor);
     350               0 :       double endR = GET_COMPONENT(R, endColor) * endA;
     351               0 :       double endG = GET_COMPONENT(G, endColor) * endA;
     352               0 :       double endB = GET_COMPONENT(B, endColor) * endA;
     353                 : 
     354                 :       #undef GET_COMPONENT
     355                 : 
     356               0 :       double diffA = startA - endA;
     357               0 :       double diffR = startR - endR;
     358               0 :       double diffG = startG - endG;
     359               0 :       double diffB = startB - endB;
     360                 :       aDistance = sqrt(diffA * diffA + diffR * diffR +
     361               0 :                        diffG * diffG + diffB * diffB);
     362               0 :       return true;
     363                 :     }
     364                 :     case eUnit_Calc: {
     365               0 :       CalcValue v1 = ExtractCalcValue(aStartValue);
     366               0 :       CalcValue v2 = ExtractCalcValue(aEndValue);
     367               0 :       float difflen = v2.mLength - v1.mLength;
     368               0 :       float diffpct = v2.mPercent - v1.mPercent;
     369               0 :       aDistance = sqrt(difflen * difflen + diffpct * diffpct);
     370               0 :       return true;
     371                 :     }
     372                 :     case eUnit_CSSValuePair: {
     373               0 :       const nsCSSValuePair *pair1 = aStartValue.GetCSSValuePairValue();
     374               0 :       const nsCSSValuePair *pair2 = aEndValue.GetCSSValuePairValue();
     375                 :       nsCSSUnit unit[2];
     376                 :       unit[0] = GetCommonUnit(aProperty, pair1->mXValue.GetUnit(),
     377               0 :                               pair2->mXValue.GetUnit());
     378                 :       unit[1] = GetCommonUnit(aProperty, pair1->mYValue.GetUnit(),
     379               0 :                               pair2->mYValue.GetUnit());
     380               0 :       if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
     381               0 :           unit[0] == eCSSUnit_URL) {
     382               0 :         return false;
     383                 :       }
     384                 : 
     385               0 :       double squareDistance = 0.0;
     386                 :       static nsCSSValue nsCSSValuePair::* const pairValues[2] = {
     387                 :         &nsCSSValuePair::mXValue, &nsCSSValuePair::mYValue
     388                 :       };
     389               0 :       for (PRUint32 i = 0; i < 2; ++i) {
     390               0 :         nsCSSValue nsCSSValuePair::*member = pairValues[i];
     391                 :         double diffsquared;
     392               0 :         switch (unit[i]) {
     393                 :           case eCSSUnit_Pixel: {
     394               0 :             float diff = (pair1->*member).GetFloatValue() -
     395               0 :                          (pair2->*member).GetFloatValue();
     396               0 :             diffsquared = diff * diff;
     397               0 :             break;
     398                 :           }
     399                 :           case eCSSUnit_Percent: {
     400               0 :             float diff = (pair1->*member).GetPercentValue() -
     401               0 :                          (pair2->*member).GetPercentValue();
     402               0 :             diffsquared = diff * diff;
     403               0 :             break;
     404                 :           }
     405                 :           case eCSSUnit_Calc: {
     406               0 :             CalcValue v1 = ExtractCalcValue(pair1->*member);
     407               0 :             CalcValue v2 = ExtractCalcValue(pair2->*member);
     408               0 :             float difflen = v2.mLength - v1.mLength;
     409               0 :             float diffpct = v2.mPercent - v1.mPercent;
     410               0 :             diffsquared = difflen * difflen + diffpct * diffpct;
     411               0 :             break;
     412                 :           }
     413                 :           default:
     414               0 :             NS_ABORT_IF_FALSE(false, "unexpected unit");
     415               0 :             return false;
     416                 :         }
     417               0 :         squareDistance += diffsquared;
     418                 :       }
     419                 : 
     420               0 :       aDistance = sqrt(squareDistance);
     421               0 :       return true;
     422                 :     }
     423                 :     case eUnit_CSSValueTriplet: {
     424               0 :       const nsCSSValueTriplet *triplet1 = aStartValue.GetCSSValueTripletValue();
     425               0 :       const nsCSSValueTriplet *triplet2 = aEndValue.GetCSSValueTripletValue();
     426                 :       nsCSSUnit unit[3];
     427                 :       unit[0] = GetCommonUnit(aProperty, triplet1->mXValue.GetUnit(),
     428               0 :                               triplet2->mXValue.GetUnit());
     429                 :       unit[1] = GetCommonUnit(aProperty, triplet1->mYValue.GetUnit(),
     430               0 :                               triplet2->mYValue.GetUnit());
     431                 :       unit[2] = GetCommonUnit(aProperty, triplet1->mZValue.GetUnit(),
     432               0 :                               triplet2->mZValue.GetUnit());
     433               0 :       if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
     434               0 :           unit[0] == eCSSUnit_URL) {
     435               0 :         return false;
     436                 :       }
     437                 : 
     438               0 :       double squareDistance = 0.0;
     439                 :       static nsCSSValue nsCSSValueTriplet::* const pairValues[3] = {
     440                 :         &nsCSSValueTriplet::mXValue, &nsCSSValueTriplet::mYValue, &nsCSSValueTriplet::mZValue
     441                 :       };
     442               0 :       for (PRUint32 i = 0; i < 3; ++i) {
     443               0 :         nsCSSValue nsCSSValueTriplet::*member = pairValues[i];
     444                 :         double diffsquared;
     445               0 :         switch (unit[i]) {
     446                 :           case eCSSUnit_Pixel: {
     447               0 :             float diff = (triplet1->*member).GetFloatValue() -
     448               0 :                          (triplet2->*member).GetFloatValue();
     449               0 :             diffsquared = diff * diff;
     450               0 :             break;
     451                 :           }
     452                 :           case eCSSUnit_Percent: {
     453               0 :             float diff = (triplet1->*member).GetPercentValue() -
     454               0 :                          (triplet2->*member).GetPercentValue();
     455               0 :              diffsquared = diff * diff;
     456               0 :              break;
     457                 :           }
     458                 :           case eCSSUnit_Calc: {
     459               0 :             CalcValue v1 = ExtractCalcValue(triplet1->*member);
     460               0 :             CalcValue v2 = ExtractCalcValue(triplet2->*member);
     461               0 :             float difflen = v2.mLength - v1.mLength;
     462               0 :             float diffpct = v2.mPercent - v1.mPercent;
     463               0 :             diffsquared = difflen * difflen + diffpct * diffpct;
     464               0 :             break;
     465                 :           }
     466                 :           case eCSSUnit_Null:
     467               0 :             diffsquared = 0;
     468               0 :             break;
     469                 :           default:
     470               0 :             NS_ABORT_IF_FALSE(false, "unexpected unit");
     471               0 :             return false;
     472                 :         }
     473               0 :         squareDistance += diffsquared;
     474                 :       }
     475                 : 
     476               0 :       aDistance = sqrt(squareDistance);
     477               0 :       return true;
     478                 :     }
     479                 :     case eUnit_CSSRect: {
     480               0 :       const nsCSSRect *rect1 = aStartValue.GetCSSRectValue();
     481               0 :       const nsCSSRect *rect2 = aEndValue.GetCSSRectValue();
     482               0 :       if (rect1->mTop.GetUnit() != rect2->mTop.GetUnit() ||
     483               0 :           rect1->mRight.GetUnit() != rect2->mRight.GetUnit() ||
     484               0 :           rect1->mBottom.GetUnit() != rect2->mBottom.GetUnit() ||
     485               0 :           rect1->mLeft.GetUnit() != rect2->mLeft.GetUnit()) {
     486                 :         // At least until we have calc()
     487               0 :         return false;
     488                 :       }
     489                 : 
     490               0 :       double squareDistance = 0.0;
     491               0 :       for (PRUint32 i = 0; i < ArrayLength(nsCSSRect::sides); ++i) {
     492               0 :         nsCSSValue nsCSSRect::*member = nsCSSRect::sides[i];
     493               0 :         NS_ABORT_IF_FALSE((rect1->*member).GetUnit() ==
     494                 :                             (rect2->*member).GetUnit(),
     495                 :                           "should have returned above");
     496                 :         double diff;
     497               0 :         switch ((rect1->*member).GetUnit()) {
     498                 :           case eCSSUnit_Pixel:
     499               0 :             diff = (rect1->*member).GetFloatValue() -
     500               0 :                    (rect2->*member).GetFloatValue();
     501               0 :             break;
     502                 :           case eCSSUnit_Auto:
     503               0 :             diff = 0;
     504               0 :             break;
     505                 :           default:
     506               0 :             NS_ABORT_IF_FALSE(false, "unexpected unit");
     507               0 :             return false;
     508                 :         }
     509               0 :         squareDistance += diff * diff;
     510                 :       }
     511                 : 
     512               0 :       aDistance = sqrt(squareDistance);
     513               0 :       return true;
     514                 :     }
     515                 :     case eUnit_Dasharray: {
     516                 :       // NOTE: This produces results on substantially different scales
     517                 :       // for length values and percentage values, which might even be
     518                 :       // mixed in the same property value.  This means the result isn't
     519                 :       // particularly useful for paced animation.
     520                 : 
     521                 :       // Call AddWeighted to make us lists of the same length.
     522               0 :       Value normValue1, normValue2;
     523               0 :       if (!AddWeighted(aProperty, 1.0, aStartValue, 0.0, aEndValue,
     524               0 :                        normValue1) ||
     525                 :           !AddWeighted(aProperty, 0.0, aStartValue, 1.0, aEndValue,
     526               0 :                        normValue2)) {
     527               0 :         return false;
     528                 :       }
     529                 : 
     530               0 :       double squareDistance = 0.0;
     531               0 :       const nsCSSValueList *list1 = normValue1.GetCSSValueListValue();
     532               0 :       const nsCSSValueList *list2 = normValue2.GetCSSValueListValue();
     533                 : 
     534               0 :       NS_ABORT_IF_FALSE(!list1 == !list2, "lists should be same length");
     535               0 :       while (list1) {
     536               0 :         const nsCSSValue &val1 = list1->mValue;
     537               0 :         const nsCSSValue &val2 = list2->mValue;
     538                 : 
     539               0 :         NS_ABORT_IF_FALSE(val1.GetUnit() == val2.GetUnit(),
     540                 :                           "unit match should be assured by AddWeighted");
     541                 :         double diff;
     542               0 :         switch (val1.GetUnit()) {
     543                 :           case eCSSUnit_Percent:
     544               0 :             diff = val1.GetPercentValue() - val2.GetPercentValue();
     545               0 :             break;
     546                 :           case eCSSUnit_Number:
     547               0 :             diff = val1.GetFloatValue() - val2.GetFloatValue();
     548               0 :             break;
     549                 :           default:
     550               0 :             NS_ABORT_IF_FALSE(false, "unexpected unit");
     551               0 :             return false;
     552                 :         }
     553               0 :         squareDistance += diff * diff;
     554                 : 
     555               0 :         list1 = list1->mNext;
     556               0 :         list2 = list2->mNext;
     557               0 :         NS_ABORT_IF_FALSE(!list1 == !list2, "lists should be same length");
     558                 :       }
     559                 : 
     560               0 :       aDistance = sqrt(squareDistance);
     561               0 :       return true;
     562                 :     }
     563                 :     case eUnit_Shadow: {
     564                 :       // Call AddWeighted to make us lists of the same length.
     565               0 :       Value normValue1, normValue2;
     566               0 :       if (!AddWeighted(aProperty, 1.0, aStartValue, 0.0, aEndValue,
     567               0 :                        normValue1) ||
     568                 :           !AddWeighted(aProperty, 0.0, aStartValue, 1.0, aEndValue,
     569               0 :                        normValue2)) {
     570               0 :         return false;
     571                 :       }
     572                 : 
     573               0 :       const nsCSSValueList *shadow1 = normValue1.GetCSSValueListValue();
     574               0 :       const nsCSSValueList *shadow2 = normValue2.GetCSSValueListValue();
     575                 : 
     576               0 :       double squareDistance = 0.0;
     577               0 :       NS_ABORT_IF_FALSE(!shadow1 == !shadow2, "lists should be same length");
     578               0 :       while (shadow1) {
     579               0 :         nsCSSValue::Array *array1 = shadow1->mValue.GetArrayValue();
     580               0 :         nsCSSValue::Array *array2 = shadow2->mValue.GetArrayValue();
     581               0 :         for (size_t i = 0; i < 4; ++i) {
     582               0 :           NS_ABORT_IF_FALSE(array1->Item(i).GetUnit() == eCSSUnit_Pixel,
     583                 :                             "unexpected unit");
     584               0 :           NS_ABORT_IF_FALSE(array2->Item(i).GetUnit() == eCSSUnit_Pixel,
     585                 :                             "unexpected unit");
     586               0 :           double diff = array1->Item(i).GetFloatValue() -
     587               0 :                         array2->Item(i).GetFloatValue();
     588               0 :           squareDistance += diff * diff;
     589                 :         }
     590                 : 
     591               0 :         const nsCSSValue &color1 = array1->Item(4);
     592               0 :         const nsCSSValue &color2 = array2->Item(4);
     593                 : #ifdef DEBUG
     594                 :         {
     595               0 :           const nsCSSValue &inset1 = array1->Item(5);
     596               0 :           const nsCSSValue &inset2 = array2->Item(5);
     597                 :           // There are only two possible states of the inset value:
     598                 :           //  (1) GetUnit() == eCSSUnit_Null
     599                 :           //  (2) GetUnit() == eCSSUnit_Enumerated &&
     600                 :           //      GetIntValue() == NS_STYLE_BOX_SHADOW_INSET
     601               0 :           NS_ABORT_IF_FALSE(color1.GetUnit() == color2.GetUnit() &&
     602                 :                             inset1 == inset2,
     603                 :                             "AddWeighted should have failed");
     604                 :         }
     605                 : #endif
     606                 : 
     607               0 :         if (color1.GetUnit() != eCSSUnit_Null) {
     608                 :           nsStyleAnimation::Value color1Value
     609               0 :             (color1.GetColorValue(), nsStyleAnimation::Value::ColorConstructor);
     610                 :           nsStyleAnimation::Value color2Value
     611               0 :             (color2.GetColorValue(), nsStyleAnimation::Value::ColorConstructor);
     612                 :           double colorDistance;
     613                 : 
     614                 :         #ifdef DEBUG
     615                 :           bool ok =
     616                 :         #endif
     617                 :             nsStyleAnimation::ComputeDistance(eCSSProperty_color,
     618                 :                                               color1Value, color2Value,
     619               0 :                                               colorDistance);
     620               0 :           NS_ABORT_IF_FALSE(ok, "should not fail");
     621               0 :           squareDistance += colorDistance * colorDistance;
     622                 :         }
     623                 : 
     624               0 :         shadow1 = shadow1->mNext;
     625               0 :         shadow2 = shadow2->mNext;
     626               0 :         NS_ABORT_IF_FALSE(!shadow1 == !shadow2, "lists should be same length");
     627                 :       }
     628               0 :       aDistance = sqrt(squareDistance);
     629               0 :       return true;
     630                 :     }
     631                 :     case eUnit_Transform: {
     632               0 :       return false;
     633                 :     }
     634                 :     case eUnit_BackgroundPosition: {
     635               0 :       const nsCSSValueList *position1 = aStartValue.GetCSSValueListValue();
     636               0 :       const nsCSSValueList *position2 = aEndValue.GetCSSValueListValue();
     637                 : 
     638               0 :       double squareDistance = 0.0;
     639               0 :       NS_ABORT_IF_FALSE(!position1 == !position2, "lists should be same length");
     640                 : 
     641               0 :       while (position1 && position2) {
     642               0 :         NS_ASSERTION(position1->mValue.GetUnit() == eCSSUnit_Array &&
     643                 :                      position2->mValue.GetUnit() == eCSSUnit_Array,
     644                 :                      "Expected two arrays");
     645                 : 
     646                 :         CalcValue calcVal[4];
     647                 : 
     648               0 :         nsCSSValue::Array* bgArray = position1->mValue.GetArrayValue();
     649               0 :         NS_ABORT_IF_FALSE(bgArray->Count() == 4, "Invalid background-position");
     650               0 :         NS_ASSERTION(bgArray->Item(0).GetUnit() == eCSSUnit_Null &&
     651                 :                      bgArray->Item(2).GetUnit() == eCSSUnit_Null,
     652                 :                      "Invalid list used");
     653               0 :         for (int i = 0; i < 2; ++i) {
     654               0 :           NS_ABORT_IF_FALSE(bgArray->Item(i*2+1).GetUnit() != eCSSUnit_Null,
     655                 :                             "Invalid background-position");
     656               0 :           calcVal[i] = ExtractCalcValue(bgArray->Item(i*2+1));
     657                 :         }
     658                 : 
     659               0 :         bgArray = position2->mValue.GetArrayValue();
     660               0 :         NS_ABORT_IF_FALSE(bgArray->Count() == 4, "Invalid background-position");
     661               0 :         NS_ASSERTION(bgArray->Item(0).GetUnit() == eCSSUnit_Null &&
     662                 :                      bgArray->Item(2).GetUnit() == eCSSUnit_Null,
     663                 :                      "Invalid list used");
     664               0 :         for (int i = 0; i < 2; ++i) {
     665               0 :           NS_ABORT_IF_FALSE(bgArray->Item(i*2+1).GetUnit() != eCSSUnit_Null,
     666                 :                             "Invalid background-position");
     667               0 :           calcVal[i+2] = ExtractCalcValue(bgArray->Item(i*2+1));
     668                 :         }
     669                 : 
     670               0 :         for (int i = 0; i < 2; ++i) {
     671               0 :           float difflen = calcVal[i+2].mLength - calcVal[i].mLength;
     672               0 :           float diffpct = calcVal[i+2].mPercent - calcVal[i].mPercent;
     673               0 :           squareDistance += difflen * difflen + diffpct * diffpct;
     674                 :         }
     675                 : 
     676               0 :         position1 = position1->mNext;
     677               0 :         position2 = position2->mNext;
     678                 :       }
     679                 :       // fail if lists differ in length.
     680               0 :       if (position1 || position2) {
     681               0 :         return false;
     682                 :       }
     683                 : 
     684               0 :       aDistance = sqrt(squareDistance);
     685               0 :       return true;
     686                 :     }
     687                 :     case eUnit_CSSValuePairList: {
     688               0 :       const nsCSSValuePairList *list1 = aStartValue.GetCSSValuePairListValue();
     689               0 :       const nsCSSValuePairList *list2 = aEndValue.GetCSSValuePairListValue();
     690               0 :       double squareDistance = 0.0;
     691               0 :       do {
     692                 :         static nsCSSValue nsCSSValuePairList::* const pairListValues[] = {
     693                 :           &nsCSSValuePairList::mXValue,
     694                 :           &nsCSSValuePairList::mYValue,
     695                 :         };
     696               0 :         for (PRUint32 i = 0; i < ArrayLength(pairListValues); ++i) {
     697               0 :           const nsCSSValue &v1 = list1->*(pairListValues[i]);
     698               0 :           const nsCSSValue &v2 = list2->*(pairListValues[i]);
     699                 :           nsCSSUnit unit =
     700               0 :             GetCommonUnit(aProperty, v1.GetUnit(), v2.GetUnit());
     701               0 :           if (unit == eCSSUnit_Null) {
     702               0 :             return false;
     703                 :           }
     704               0 :           double diffsquared = 0.0;
     705               0 :           switch (unit) {
     706                 :             case eCSSUnit_Pixel: {
     707               0 :               float diff = v1.GetFloatValue() - v2.GetFloatValue();
     708               0 :               diffsquared = diff * diff;
     709               0 :               break;
     710                 :             }
     711                 :             case eCSSUnit_Percent: {
     712               0 :               float diff = v1.GetPercentValue() - v2.GetPercentValue();
     713               0 :               diffsquared = diff * diff;
     714               0 :               break;
     715                 :             }
     716                 :             case eCSSUnit_Calc: {
     717               0 :               CalcValue val1 = ExtractCalcValue(v1);
     718               0 :               CalcValue val2 = ExtractCalcValue(v2);
     719               0 :               float difflen = val2.mLength - val1.mLength;
     720               0 :               float diffpct = val2.mPercent - val1.mPercent;
     721               0 :               diffsquared = difflen * difflen + diffpct * diffpct;
     722               0 :               break;
     723                 :             }
     724                 :             default:
     725               0 :               if (v1 != v2) {
     726               0 :                 return false;
     727                 :               }
     728               0 :               break;
     729                 :           }
     730               0 :           squareDistance += diffsquared;
     731                 :         }
     732               0 :         list1 = list1->mNext;
     733               0 :         list2 = list2->mNext;
     734                 :       } while (list1 && list2);
     735               0 :       if (list1 || list2) {
     736                 :         // We can't interpolate lists of different lengths.
     737               0 :         return false;
     738                 :       }
     739               0 :       aDistance = sqrt(squareDistance);
     740               0 :       return true;
     741                 :     }
     742                 :   }
     743                 : 
     744               0 :   NS_ABORT_IF_FALSE(false, "Can't compute distance using the given common unit");
     745               0 :   return false;
     746                 : }
     747                 : 
     748                 : #define MAX_PACKED_COLOR_COMPONENT 255
     749                 : 
     750               0 : inline PRUint8 ClampColor(double aColor)
     751                 : {
     752               0 :   if (aColor >= MAX_PACKED_COLOR_COMPONENT)
     753               0 :     return MAX_PACKED_COLOR_COMPONENT;
     754               0 :   if (aColor <= 0.0)
     755               0 :     return 0;
     756               0 :   return NSToIntRound(aColor);
     757                 : }
     758                 : 
     759                 : template <typename T>
     760                 : T
     761               0 : RestrictValue(PRUint32 aRestrictions, T aValue)
     762                 : {
     763               0 :   T result = aValue;
     764               0 :   switch (aRestrictions) {
     765                 :     case 0:
     766               0 :       break;
     767                 :     case CSS_PROPERTY_VALUE_NONNEGATIVE:
     768               0 :       if (result < 0) {
     769               0 :         result = 0;
     770                 :       }
     771               0 :       break;
     772                 :     case CSS_PROPERTY_VALUE_AT_LEAST_ONE:
     773               0 :       if (result < 1) {
     774               0 :         result = 1;
     775                 :       }
     776               0 :       break;
     777                 :     default:
     778               0 :       NS_ABORT_IF_FALSE(false, "bad value restriction");
     779               0 :       break;
     780                 :   }
     781               0 :   return result;
     782                 : }
     783                 : 
     784                 : template <typename T>
     785                 : T
     786               0 : RestrictValue(nsCSSProperty aProperty, T aValue)
     787                 : {
     788               0 :   return RestrictValue(nsCSSProps::ValueRestrictions(aProperty), aValue);
     789                 : }
     790                 : 
     791                 : static inline void
     792               0 : AddCSSValuePixel(double aCoeff1, const nsCSSValue &aValue1,
     793                 :                  double aCoeff2, const nsCSSValue &aValue2,
     794                 :                  nsCSSValue &aResult, PRUint32 aValueRestrictions = 0)
     795                 : {
     796               0 :   NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Pixel, "unexpected unit");
     797               0 :   NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Pixel, "unexpected unit");
     798                 :   aResult.SetFloatValue(RestrictValue(aValueRestrictions,
     799               0 :                                       aCoeff1 * aValue1.GetFloatValue() +
     800               0 :                                       aCoeff2 * aValue2.GetFloatValue()),
     801               0 :                         eCSSUnit_Pixel);
     802               0 : }
     803                 : 
     804                 : static inline void
     805               0 : AddCSSValueNumber(double aCoeff1, const nsCSSValue &aValue1,
     806                 :                   double aCoeff2, const nsCSSValue &aValue2,
     807                 :                   nsCSSValue &aResult, PRUint32 aValueRestrictions = 0)
     808                 : {
     809               0 :   NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Number, "unexpected unit");
     810               0 :   NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Number, "unexpected unit");
     811                 :   aResult.SetFloatValue(RestrictValue(aValueRestrictions,
     812               0 :                                       aCoeff1 * aValue1.GetFloatValue() +
     813               0 :                                       aCoeff2 * aValue2.GetFloatValue()),
     814               0 :                         eCSSUnit_Number);
     815               0 : }
     816                 : 
     817                 : static inline void
     818               0 : AddCSSValuePercent(double aCoeff1, const nsCSSValue &aValue1,
     819                 :                    double aCoeff2, const nsCSSValue &aValue2,
     820                 :                    nsCSSValue &aResult, PRUint32 aValueRestrictions = 0)
     821                 : {
     822               0 :   NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Percent, "unexpected unit");
     823               0 :   NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Percent, "unexpected unit");
     824                 :   aResult.SetPercentValue(RestrictValue(aValueRestrictions,
     825               0 :                                         aCoeff1 * aValue1.GetPercentValue() +
     826               0 :                                         aCoeff2 * aValue2.GetPercentValue()));
     827               0 : }
     828                 : 
     829                 : // Add two canonical-form calc values (eUnit_Calc) to make another
     830                 : // canonical-form calc value.
     831                 : static void
     832               0 : AddCSSValueCanonicalCalc(double aCoeff1, const nsCSSValue &aValue1,
     833                 :                          double aCoeff2, const nsCSSValue &aValue2,
     834                 :                          nsCSSValue &aResult)
     835                 : {
     836               0 :   CalcValue v1 = ExtractCalcValue(aValue1);
     837               0 :   CalcValue v2 = ExtractCalcValue(aValue2);
     838               0 :   NS_ABORT_IF_FALSE(v1.mHasPercent || v2.mHasPercent,
     839                 :                     "only used on properties that always have percent in calc");
     840               0 :   nsRefPtr<nsCSSValue::Array> a = nsCSSValue::Array::Create(2),
     841               0 :                               acalc = nsCSSValue::Array::Create(1);
     842               0 :   a->Item(0).SetFloatValue(aCoeff1 * v1.mLength + aCoeff2 * v2.mLength,
     843               0 :                            eCSSUnit_Pixel);
     844               0 :   a->Item(1).SetPercentValue(aCoeff1 * v1.mPercent + aCoeff2 * v2.mPercent);
     845               0 :   acalc->Item(0).SetArrayValue(a, eCSSUnit_Calc_Plus);
     846               0 :   aResult.SetArrayValue(acalc, eCSSUnit_Calc);
     847               0 : }
     848                 : 
     849                 : static void
     850               0 : AddCSSValueAngle(const nsCSSValue &aValue1, double aCoeff1,
     851                 :                  const nsCSSValue &aValue2, double aCoeff2,
     852                 :                  nsCSSValue &aResult)
     853                 : {
     854               0 :   aResult.SetFloatValue(aCoeff1 * aValue1.GetAngleValueInRadians() +
     855               0 :                         aCoeff2 * aValue2.GetAngleValueInRadians(),
     856               0 :                         eCSSUnit_Radian);
     857               0 : }
     858                 : 
     859                 : static bool
     860               0 : AddCSSValuePixelPercentCalc(const PRUint32 aValueRestrictions,
     861                 :                             const nsCSSUnit aCommonUnit,
     862                 :                             double aCoeff1, const nsCSSValue &aValue1,
     863                 :                             double aCoeff2, const nsCSSValue &aValue2,
     864                 :                             nsCSSValue &aResult)
     865                 : {
     866               0 :   switch (aCommonUnit) {
     867                 :     case eCSSUnit_Pixel:
     868                 :       AddCSSValuePixel(aCoeff1, aValue1,
     869                 :                        aCoeff2, aValue2,
     870               0 :                        aResult, aValueRestrictions);
     871               0 :       break;
     872                 :     case eCSSUnit_Percent:
     873                 :       AddCSSValuePercent(aCoeff1, aValue1,
     874                 :                          aCoeff2, aValue2,
     875               0 :                          aResult, aValueRestrictions);
     876               0 :       break;
     877                 :     case eCSSUnit_Calc:
     878                 :       AddCSSValueCanonicalCalc(aCoeff1, aValue1,
     879                 :                                aCoeff2, aValue2,
     880               0 :                                aResult);
     881               0 :       break;
     882                 :     default:
     883               0 :       return false;
     884                 :   }
     885                 : 
     886               0 :   return true;
     887                 : }
     888                 : 
     889                 : static bool
     890               0 : AddShadowItems(double aCoeff1, const nsCSSValue &aValue1,
     891                 :                double aCoeff2, const nsCSSValue &aValue2,
     892                 :                nsCSSValueList **&aResultTail)
     893                 : {
     894                 :   // X, Y, Radius, Spread, Color, Inset
     895               0 :   NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Array,
     896                 :                     "wrong unit");
     897               0 :   NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Array,
     898                 :                     "wrong unit");
     899               0 :   nsCSSValue::Array *array1 = aValue1.GetArrayValue();
     900               0 :   nsCSSValue::Array *array2 = aValue2.GetArrayValue();
     901               0 :   nsRefPtr<nsCSSValue::Array> resultArray = nsCSSValue::Array::Create(6);
     902                 : 
     903               0 :   for (size_t i = 0; i < 4; ++i) {
     904               0 :     AddCSSValuePixel(aCoeff1, array1->Item(i), aCoeff2, array2->Item(i),
     905               0 :                      resultArray->Item(i),
     906                 :                      // blur radius must be nonnegative
     907               0 :                      (i == 2) ? CSS_PROPERTY_VALUE_NONNEGATIVE : 0);
     908                 :   }
     909                 : 
     910               0 :   const nsCSSValue& color1 = array1->Item(4);
     911               0 :   const nsCSSValue& color2 = array2->Item(4);
     912               0 :   const nsCSSValue& inset1 = array1->Item(5);
     913               0 :   const nsCSSValue& inset2 = array2->Item(5);
     914               0 :   if (color1.GetUnit() != color2.GetUnit() ||
     915               0 :       inset1.GetUnit() != inset2.GetUnit()) {
     916                 :     // We don't know how to animate between color and no-color, or
     917                 :     // between inset and not-inset.
     918               0 :     return false;
     919                 :   }
     920                 : 
     921               0 :   if (color1.GetUnit() != eCSSUnit_Null) {
     922                 :     nsStyleAnimation::Value color1Value
     923               0 :       (color1.GetColorValue(), nsStyleAnimation::Value::ColorConstructor);
     924                 :     nsStyleAnimation::Value color2Value
     925               0 :       (color2.GetColorValue(), nsStyleAnimation::Value::ColorConstructor);
     926               0 :     nsStyleAnimation::Value resultColorValue;
     927                 :   #ifdef DEBUG
     928                 :     bool ok =
     929                 :   #endif
     930                 :       nsStyleAnimation::AddWeighted(eCSSProperty_color, aCoeff1, color1Value,
     931               0 :                                     aCoeff2, color2Value, resultColorValue);
     932               0 :     NS_ABORT_IF_FALSE(ok, "should not fail");
     933               0 :     resultArray->Item(4).SetColorValue(resultColorValue.GetColorValue());
     934                 :   }
     935                 : 
     936               0 :   NS_ABORT_IF_FALSE(inset1 == inset2, "should match");
     937               0 :   resultArray->Item(5) = inset1;
     938                 : 
     939               0 :   nsCSSValueList *resultItem = new nsCSSValueList;
     940               0 :   if (!resultItem) {
     941               0 :     return false;
     942                 :   }
     943               0 :   resultItem->mValue.SetArrayValue(resultArray, eCSSUnit_Array);
     944               0 :   *aResultTail = resultItem;
     945               0 :   aResultTail = &resultItem->mNext;
     946               0 :   return true;
     947                 : }
     948                 : 
     949                 : static void
     950               0 : AddTransformTranslate(const nsCSSValue &aValue1, double aCoeff1,
     951                 :                       const nsCSSValue &aValue2, double aCoeff2,
     952                 :                       nsCSSValue &aResult)
     953                 : {
     954               0 :   NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Percent ||
     955                 :                     aValue1.GetUnit() == eCSSUnit_Pixel ||
     956                 :                     aValue1.IsCalcUnit(),
     957                 :                     "unexpected unit");
     958               0 :   NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Percent ||
     959                 :                     aValue2.GetUnit() == eCSSUnit_Pixel ||
     960                 :                     aValue2.IsCalcUnit(),
     961                 :                     "unexpected unit");
     962                 : 
     963               0 :   if (aValue1.GetUnit() != aValue2.GetUnit() || aValue1.IsCalcUnit()) {
     964                 :     // different units; create a calc() expression
     965               0 :     AddCSSValueCanonicalCalc(aCoeff1, aValue1, aCoeff2, aValue2, aResult);
     966               0 :   } else if (aValue1.GetUnit() == eCSSUnit_Percent) {
     967                 :     // both percent
     968               0 :     AddCSSValuePercent(aCoeff1, aValue1, aCoeff2, aValue2, aResult);
     969                 :   } else {
     970                 :     // both pixels
     971               0 :     AddCSSValuePixel(aCoeff1, aValue1, aCoeff2, aValue2, aResult);
     972                 :   }
     973               0 : }
     974                 : 
     975                 : static void
     976               0 : AddTransformScale(const nsCSSValue &aValue1, double aCoeff1,
     977                 :                   const nsCSSValue &aValue2, double aCoeff2,
     978                 :                   nsCSSValue &aResult)
     979                 : {
     980                 :   // Handle scale, and the two matrix components where identity is 1, by
     981                 :   // subtracting 1, multiplying by the coefficients, and then adding 1
     982                 :   // back.  This gets the right AddWeighted behavior and gets us the
     983                 :   // interpolation-against-identity behavior for free.
     984               0 :   NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Number, "unexpected unit");
     985               0 :   NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Number, "unexpected unit");
     986                 : 
     987               0 :   float v1 = aValue1.GetFloatValue() - 1.0f,
     988               0 :         v2 = aValue2.GetFloatValue() - 1.0f;
     989               0 :   float result = v1 * aCoeff1 + v2 * aCoeff2;
     990               0 :   aResult.SetFloatValue(result + 1.0f, eCSSUnit_Number);
     991               0 : }
     992                 : 
     993                 : static already_AddRefed<nsCSSValue::Array>
     994               0 : AppendTransformFunction(nsCSSKeyword aTransformFunction,
     995                 :                         nsCSSValueList**& aListTail)
     996                 : {
     997                 :   PRUint32 nargs;
     998               0 :   switch (aTransformFunction) {
     999                 :     case eCSSKeyword_matrix3d:
    1000               0 :       nargs = 16;
    1001               0 :       break;
    1002                 :     case eCSSKeyword_matrix:
    1003               0 :       nargs = 6;
    1004               0 :       break;
    1005                 :     case eCSSKeyword_rotate3d:
    1006               0 :       nargs = 4;
    1007               0 :       break;
    1008                 :     case eCSSKeyword_interpolatematrix:
    1009                 :     case eCSSKeyword_translate3d:
    1010                 :     case eCSSKeyword_scale3d:
    1011               0 :       nargs = 3;
    1012               0 :       break;
    1013                 :     case eCSSKeyword_translate:
    1014                 :     case eCSSKeyword_skew:
    1015                 :     case eCSSKeyword_scale:
    1016               0 :       nargs = 2;
    1017               0 :       break;
    1018                 :     default:
    1019               0 :       NS_ERROR("must be a transform function");
    1020                 :     case eCSSKeyword_translatex:
    1021                 :     case eCSSKeyword_translatey:
    1022                 :     case eCSSKeyword_translatez:
    1023                 :     case eCSSKeyword_scalex:
    1024                 :     case eCSSKeyword_scaley:
    1025                 :     case eCSSKeyword_scalez:
    1026                 :     case eCSSKeyword_skewx:
    1027                 :     case eCSSKeyword_skewy:
    1028                 :     case eCSSKeyword_rotate:
    1029                 :     case eCSSKeyword_rotatex:
    1030                 :     case eCSSKeyword_rotatey:
    1031                 :     case eCSSKeyword_rotatez:
    1032                 :     case eCSSKeyword_perspective:
    1033               0 :       nargs = 1;
    1034               0 :       break;
    1035                 :   }
    1036                 : 
    1037               0 :   nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(nargs + 1);
    1038               0 :   arr->Item(0).SetStringValue(
    1039               0 :     NS_ConvertUTF8toUTF16(nsCSSKeywords::GetStringValue(aTransformFunction)),
    1040               0 :     eCSSUnit_Ident);
    1041                 : 
    1042               0 :   nsCSSValueList *item = new nsCSSValueList;
    1043               0 :   item->mValue.SetArrayValue(arr, eCSSUnit_Function);
    1044                 : 
    1045               0 :   *aListTail = item;
    1046               0 :   aListTail = &item->mNext;
    1047                 : 
    1048               0 :   return arr.forget();
    1049                 : }
    1050                 : 
    1051                 : /*
    1052                 :  * The relevant section of the transitions specification:
    1053                 :  * http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types-
    1054                 :  * defers all of the details to the 2-D and 3-D transforms specifications.
    1055                 :  * For the 2-D transforms specification (all that's relevant for us, right
    1056                 :  * now), the relevant section is:
    1057                 :  * http://dev.w3.org/csswg/css3-2d-transforms/#animation
    1058                 :  * This, in turn, refers to the unmatrix program in Graphics Gems,
    1059                 :  * available from http://tog.acm.org/resources/GraphicsGems/ , and in
    1060                 :  * particular as the file GraphicsGems/gemsii/unmatrix.c
    1061                 :  * in http://tog.acm.org/resources/GraphicsGems/AllGems.tar.gz
    1062                 :  *
    1063                 :  * The unmatrix reference is for general 3-D transform matrices (any of the
    1064                 :  * 16 components can have any value).
    1065                 :  *
    1066                 :  * For CSS 2-D transforms, we have a 2-D matrix with the bottom row constant:
    1067                 :  *
    1068                 :  * [ A C E ]
    1069                 :  * [ B D F ]
    1070                 :  * [ 0 0 1 ]
    1071                 :  *
    1072                 :  * For that case, I believe the algorithm in unmatrix reduces to:
    1073                 :  *
    1074                 :  *  (1) If A * D - B * C == 0, the matrix is singular.  Fail.
    1075                 :  *
    1076                 :  *  (2) Set translation components (Tx and Ty) to the translation parts of
    1077                 :  *      the matrix (E and F) and then ignore them for the rest of the time.
    1078                 :  *      (For us, E and F each actually consist of three constants:  a
    1079                 :  *      length, a multiplier for the width, and a multiplier for the
    1080                 :  *      height.  This actually requires its own decomposition, but I'll
    1081                 :  *      keep that separate.)
    1082                 :  *
    1083                 :  *  (3) Let the X scale (Sx) be sqrt(A^2 + B^2).  Then divide both A and B
    1084                 :  *      by it.
    1085                 :  *
    1086                 :  *  (4) Let the XY shear (K) be A * C + B * D.  From C, subtract A times
    1087                 :  *      the XY shear.  From D, subtract B times the XY shear.
    1088                 :  *
    1089                 :  *  (5) Let the Y scale (Sy) be sqrt(C^2 + D^2).  Divide C, D, and the XY
    1090                 :  *      shear (K) by it.
    1091                 :  *
    1092                 :  *  (6) At this point, A * D - B * C is either 1 or -1.  If it is -1,
    1093                 :  *      negate the XY shear (K), the X scale (Sx), and A, B, C, and D.
    1094                 :  *      (Alternatively, we could negate the XY shear (K) and the Y scale
    1095                 :  *      (Sy).)
    1096                 :  *
    1097                 :  *  (7) Let the rotation be R = atan2(B, A).
    1098                 :  *
    1099                 :  * Then the resulting decomposed transformation is:
    1100                 :  *
    1101                 :  *   translate(Tx, Ty) rotate(R) skewX(atan(K)) scale(Sx, Sy)
    1102                 :  *
    1103                 :  * An interesting result of this is that all of the simple transform
    1104                 :  * functions (i.e., all functions other than matrix()), in isolation,
    1105                 :  * decompose back to themselves except for:
    1106                 :  *   'skewY(φ)', which is 'matrix(1, tan(φ), 0, 1, 0, 0)', which decomposes
    1107                 :  *   to 'rotate(φ) skewX(φ) scale(sec(φ), cos(φ))' since (ignoring the
    1108                 :  *   alternate sign possibilities that would get fixed in step 6):
    1109                 :  *     In step 3, the X scale factor is sqrt(1+tan²(φ)) = sqrt(sec²(φ)) = sec(φ).
    1110                 :  *     Thus, after step 3, A = 1/sec(φ) = cos(φ) and B = tan(φ) / sec(φ) = sin(φ).
    1111                 :  *     In step 4, the XY shear is sin(φ).
    1112                 :  *     Thus, after step 4, C = -cos(φ)sin(φ) and D = 1 - sin²(φ) = cos²(φ).
    1113                 :  *     Thus, in step 5, the Y scale is sqrt(cos²(φ)(sin²(φ) + cos²(φ)) = cos(φ).
    1114                 :  *     Thus, after step 5, C = -sin(φ), D = cos(φ), and the XY shear is tan(φ).
    1115                 :  *     Thus, in step 6, A * D - B * C = cos²(φ) + sin²(φ) = 1.
    1116                 :  *     In step 7, the rotation is thus φ.
    1117                 :  *
    1118                 :  *   skew(θ, φ), which is matrix(1, tan(φ), tan(θ), 1, 0, 0), which decomposes
    1119                 :  *   to 'rotate(φ) skewX(θ + φ) scale(sec(φ), cos(φ))' since (ignoring
    1120                 :  *   the alternate sign possibilities that would get fixed in step 6):
    1121                 :  *     In step 3, the X scale factor is sqrt(1+tan²(φ)) = sqrt(sec²(φ)) = sec(φ).
    1122                 :  *     Thus, after step 3, A = 1/sec(φ) = cos(φ) and B = tan(φ) / sec(φ) = sin(φ).
    1123                 :  *     In step 4, the XY shear is cos(φ)tan(θ) + sin(φ).
    1124                 :  *     Thus, after step 4,
    1125                 :  *     C = tan(θ) - cos(φ)(cos(φ)tan(θ) + sin(φ)) = tan(θ)sin²(φ) - cos(φ)sin(φ)
    1126                 :  *     D = 1 - sin(φ)(cos(φ)tan(θ) + sin(φ)) = cos²(φ) - sin(φ)cos(φ)tan(θ)
    1127                 :  *     Thus, in step 5, the Y scale is sqrt(C² + D²) =
    1128                 :  *     sqrt(tan²(θ)(sin⁴(φ) + sin²(φ)cos²(φ)) -
    1129                 :  *          2 tan(θ)(sin³(φ)cos(φ) + sin(φ)cos³(φ)) +
    1130                 :  *          (sin²(φ)cos²(φ) + cos⁴(φ))) =
    1131                 :  *     sqrt(tan²(θ)sin²(φ) - 2 tan(θ)sin(φ)cos(φ) + cos²(φ)) =
    1132                 :  *     cos(φ) - tan(θ)sin(φ) (taking the negative of the obvious solution so
    1133                 :  *     we avoid flipping in step 6).
    1134                 :  *     After step 5, C = -sin(φ) and D = cos(φ), and the XY shear is
    1135                 :  *     (cos(φ)tan(θ) + sin(φ)) / (cos(φ) - tan(θ)sin(φ)) =
    1136                 :  *     (dividing both numerator and denominator by cos(φ))
    1137                 :  *     (tan(θ) + tan(φ)) / (1 - tan(θ)tan(φ)) = tan(θ + φ).
    1138                 :  *     (See http://en.wikipedia.org/wiki/List_of_trigonometric_identities .)
    1139                 :  *     Thus, in step 6, A * D - B * C = cos²(φ) + sin²(φ) = 1.
    1140                 :  *     In step 7, the rotation is thus φ.
    1141                 :  *
    1142                 :  *     To check this result, we can multiply things back together:
    1143                 :  *
    1144                 :  *     [ cos(φ) -sin(φ) ] [ 1 tan(θ + φ) ] [ sec(φ)    0   ]
    1145                 :  *     [ sin(φ)  cos(φ) ] [ 0      1     ] [   0    cos(φ) ]
    1146                 :  *
    1147                 :  *     [ cos(φ)      cos(φ)tan(θ + φ) - sin(φ) ] [ sec(φ)    0   ]
    1148                 :  *     [ sin(φ)      sin(φ)tan(θ + φ) + cos(φ) ] [   0    cos(φ) ]
    1149                 :  *
    1150                 :  *     but since tan(θ + φ) = (tan(θ) + tan(φ)) / (1 - tan(θ)tan(φ)),
    1151                 :  *     cos(φ)tan(θ + φ) - sin(φ)
    1152                 :  *      = cos(φ)(tan(θ) + tan(φ)) - sin(φ) + sin(φ)tan(θ)tan(φ)
    1153                 :  *      = cos(φ)tan(θ) + sin(φ) - sin(φ) + sin(φ)tan(θ)tan(φ)
    1154                 :  *      = cos(φ)tan(θ) + sin(φ)tan(θ)tan(φ)
    1155                 :  *      = tan(θ) (cos(φ) + sin(φ)tan(φ))
    1156                 :  *      = tan(θ) sec(φ) (cos²(φ) + sin²(φ))
    1157                 :  *      = tan(θ) sec(φ)
    1158                 :  *     and
    1159                 :  *     sin(φ)tan(θ + φ) + cos(φ)
    1160                 :  *      = sin(φ)(tan(θ) + tan(φ)) + cos(φ) - cos(φ)tan(θ)tan(φ)
    1161                 :  *      = tan(θ) (sin(φ) - sin(φ)) + sin(φ)tan(φ) + cos(φ)
    1162                 :  *      = sec(φ) (sin²(φ) + cos²(φ))
    1163                 :  *      = sec(φ)
    1164                 :  *     so the above is:
    1165                 :  *     [ cos(φ)  tan(θ) sec(φ) ] [ sec(φ)    0   ]
    1166                 :  *     [ sin(φ)     sec(φ)     ] [   0    cos(φ) ]
    1167                 :  *
    1168                 :  *     [    1   tan(θ) ]
    1169                 :  *     [ tan(φ)    1   ]
    1170                 :  */
    1171                 : 
    1172                 : /*
    1173                 :  * Decompose2DMatrix implements the above decomposition algorithm.
    1174                 :  */
    1175                 : 
    1176                 : #define XYSHEAR 0
    1177                 : #define XZSHEAR 1
    1178                 : #define YZSHEAR 2
    1179                 : 
    1180                 : static bool
    1181               0 : Decompose2DMatrix(const gfxMatrix &aMatrix, gfxPoint3D &aScale,
    1182                 :                   float aShear[3], gfxQuaternion &aRotate,
    1183                 :                   gfxPoint3D &aTranslate)
    1184                 : {
    1185               0 :   float A = aMatrix.xx,
    1186               0 :         B = aMatrix.yx,
    1187               0 :         C = aMatrix.xy,
    1188               0 :         D = aMatrix.yy;
    1189               0 :   if (A * D == B * C) {
    1190                 :     // singular matrix
    1191               0 :     return false;
    1192                 :   }
    1193                 : 
    1194               0 :   float scaleX = sqrt(A * A + B * B);
    1195               0 :   A /= scaleX;
    1196               0 :   B /= scaleX;
    1197                 : 
    1198               0 :   float XYshear = A * C + B * D;
    1199               0 :   C -= A * XYshear;
    1200               0 :   D -= B * XYshear;
    1201                 : 
    1202               0 :   float scaleY = sqrt(C * C + D * D);
    1203               0 :   C /= scaleY;
    1204               0 :   D /= scaleY;
    1205               0 :   XYshear /= scaleY;
    1206                 : 
    1207                 :   // A*D - B*C should now be 1 or -1
    1208               0 :   NS_ASSERTION(0.99 < NS_ABS(A*D - B*C) && NS_ABS(A*D - B*C) < 1.01,
    1209                 :                "determinant should now be 1 or -1");
    1210               0 :   if (A * D < B * C) {
    1211               0 :     A = -A;
    1212               0 :     B = -B;
    1213               0 :     C = -C;
    1214               0 :     D = -D;
    1215               0 :     XYshear = -XYshear;
    1216               0 :     scaleX = -scaleX;
    1217                 :   }
    1218                 : 
    1219               0 :   float rotate = atan2f(B, A);
    1220               0 :   aRotate = gfxQuaternion(0, 0, sin(rotate/2), cos(rotate/2));
    1221               0 :   aShear[XYSHEAR] = XYshear;
    1222               0 :   aScale.x = scaleX;
    1223               0 :   aScale.y = scaleY;
    1224               0 :   aTranslate.x = aMatrix.x0;
    1225               0 :   aTranslate.y = aMatrix.y0;
    1226               0 :   return true;
    1227                 : }
    1228                 : 
    1229                 : /**
    1230                 :  * Implementation of the unmatrix algorithm, specified by:
    1231                 :  *
    1232                 :  * http://dev.w3.org/csswg/css3-2d-transforms/#unmatrix
    1233                 :  *
    1234                 :  * This, in turn, refers to the unmatrix program in Graphics Gems,
    1235                 :  * available from http://tog.acm.org/resources/GraphicsGems/ , and in
    1236                 :  * particular as the file GraphicsGems/gemsii/unmatrix.c
    1237                 :  * in http://tog.acm.org/resources/GraphicsGems/AllGems.tar.gz
    1238                 :  */
    1239                 : static bool
    1240               0 : Decompose3DMatrix(const gfx3DMatrix &aMatrix, gfxPoint3D &aScale,
    1241                 :                   float aShear[3], gfxQuaternion &aRotate,
    1242                 :                   gfxPoint3D &aTranslate, gfxPointH3D &aPerspective)
    1243                 : {
    1244               0 :   gfx3DMatrix local = aMatrix;
    1245                 : 
    1246               0 :   if (local[3][3] == 0) {
    1247               0 :     return false;
    1248                 :   }
    1249                 :   /* Normalize the matrix */
    1250               0 :   local.Normalize();
    1251                 : 
    1252                 :   /** 
    1253                 :    * perspective is used to solve for perspective, but it also provides
    1254                 :    * an easy way to test for singularity of the upper 3x3 component.
    1255                 :    */
    1256               0 :   gfx3DMatrix perspective = local;
    1257               0 :   gfxPointH3D empty(0, 0, 0, 1);
    1258               0 :   perspective.SetTransposedVector(3, empty);
    1259                 : 
    1260               0 :   if (perspective.Determinant() == 0.0) {
    1261               0 :     return false;
    1262                 :   }
    1263                 : 
    1264                 :   /* First, isolate perspective. */
    1265               0 :   if (local[0][3] != 0 || local[1][3] != 0 ||
    1266               0 :       local[2][3] != 0) {
    1267                 :     /* aPerspective is the right hand side of the equation. */
    1268               0 :     aPerspective = local.TransposedVector(3);
    1269                 : 
    1270                 :     /** 
    1271                 :      * Solve the equation by inverting perspective and multiplying
    1272                 :      * aPerspective by the inverse.
    1273                 :      */
    1274               0 :     perspective.Invert();
    1275               0 :     aPerspective = perspective.TransposeTransform4D(aPerspective);
    1276                 :     
    1277                 :     /* Clear the perspective partition */
    1278               0 :     local.SetTransposedVector(3, empty);
    1279                 :   } else {
    1280               0 :     aPerspective = gfxPointH3D(0, 0, 0, 1);
    1281                 :   }
    1282                 : 
    1283                 :   /* Next take care of translation */
    1284               0 :   for (int i = 0; i < 3; i++) {
    1285               0 :     aTranslate[i] = local[3][i];
    1286               0 :     local[3][i] = 0;
    1287                 :   }
    1288                 : 
    1289                 :   /* Now get scale and shear. */
    1290                 : 
    1291                 :   /* Compute X scale factor and normalize first row. */
    1292               0 :   aScale.x = local[0].Length();
    1293               0 :   local[0] /= aScale.x;
    1294                 :     
    1295                 :   /* Compute XY shear factor and make 2nd local orthogonal to 1st. */
    1296               0 :   aShear[XYSHEAR] = local[0].DotProduct(local[1]);
    1297               0 :   local[1] -= local[0] * aShear[XYSHEAR];
    1298                 :   
    1299                 :   /* Now, compute Y scale and normalize 2nd local. */
    1300               0 :   aScale.y = local[1].Length();
    1301               0 :   local[1] /= aScale.y;
    1302               0 :   aShear[XYSHEAR] /= aScale.y;
    1303                 : 
    1304                 :   /* Compute XZ and YZ shears, make 3rd local orthogonal */
    1305               0 :   aShear[XZSHEAR] = local[0].DotProduct(local[2]);
    1306               0 :   local[2] -= local[0] * aShear[XZSHEAR];
    1307               0 :   aShear[YZSHEAR] = local[1].DotProduct(local[2]);
    1308               0 :   local[2] -= local[1] * aShear[YZSHEAR];
    1309                 : 
    1310                 :   /* Next, get Z scale and normalize 3rd local. */
    1311               0 :   aScale.z = local[2].Length();
    1312               0 :   local[2] /= aScale.z;
    1313                 : 
    1314               0 :   aShear[XZSHEAR] /= aScale.z;
    1315               0 :   aShear[YZSHEAR] /= aScale.z;
    1316                 : 
    1317                 :   /**
    1318                 :    * At this point, the matrix (in locals) is orthonormal.
    1319                 :    * Check for a coordinate system flip.  If the determinant
    1320                 :    * is -1, then negate the matrix and the scaling factors.
    1321                 :    */
    1322               0 :   if (local[0].DotProduct(local[1].CrossProduct(local[2])) < 0) {
    1323               0 :     aScale *= -1;
    1324               0 :     for (int i = 0; i < 3; i++) {
    1325               0 :       local[i] *= -1;
    1326                 :     }
    1327                 :   }
    1328                 : 
    1329                 :   /* Now, get the rotations out */
    1330               0 :   aRotate = gfxQuaternion(local);
    1331                 : 
    1332               0 :   return true;
    1333                 : }
    1334                 : 
    1335                 : template<typename T>
    1336               0 : T InterpolateNumerically(const T& aOne, const T& aTwo, double aCoeff)
    1337                 : {
    1338               0 :   return aOne + (aTwo - aOne) * aCoeff;
    1339                 : }
    1340                 : 
    1341                 : 
    1342                 : /* static */ gfx3DMatrix
    1343               0 : nsStyleAnimation::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1,
    1344                 :                                              const gfx3DMatrix &aMatrix2,
    1345                 :                                              double aProgress)
    1346                 : {
    1347                 :   // Decompose both matrices
    1348                 : 
    1349                 :   // TODO: What do we do if one of these returns false (singular matrix)
    1350                 : 
    1351               0 :   gfxPoint3D scale1(1, 1, 1), translate1;
    1352               0 :   gfxPointH3D perspective1(0, 0, 0, 1);
    1353               0 :   gfxQuaternion rotate1;
    1354               0 :   float shear1[3] = { 0.0f, 0.0f, 0.0f};
    1355                 : 
    1356               0 :   gfxPoint3D scale2(1, 1, 1), translate2;
    1357               0 :   gfxPointH3D perspective2(0, 0, 0, 1);
    1358               0 :   gfxQuaternion rotate2;
    1359               0 :   float shear2[3] = { 0.0f, 0.0f, 0.0f};
    1360                 : 
    1361               0 :   gfxMatrix matrix2d1, matrix2d2;
    1362               0 :   if (aMatrix1.Is2D(&matrix2d1) && aMatrix2.Is2D(&matrix2d2)) {
    1363               0 :     Decompose2DMatrix(matrix2d1, scale1, shear1, rotate1, translate1);
    1364               0 :     Decompose2DMatrix(matrix2d2, scale2, shear2, rotate2, translate2);
    1365                 :   } else {
    1366                 :     Decompose3DMatrix(aMatrix1, scale1, shear1,
    1367               0 :                       rotate1, translate1, perspective1);
    1368                 :     Decompose3DMatrix(aMatrix2, scale2, shear2,
    1369               0 :                       rotate2, translate2, perspective2);
    1370                 :   }
    1371                 : 
    1372                 :   // Interpolate each of the pieces
    1373               0 :   gfx3DMatrix result;
    1374                 : 
    1375                 :   gfxPointH3D perspective = 
    1376               0 :     InterpolateNumerically(perspective1, perspective2, aProgress);
    1377               0 :   result.SetTransposedVector(3, perspective);
    1378                 :  
    1379                 :   gfxPoint3D translate = 
    1380               0 :     InterpolateNumerically(translate1, translate2, aProgress);
    1381               0 :   result.Translate(translate);
    1382                 : 
    1383               0 :   gfxQuaternion q3 = rotate1.Slerp(rotate2, aProgress);
    1384               0 :   gfx3DMatrix rotate = q3.ToMatrix();
    1385               0 :   if (!rotate.IsIdentity()) {
    1386               0 :       result = rotate * result;
    1387                 :   }
    1388                 : 
    1389                 :   // TODO: Would it be better to interpolate these as angles? How do we convert back to angles?
    1390                 :   float yzshear =
    1391               0 :     InterpolateNumerically(shear1[YZSHEAR], shear2[YZSHEAR], aProgress);
    1392               0 :   if (yzshear != 0.0) {
    1393               0 :     result.SkewYZ(yzshear);
    1394                 :   }
    1395                 : 
    1396                 :   float xzshear =
    1397               0 :     InterpolateNumerically(shear1[XZSHEAR], shear2[XZSHEAR], aProgress);
    1398               0 :   if (xzshear != 0.0) {
    1399               0 :     result.SkewXZ(xzshear);
    1400                 :   }
    1401                 : 
    1402                 :   float xyshear =
    1403               0 :     InterpolateNumerically(shear1[XYSHEAR], shear2[XYSHEAR], aProgress);
    1404               0 :   if (xyshear != 0.0) {
    1405               0 :     result.SkewXY(xyshear);
    1406                 :   }
    1407                 : 
    1408                 :   gfxPoint3D scale = 
    1409               0 :     InterpolateNumerically(scale1, scale2, aProgress);
    1410               0 :   if (scale != gfxPoint3D(1.0, 1.0, 1.0)) {
    1411               0 :     result.Scale(scale.x, scale.y, scale.z);
    1412                 :   }
    1413                 : 
    1414                 :   return result;
    1415                 : }
    1416                 : 
    1417                 : static nsCSSValueList*
    1418               0 : AddDifferentTransformLists(const nsCSSValueList* aList1, double aCoeff1,
    1419                 :                            const nsCSSValueList* aList2, double aCoeff2)
    1420                 : {
    1421               0 :   nsAutoPtr<nsCSSValueList> result;
    1422               0 :   nsCSSValueList **resultTail = getter_Transfers(result);
    1423                 : 
    1424               0 :   nsRefPtr<nsCSSValue::Array> arr;
    1425               0 :   arr = AppendTransformFunction(eCSSKeyword_interpolatematrix, resultTail);
    1426                 :   
    1427                 :   // FIXME: We should change the other transform code to also only
    1428                 :   // take a single progress value, as having values that don't
    1429                 :   // sum to 1 doesn't make sense for these.
    1430               0 :   if (aList1 == aList2) {
    1431               0 :     arr->Item(1).Reset();
    1432                 :   } else {
    1433               0 :     aList1->CloneInto(arr->Item(1).SetListValue());
    1434                 :   }
    1435                 : 
    1436               0 :   aList2->CloneInto(arr->Item(2).SetListValue());
    1437               0 :   arr->Item(3).SetPercentValue(aCoeff2);
    1438                 : 
    1439               0 :   return result.forget();
    1440                 : }
    1441                 : 
    1442                 : static bool
    1443               0 : TransformFunctionsMatch(nsCSSKeyword func1, nsCSSKeyword func2)
    1444                 : {
    1445               0 :   if (func1 == func2) {
    1446               0 :     return true;
    1447                 :   }
    1448                 : 
    1449               0 :   if ((func1 == eCSSKeyword_rotatez && func2 == eCSSKeyword_rotate) ||
    1450                 :       (func1 == eCSSKeyword_rotate && func2 == eCSSKeyword_rotatez)) {
    1451               0 :     return true;
    1452                 :   }
    1453               0 :   return false;
    1454                 : }
    1455                 : 
    1456                 : static nsCSSValueList*
    1457               0 : AddTransformLists(const nsCSSValueList* aList1, double aCoeff1,
    1458                 :                   const nsCSSValueList* aList2, double aCoeff2)
    1459                 : {
    1460               0 :   nsAutoPtr<nsCSSValueList> result;
    1461               0 :   nsCSSValueList **resultTail = getter_Transfers(result);
    1462                 : 
    1463               0 :   do {
    1464               0 :     const nsCSSValue::Array *a1 = aList1->mValue.GetArrayValue(),
    1465               0 :                             *a2 = aList2->mValue.GetArrayValue();
    1466               0 :     NS_ABORT_IF_FALSE(TransformFunctionsMatch(nsStyleTransformMatrix::TransformFunctionOf(a1),
    1467                 :                                               nsStyleTransformMatrix::TransformFunctionOf(a2)),
    1468                 :                       "transform function mismatch");
    1469               0 :     NS_ABORT_IF_FALSE(!*resultTail,
    1470                 :                       "resultTail isn't pointing to the tail (may leak)");
    1471                 : 
    1472               0 :     nsCSSKeyword tfunc = nsStyleTransformMatrix::TransformFunctionOf(a1);
    1473               0 :     nsRefPtr<nsCSSValue::Array> arr;
    1474               0 :     if (tfunc != eCSSKeyword_matrix &&
    1475                 :         tfunc != eCSSKeyword_matrix3d &&
    1476                 :         tfunc != eCSSKeyword_interpolatematrix &&
    1477                 :         tfunc != eCSSKeyword_rotate3d &&
    1478                 :         tfunc != eCSSKeyword_perspective) {
    1479               0 :       arr = AppendTransformFunction(tfunc, resultTail);
    1480                 :     }
    1481                 : 
    1482               0 :     switch (tfunc) {
    1483                 :       case eCSSKeyword_translate: {
    1484               0 :         NS_ABORT_IF_FALSE(a1->Count() == 2 || a1->Count() == 3,
    1485                 :                           "unexpected count");
    1486               0 :         NS_ABORT_IF_FALSE(a2->Count() == 2 || a2->Count() == 3,
    1487                 :                           "unexpected count");
    1488                 : 
    1489                 :         // FIXME: This would produce fewer calc() expressions if the
    1490                 :         // zero were of compatible type (length vs. percent) when
    1491                 :         // needed.
    1492               0 :         nsCSSValue zero(0.0f, eCSSUnit_Pixel);
    1493                 :         // Add Y component of translation.
    1494               0 :         AddTransformTranslate(a1->Count() == 3 ? a1->Item(2) : zero,
    1495                 :                               aCoeff1,
    1496               0 :                               a2->Count() == 3 ? a2->Item(2) : zero,
    1497                 :                               aCoeff2,
    1498               0 :                               arr->Item(2));
    1499                 : 
    1500                 :         // Add X component of translation (which can be merged with case
    1501                 :         // below in non-DEBUG).
    1502               0 :         AddTransformTranslate(a1->Item(1), aCoeff1, a2->Item(1), aCoeff2,
    1503               0 :                               arr->Item(1));
    1504                 :         break;
    1505                 :       }
    1506                 :       case eCSSKeyword_translatex:
    1507                 :       case eCSSKeyword_translatey:
    1508                 :       case eCSSKeyword_translatez: {
    1509               0 :         NS_ABORT_IF_FALSE(a1->Count() == 2, "unexpected count");
    1510               0 :         NS_ABORT_IF_FALSE(a2->Count() == 2, "unexpected count");
    1511               0 :         AddTransformTranslate(a1->Item(1), aCoeff1, a2->Item(1), aCoeff2,
    1512               0 :                               arr->Item(1));
    1513               0 :         break;
    1514                 :       }
    1515                 :       case eCSSKeyword_translate3d: {
    1516               0 :           NS_ABORT_IF_FALSE(a1->Count() == 4, "unexpected count");
    1517               0 :           NS_ABORT_IF_FALSE(a2->Count() == 4, "unexpected count");
    1518               0 :           AddTransformTranslate(a1->Item(1), aCoeff1, a2->Item(1), aCoeff2,
    1519               0 :                                 arr->Item(1));
    1520               0 :           AddTransformTranslate(a1->Item(2), aCoeff1, a2->Item(2), aCoeff2,
    1521               0 :                                 arr->Item(2));
    1522               0 :           AddTransformTranslate(a1->Item(3), aCoeff1, a2->Item(3), aCoeff2,
    1523               0 :                                 arr->Item(3));
    1524               0 :           break;
    1525                 :       }
    1526                 :       case eCSSKeyword_scale: {
    1527               0 :         NS_ABORT_IF_FALSE(a1->Count() == 2 || a1->Count() == 3,
    1528                 :                           "unexpected count");
    1529               0 :         NS_ABORT_IF_FALSE(a2->Count() == 2 || a2->Count() == 3,
    1530                 :                           "unexpected count");
    1531                 : 
    1532                 :         // This is different from skew() and translate(), since an
    1533                 :         // omitted second parameter repeats the first rather than being
    1534                 :         // zero.
    1535                 :         // Add Y component of scale.
    1536               0 :         AddTransformScale(a1->Count() == 3 ? a1->Item(2) : a1->Item(1),
    1537                 :                           aCoeff1,
    1538               0 :                           a2->Count() == 3 ? a2->Item(2) : a2->Item(1),
    1539                 :                           aCoeff2,
    1540               0 :                           arr->Item(2));
    1541                 : 
    1542                 :         // Add X component of scale (which can be merged with case below
    1543                 :         // in non-DEBUG).
    1544               0 :         AddTransformScale(a1->Item(1), aCoeff1, a2->Item(1), aCoeff2,
    1545               0 :                           arr->Item(1));
    1546                 : 
    1547               0 :         break;
    1548                 :       }
    1549                 :       case eCSSKeyword_scalex:
    1550                 :       case eCSSKeyword_scaley: 
    1551                 :       case eCSSKeyword_scalez: {
    1552               0 :         NS_ABORT_IF_FALSE(a1->Count() == 2, "unexpected count");
    1553               0 :         NS_ABORT_IF_FALSE(a2->Count() == 2, "unexpected count");
    1554                 : 
    1555               0 :         AddTransformScale(a1->Item(1), aCoeff1, a2->Item(1), aCoeff2,
    1556               0 :                           arr->Item(1));
    1557                 : 
    1558               0 :         break;
    1559                 :       }
    1560                 :       case eCSSKeyword_scale3d: {
    1561               0 :           NS_ABORT_IF_FALSE(a1->Count() == 4, "unexpected count");
    1562               0 :           NS_ABORT_IF_FALSE(a2->Count() == 4, "unexpected count");
    1563                 : 
    1564               0 :           AddTransformScale(a1->Item(1), aCoeff1, a2->Item(1), aCoeff2,
    1565               0 :                             arr->Item(1));
    1566               0 :           AddTransformScale(a1->Item(2), aCoeff1, a2->Item(2), aCoeff2,
    1567               0 :                             arr->Item(2));
    1568               0 :           AddTransformScale(a1->Item(3), aCoeff1, a2->Item(3), aCoeff2,
    1569               0 :                             arr->Item(3));
    1570                 : 
    1571               0 :           break;
    1572                 :       }
    1573                 :       // It would probably be nicer to animate skew in tangent space
    1574                 :       // rather than angle space.  However, it's easy to specify
    1575                 :       // skews with infinite tangents, and behavior changes pretty
    1576                 :       // drastically when crossing such skews (since the direction of
    1577                 :       // animation flips), so interop is probably more important here.
    1578                 :       case eCSSKeyword_skew: {
    1579               0 :         NS_ABORT_IF_FALSE(a1->Count() == 2 || a1->Count() == 3,
    1580                 :                           "unexpected count");
    1581               0 :         NS_ABORT_IF_FALSE(a2->Count() == 2 || a2->Count() == 3,
    1582                 :                           "unexpected count");
    1583                 : 
    1584               0 :         nsCSSValue zero(0.0f, eCSSUnit_Radian);
    1585                 :         // Add Y component of skew.
    1586               0 :         AddCSSValueAngle(a1->Count() == 3 ? a1->Item(2) : zero,
    1587                 :                          aCoeff1,
    1588               0 :                          a2->Count() == 3 ? a2->Item(2) : zero,
    1589                 :                          aCoeff2,
    1590               0 :                          arr->Item(2));
    1591                 : 
    1592                 :         // Add X component of skew (which can be merged with case below
    1593                 :         // in non-DEBUG).
    1594               0 :         AddCSSValueAngle(a1->Item(1), aCoeff1, a2->Item(1), aCoeff2,
    1595               0 :                          arr->Item(1));
    1596                 : 
    1597                 :         break;
    1598                 :       }
    1599                 :       case eCSSKeyword_skewx:
    1600                 :       case eCSSKeyword_skewy:
    1601                 :       case eCSSKeyword_rotate:
    1602                 :       case eCSSKeyword_rotatex:
    1603                 :       case eCSSKeyword_rotatey:
    1604                 :       case eCSSKeyword_rotatez: {
    1605               0 :         NS_ABORT_IF_FALSE(a1->Count() == 2, "unexpected count");
    1606               0 :         NS_ABORT_IF_FALSE(a2->Count() == 2, "unexpected count");
    1607                 : 
    1608               0 :         AddCSSValueAngle(a1->Item(1), aCoeff1, a2->Item(1), aCoeff2,
    1609               0 :                          arr->Item(1));
    1610                 : 
    1611               0 :         break;
    1612                 :       }
    1613                 :       case eCSSKeyword_matrix:
    1614                 :       case eCSSKeyword_matrix3d:
    1615                 :       case eCSSKeyword_interpolatematrix:
    1616                 :       case eCSSKeyword_rotate3d:
    1617                 :       case eCSSKeyword_perspective: {
    1618                 :         // FIXME: If the matrix contains only numbers then we could decompose
    1619                 :         // here.
    1620                 : 
    1621                 :         // Construct temporary lists with only this item in them.
    1622               0 :         nsCSSValueList tempList1, tempList2;
    1623               0 :         tempList1.mValue = aList1->mValue;
    1624               0 :         tempList2.mValue = aList2->mValue;
    1625                 : 
    1626               0 :         if (aList1 == aList2) {
    1627                 :           *resultTail =
    1628               0 :             AddDifferentTransformLists(&tempList1, aCoeff1, &tempList1, aCoeff2);
    1629                 :         } else {
    1630                 :           *resultTail =
    1631               0 :             AddDifferentTransformLists(&tempList1, aCoeff1, &tempList2, aCoeff2);
    1632                 :         }
    1633                 : 
    1634                 :         // Now advance resultTail to point to the new tail slot.
    1635               0 :         while (*resultTail) {
    1636               0 :           resultTail = &(*resultTail)->mNext;
    1637                 :         }
    1638                 : 
    1639                 :         break;
    1640                 :       }
    1641                 :       default:
    1642               0 :         NS_ABORT_IF_FALSE(false, "unknown transform function");
    1643                 :     }
    1644                 : 
    1645               0 :     aList1 = aList1->mNext;
    1646               0 :     aList2 = aList2->mNext;
    1647                 :   } while (aList1);
    1648               0 :   NS_ABORT_IF_FALSE(!aList2, "list length mismatch");
    1649               0 :   NS_ABORT_IF_FALSE(!*resultTail,
    1650                 :                     "resultTail isn't pointing to the tail");
    1651                 : 
    1652               0 :   return result.forget();
    1653                 : }
    1654                 : 
    1655                 : bool
    1656               0 : nsStyleAnimation::AddWeighted(nsCSSProperty aProperty,
    1657                 :                               double aCoeff1, const Value& aValue1,
    1658                 :                               double aCoeff2, const Value& aValue2,
    1659                 :                               Value& aResultValue)
    1660                 : {
    1661                 :   Unit commonUnit =
    1662               0 :     GetCommonUnit(aProperty, aValue1.GetUnit(), aValue2.GetUnit());
    1663                 :   // Maybe need a followup method to convert the inputs into the common
    1664                 :   // unit-type, if they don't already match it. (Or would it make sense to do
    1665                 :   // that in GetCommonUnit? in which case maybe ConvertToCommonUnit would be
    1666                 :   // better.)
    1667                 : 
    1668               0 :   switch (commonUnit) {
    1669                 :     case eUnit_Null:
    1670                 :     case eUnit_Auto:
    1671                 :     case eUnit_None:
    1672                 :     case eUnit_Normal:
    1673                 :     case eUnit_UnparsedString:
    1674               0 :       return false;
    1675                 : 
    1676                 :     case eUnit_Enumerated:
    1677               0 :       switch (aProperty) {
    1678                 :         case eCSSProperty_font_stretch: {
    1679                 :           // Animate just like eUnit_Integer.
    1680               0 :           PRInt32 result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
    1681               0 :                                  aCoeff2 * double(aValue2.GetIntValue()));
    1682               0 :           if (result < NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED) {
    1683               0 :             result = NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED;
    1684               0 :           } else if (result > NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED) {
    1685               0 :             result = NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED;
    1686                 :           }
    1687               0 :           aResultValue.SetIntValue(result, eUnit_Enumerated);
    1688               0 :           return true;
    1689                 :         }
    1690                 :         default:
    1691               0 :           return false;
    1692                 :       }
    1693                 :     case eUnit_Visibility: {
    1694               0 :       PRInt32 val1 = aValue1.GetIntValue() == NS_STYLE_VISIBILITY_VISIBLE;
    1695               0 :       PRInt32 val2 = aValue2.GetIntValue() == NS_STYLE_VISIBILITY_VISIBLE;
    1696               0 :       double interp = aCoeff1 * val1 + aCoeff2 * val2;
    1697                 :       PRInt32 result = interp > 0.0 ? NS_STYLE_VISIBILITY_VISIBLE
    1698               0 :                                     : NS_STYLE_VISIBILITY_HIDDEN;
    1699               0 :       aResultValue.SetIntValue(result, eUnit_Visibility);
    1700               0 :       return true;
    1701                 :     }
    1702                 :     case eUnit_Integer: {
    1703                 :       // http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types-
    1704                 :       // says we should use floor
    1705               0 :       PRInt32 result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
    1706               0 :                              aCoeff2 * double(aValue2.GetIntValue()));
    1707               0 :       if (aProperty == eCSSProperty_font_weight) {
    1708               0 :         if (result < 100) {
    1709               0 :           result = 100;
    1710               0 :         } else if (result > 900) {
    1711               0 :           result = 900;
    1712                 :         }
    1713               0 :         result -= result % 100;
    1714                 :       } else {
    1715               0 :         result = RestrictValue(aProperty, result);
    1716                 :       }
    1717               0 :       aResultValue.SetIntValue(result, eUnit_Integer);
    1718               0 :       return true;
    1719                 :     }
    1720                 :     case eUnit_Coord: {
    1721                 :       aResultValue.SetCoordValue(RestrictValue(aProperty, NSToCoordRound(
    1722               0 :         aCoeff1 * aValue1.GetCoordValue() +
    1723               0 :         aCoeff2 * aValue2.GetCoordValue())));
    1724               0 :       return true;
    1725                 :     }
    1726                 :     case eUnit_Percent: {
    1727                 :       aResultValue.SetPercentValue(RestrictValue(aProperty,
    1728               0 :         aCoeff1 * aValue1.GetPercentValue() +
    1729               0 :         aCoeff2 * aValue2.GetPercentValue()));
    1730               0 :       return true;
    1731                 :     }
    1732                 :     case eUnit_Float: {
    1733                 :       aResultValue.SetFloatValue(RestrictValue(aProperty,
    1734               0 :         aCoeff1 * aValue1.GetFloatValue() +
    1735               0 :         aCoeff2 * aValue2.GetFloatValue()));
    1736               0 :       return true;
    1737                 :     }
    1738                 :     case eUnit_Color: {
    1739               0 :       nscolor color1 = aValue1.GetColorValue();
    1740               0 :       nscolor color2 = aValue2.GetColorValue();
    1741                 :       // FIXME (spec): The CSS transitions spec doesn't say whether
    1742                 :       // colors are premultiplied, but things work better when they are,
    1743                 :       // so use premultiplication.  Spec issue is still open per
    1744                 :       // http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html
    1745                 : 
    1746                 :       // To save some math, scale the alpha down to a 0-1 scale, but
    1747                 :       // leave the color components on a 0-255 scale.
    1748               0 :       double A1 = NS_GET_A(color1) * (1.0 / 255.0);
    1749               0 :       double R1 = NS_GET_R(color1) * A1;
    1750               0 :       double G1 = NS_GET_G(color1) * A1;
    1751               0 :       double B1 = NS_GET_B(color1) * A1;
    1752               0 :       double A2 = NS_GET_A(color2) * (1.0 / 255.0);
    1753               0 :       double R2 = NS_GET_R(color2) * A2;
    1754               0 :       double G2 = NS_GET_G(color2) * A2;
    1755               0 :       double B2 = NS_GET_B(color2) * A2;
    1756               0 :       double Aresf = (A1 * aCoeff1 + A2 * aCoeff2);
    1757                 :       nscolor resultColor;
    1758               0 :       if (Aresf <= 0.0) {
    1759               0 :         resultColor = NS_RGBA(0, 0, 0, 0);
    1760                 :       } else {
    1761               0 :         if (Aresf > 1.0) {
    1762               0 :           Aresf = 1.0;
    1763                 :         }
    1764               0 :         double factor = 1.0 / Aresf;
    1765               0 :         PRUint8 Ares = NSToIntRound(Aresf * 255.0);
    1766               0 :         PRUint8 Rres = ClampColor((R1 * aCoeff1 + R2 * aCoeff2) * factor);
    1767               0 :         PRUint8 Gres = ClampColor((G1 * aCoeff1 + G2 * aCoeff2) * factor);
    1768               0 :         PRUint8 Bres = ClampColor((B1 * aCoeff1 + B2 * aCoeff2) * factor);
    1769               0 :         resultColor = NS_RGBA(Rres, Gres, Bres, Ares);
    1770                 :       }
    1771               0 :       aResultValue.SetColorValue(resultColor);
    1772               0 :       return true;
    1773                 :     }
    1774                 :     case eUnit_Calc: {
    1775               0 :       CalcValue v1 = ExtractCalcValue(aValue1);
    1776               0 :       CalcValue v2 = ExtractCalcValue(aValue2);
    1777               0 :       double len = aCoeff1 * v1.mLength + aCoeff2 * v2.mLength;
    1778               0 :       double pct = aCoeff1 * v1.mPercent + aCoeff2 * v2.mPercent;
    1779                 :       bool hasPct = (aCoeff1 != 0.0 && v1.mHasPercent) ||
    1780               0 :                       (aCoeff2 != 0.0 && v2.mHasPercent);
    1781               0 :       nsCSSValue *val = new nsCSSValue();
    1782               0 :       nsCSSValue::Array *arr = nsCSSValue::Array::Create(1);
    1783               0 :       val->SetArrayValue(arr, eCSSUnit_Calc);
    1784               0 :       if (hasPct) {
    1785               0 :         nsCSSValue::Array *arr2 = nsCSSValue::Array::Create(2);
    1786               0 :         arr2->Item(0).SetFloatValue(len, eCSSUnit_Pixel);
    1787               0 :         arr2->Item(1).SetPercentValue(pct);
    1788               0 :         arr->Item(0).SetArrayValue(arr2, eCSSUnit_Calc_Plus);
    1789                 :       } else {
    1790               0 :         arr->Item(0).SetFloatValue(len, eCSSUnit_Pixel);
    1791                 :       }
    1792               0 :       aResultValue.SetAndAdoptCSSValueValue(val, eUnit_Calc);
    1793               0 :       return true;
    1794                 :     }
    1795                 :     case eUnit_CSSValuePair: {
    1796               0 :       const nsCSSValuePair *pair1 = aValue1.GetCSSValuePairValue();
    1797               0 :       const nsCSSValuePair *pair2 = aValue2.GetCSSValuePairValue();
    1798                 :       nsCSSUnit unit[2];
    1799                 :       unit[0] = GetCommonUnit(aProperty, pair1->mXValue.GetUnit(),
    1800               0 :                               pair2->mXValue.GetUnit());
    1801                 :       unit[1] = GetCommonUnit(aProperty, pair1->mYValue.GetUnit(),
    1802               0 :                               pair2->mYValue.GetUnit());
    1803               0 :       if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
    1804               0 :           unit[0] == eCSSUnit_URL) {
    1805               0 :         return false;
    1806                 :       }
    1807                 : 
    1808               0 :       nsAutoPtr<nsCSSValuePair> result(new nsCSSValuePair);
    1809                 :       static nsCSSValue nsCSSValuePair::* const pairValues[2] = {
    1810                 :         &nsCSSValuePair::mXValue, &nsCSSValuePair::mYValue
    1811                 :       };
    1812               0 :       PRUint32 restrictions = nsCSSProps::ValueRestrictions(aProperty);
    1813               0 :       for (PRUint32 i = 0; i < 2; ++i) {
    1814               0 :         nsCSSValue nsCSSValuePair::*member = pairValues[i];
    1815               0 :         if (!AddCSSValuePixelPercentCalc(restrictions, unit[i],
    1816                 :                                          aCoeff1, pair1->*member,
    1817                 :                                          aCoeff2, pair2->*member,
    1818               0 :                                          result->*member) ) {
    1819               0 :           NS_ABORT_IF_FALSE(false, "unexpected unit");
    1820               0 :           return false;
    1821                 :         }
    1822                 :       }
    1823                 : 
    1824                 :       aResultValue.SetAndAdoptCSSValuePairValue(result.forget(),
    1825               0 :                                                 eUnit_CSSValuePair);
    1826               0 :       return true;
    1827                 :     }
    1828                 :     case eUnit_CSSValueTriplet: {
    1829               0 :       nsCSSValueTriplet triplet1(*aValue1.GetCSSValueTripletValue());
    1830               0 :       nsCSSValueTriplet triplet2(*aValue2.GetCSSValueTripletValue());
    1831                 : 
    1832               0 :       if (triplet1.mZValue.GetUnit() == eCSSUnit_Null) {
    1833               0 :         triplet1.mZValue.SetFloatValue(0.0, eCSSUnit_Pixel);
    1834                 :       }
    1835               0 :       if (triplet2.mZValue.GetUnit() == eCSSUnit_Null) {
    1836               0 :           triplet2.mZValue.SetFloatValue(0.0, eCSSUnit_Pixel);
    1837                 :       }
    1838                 : 
    1839                 :       nsCSSUnit unit[3];
    1840                 :       unit[0] = GetCommonUnit(aProperty, triplet1.mXValue.GetUnit(),
    1841               0 :                               triplet2.mXValue.GetUnit());
    1842                 :       unit[1] = GetCommonUnit(aProperty, triplet1.mYValue.GetUnit(),
    1843               0 :                                triplet2.mYValue.GetUnit());
    1844                 :       unit[2] = GetCommonUnit(aProperty, triplet1.mZValue.GetUnit(),
    1845               0 :                               triplet2.mZValue.GetUnit());
    1846               0 :       if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
    1847               0 :           unit[0] == eCSSUnit_Null || unit[0] == eCSSUnit_URL) {
    1848               0 :         return false;
    1849                 :       }
    1850                 : 
    1851               0 :       nsAutoPtr<nsCSSValueTriplet> result(new nsCSSValueTriplet);
    1852                 :       static nsCSSValue nsCSSValueTriplet::* const tripletValues[3] = {
    1853                 :         &nsCSSValueTriplet::mXValue, &nsCSSValueTriplet::mYValue, &nsCSSValueTriplet::mZValue
    1854                 :       };
    1855               0 :       PRUint32 restrictions = nsCSSProps::ValueRestrictions(aProperty);
    1856               0 :       for (PRUint32 i = 0; i < 3; ++i) {
    1857               0 :         nsCSSValue nsCSSValueTriplet::*member = tripletValues[i];
    1858               0 :         if (!AddCSSValuePixelPercentCalc(restrictions, unit[i],
    1859                 :                                          aCoeff1, &triplet1->*member,
    1860                 :                                          aCoeff2, &triplet2->*member,
    1861               0 :                                          result->*member) ) {
    1862               0 :           NS_ABORT_IF_FALSE(false, "unexpected unit");
    1863               0 :           return false;
    1864                 :         }
    1865                 :       }
    1866                 : 
    1867               0 :       if (result->mZValue.GetUnit() == eCSSUnit_Pixel &&
    1868               0 :           result->mZValue.GetFloatValue() == 0.0f) {
    1869               0 :         result->mZValue.Reset();
    1870                 :       }
    1871                 : 
    1872                 :       aResultValue.SetAndAdoptCSSValueTripletValue(result.forget(),
    1873               0 :                                                    eUnit_CSSValueTriplet);
    1874               0 :       return true;
    1875                 :     }
    1876                 :     case eUnit_CSSRect: {
    1877               0 :       NS_ABORT_IF_FALSE(nsCSSProps::ValueRestrictions(aProperty) == 0,
    1878                 :                         "must add code for handling value restrictions");
    1879               0 :       const nsCSSRect *rect1 = aValue1.GetCSSRectValue();
    1880               0 :       const nsCSSRect *rect2 = aValue2.GetCSSRectValue();
    1881               0 :       if (rect1->mTop.GetUnit() != rect2->mTop.GetUnit() ||
    1882               0 :           rect1->mRight.GetUnit() != rect2->mRight.GetUnit() ||
    1883               0 :           rect1->mBottom.GetUnit() != rect2->mBottom.GetUnit() ||
    1884               0 :           rect1->mLeft.GetUnit() != rect2->mLeft.GetUnit()) {
    1885                 :         // At least until we have calc()
    1886               0 :         return false;
    1887                 :       }
    1888                 : 
    1889               0 :       nsAutoPtr<nsCSSRect> result(new nsCSSRect);
    1890               0 :       for (PRUint32 i = 0; i < ArrayLength(nsCSSRect::sides); ++i) {
    1891               0 :         nsCSSValue nsCSSRect::*member = nsCSSRect::sides[i];
    1892               0 :         NS_ABORT_IF_FALSE((rect1->*member).GetUnit() ==
    1893                 :                             (rect2->*member).GetUnit(),
    1894                 :                           "should have returned above");
    1895               0 :         switch ((rect1->*member).GetUnit()) {
    1896                 :           case eCSSUnit_Pixel:
    1897                 :             AddCSSValuePixel(aCoeff1, rect1->*member, aCoeff2, rect2->*member,
    1898               0 :                              result->*member);
    1899               0 :             break;
    1900                 :           case eCSSUnit_Auto:
    1901               0 :             if (float(aCoeff1 + aCoeff2) != 1.0f) {
    1902                 :               // Interpolating between two auto values makes sense;
    1903                 :               // adding in other ratios does not.
    1904               0 :               return false;
    1905                 :             }
    1906               0 :             (result->*member).SetAutoValue();
    1907               0 :             break;
    1908                 :           default:
    1909               0 :             NS_ABORT_IF_FALSE(false, "unexpected unit");
    1910               0 :             return false;
    1911                 :         }
    1912                 :       }
    1913                 : 
    1914               0 :       aResultValue.SetAndAdoptCSSRectValue(result.forget(), eUnit_CSSRect);
    1915               0 :       return true;
    1916                 :     }
    1917                 :     case eUnit_Dasharray: {
    1918               0 :       const nsCSSValueList *list1 = aValue1.GetCSSValueListValue();
    1919               0 :       const nsCSSValueList *list2 = aValue2.GetCSSValueListValue();
    1920                 : 
    1921               0 :       PRUint32 len1 = 0, len2 = 0;
    1922               0 :       for (const nsCSSValueList *v = list1; v; v = v->mNext) {
    1923               0 :         ++len1;
    1924                 :       }
    1925               0 :       for (const nsCSSValueList *v = list2; v; v = v->mNext) {
    1926               0 :         ++len2;
    1927                 :       }
    1928               0 :       NS_ABORT_IF_FALSE(len1 > 0 && len2 > 0, "unexpected length");
    1929               0 :       if (list1->mValue.GetUnit() == eCSSUnit_None ||
    1930               0 :           list2->mValue.GetUnit() == eCSSUnit_None) {
    1931                 :         // One of our values is "none".  Can't do addition with that.
    1932               0 :         NS_ABORT_IF_FALSE(
    1933                 :           (list1->mValue.GetUnit() != eCSSUnit_None || len1 == 1) &&
    1934                 :           (list2->mValue.GetUnit() != eCSSUnit_None || len2 == 1),
    1935                 :           "multi-value valuelist with 'none' as first element");
    1936               0 :         return false;
    1937                 :       }
    1938                 : 
    1939               0 :       nsAutoPtr<nsCSSValueList> result;
    1940               0 :       nsCSSValueList **resultTail = getter_Transfers(result);
    1941               0 :       for (PRUint32 i = 0, i_end = lcm(len1, len2); i != i_end; ++i) {
    1942               0 :         const nsCSSValue &v1 = list1->mValue;
    1943               0 :         const nsCSSValue &v2 = list2->mValue;
    1944               0 :         NS_ABORT_IF_FALSE(v1.GetUnit() == eCSSUnit_Number ||
    1945                 :                           v1.GetUnit() == eCSSUnit_Percent, "unexpected");
    1946               0 :         NS_ABORT_IF_FALSE(v2.GetUnit() == eCSSUnit_Number ||
    1947                 :                           v2.GetUnit() == eCSSUnit_Percent, "unexpected");
    1948               0 :         if (v1.GetUnit() != v2.GetUnit()) {
    1949                 :           // Can't animate between lengths and percentages (until calc()).
    1950               0 :           return false;
    1951                 :         }
    1952                 : 
    1953               0 :         nsCSSValueList *item = new nsCSSValueList;
    1954               0 :         if (!item) {
    1955               0 :           return false;
    1956                 :         }
    1957               0 :         *resultTail = item;
    1958               0 :         resultTail = &item->mNext;
    1959                 : 
    1960               0 :         if (v1.GetUnit() == eCSSUnit_Number) {
    1961                 :           AddCSSValueNumber(aCoeff1, v1, aCoeff2, v2, item->mValue,
    1962               0 :                             CSS_PROPERTY_VALUE_NONNEGATIVE);
    1963                 :         } else {
    1964                 :           AddCSSValuePercent(aCoeff1, v1, aCoeff2, v2, item->mValue,
    1965               0 :                              CSS_PROPERTY_VALUE_NONNEGATIVE);
    1966                 :         }
    1967                 : 
    1968               0 :         list1 = list1->mNext;
    1969               0 :         if (!list1) {
    1970               0 :           list1 = aValue1.GetCSSValueListValue();
    1971                 :         }
    1972               0 :         list2 = list2->mNext;
    1973               0 :         if (!list2) {
    1974               0 :           list2 = aValue2.GetCSSValueListValue();
    1975                 :         }
    1976                 :       }
    1977                 : 
    1978                 :       aResultValue.SetAndAdoptCSSValueListValue(result.forget(),
    1979               0 :                                                 eUnit_Dasharray);
    1980               0 :       return true;
    1981                 :     }
    1982                 :     case eUnit_Shadow: {
    1983                 :       // This is implemented according to:
    1984                 :       // http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types-
    1985                 :       // and the third item in the summary of:
    1986                 :       // http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html
    1987               0 :       const nsCSSValueList *shadow1 = aValue1.GetCSSValueListValue();
    1988               0 :       const nsCSSValueList *shadow2 = aValue2.GetCSSValueListValue();
    1989               0 :       nsAutoPtr<nsCSSValueList> result;
    1990               0 :       nsCSSValueList **resultTail = getter_Transfers(result);
    1991               0 :       while (shadow1 && shadow2) {
    1992               0 :         if (!AddShadowItems(aCoeff1, shadow1->mValue,
    1993                 :                             aCoeff2, shadow2->mValue,
    1994               0 :                             resultTail)) {
    1995               0 :           return false;
    1996                 :         }
    1997               0 :         shadow1 = shadow1->mNext;
    1998               0 :         shadow2 = shadow2->mNext;
    1999                 :       }
    2000               0 :       if (shadow1 || shadow2) {
    2001                 :         const nsCSSValueList *longShadow;
    2002                 :         double longCoeff;
    2003               0 :         if (shadow1) {
    2004               0 :           longShadow = shadow1;
    2005               0 :           longCoeff = aCoeff1;
    2006                 :         } else {
    2007               0 :           longShadow = shadow2;
    2008               0 :           longCoeff = aCoeff2;
    2009                 :         }
    2010                 : 
    2011               0 :         while (longShadow) {
    2012                 :           // Passing coefficients that add to less than 1 produces the
    2013                 :           // desired result of interpolating "0 0 0 transparent" with
    2014                 :           // the current shadow.
    2015               0 :           if (!AddShadowItems(longCoeff, longShadow->mValue,
    2016                 :                               0.0, longShadow->mValue,
    2017               0 :                               resultTail)) {
    2018               0 :             return false;
    2019                 :           }
    2020                 : 
    2021               0 :           longShadow = longShadow->mNext;
    2022                 :         }
    2023                 :       }
    2024               0 :       aResultValue.SetAndAdoptCSSValueListValue(result.forget(), eUnit_Shadow);
    2025               0 :       return true;
    2026                 :     }
    2027                 :     case eUnit_Transform: {
    2028               0 :       const nsCSSValueList *list1 = aValue1.GetCSSValueListValue();
    2029               0 :       const nsCSSValueList *list2 = aValue2.GetCSSValueListValue();
    2030                 : 
    2031                 :       // We want to avoid the matrix decomposition when we can, since
    2032                 :       // avoiding it can produce better results both for compound
    2033                 :       // transforms and for skew and skewY (see below).  We can do this
    2034                 :       // in two cases:
    2035                 :       //   (1) if one of the transforms is 'none'
    2036                 :       //   (2) if the lists have the same length and the transform
    2037                 :       //       functions match
    2038               0 :       nsAutoPtr<nsCSSValueList> result;
    2039               0 :       if (list1->mValue.GetUnit() == eCSSUnit_None) {
    2040               0 :         if (list2->mValue.GetUnit() == eCSSUnit_None) {
    2041               0 :           result = new nsCSSValueList;
    2042               0 :           if (result) {
    2043               0 :             result->mValue.SetNoneValue();
    2044                 :           }
    2045                 :         } else {
    2046               0 :           result = AddTransformLists(list2, 0, list2, aCoeff2);
    2047                 :         }
    2048                 :       } else {
    2049               0 :         if (list2->mValue.GetUnit() == eCSSUnit_None) {
    2050               0 :           result = AddTransformLists(list1, 0, list1, aCoeff1);
    2051                 :         } else {
    2052               0 :           bool match = true;
    2053                 : 
    2054                 :           {
    2055               0 :             const nsCSSValueList *item1 = list1, *item2 = list2;
    2056               0 :             do {
    2057                 :               nsCSSKeyword func1 = nsStyleTransformMatrix::TransformFunctionOf(
    2058               0 :                                      item1->mValue.GetArrayValue());
    2059                 :               nsCSSKeyword func2 = nsStyleTransformMatrix::TransformFunctionOf(
    2060               0 :                                      item2->mValue.GetArrayValue());
    2061                 : 
    2062               0 :               if (!TransformFunctionsMatch(func1, func2)) {
    2063               0 :                 break;
    2064                 :               }
    2065                 : 
    2066               0 :               item1 = item1->mNext;
    2067               0 :               item2 = item2->mNext;
    2068                 :             } while (item1 && item2);
    2069               0 :             if (item1 || item2) {
    2070                 :               // Either |break| above or length mismatch.
    2071               0 :               match = false;
    2072                 :             }
    2073                 :           }
    2074                 : 
    2075               0 :           if (match) {
    2076               0 :             result = AddTransformLists(list1, aCoeff1, list2, aCoeff2);
    2077                 :           } else {
    2078               0 :             result = AddDifferentTransformLists(list1, aCoeff1, list2, aCoeff2);
    2079                 :           }
    2080                 :         }
    2081                 :       }
    2082                 : 
    2083                 :       aResultValue.SetAndAdoptCSSValueListValue(result.forget(),
    2084               0 :                                                 eUnit_Transform);
    2085               0 :       return true;
    2086                 :     }
    2087                 :     case eUnit_BackgroundPosition: {
    2088               0 :       const nsCSSValueList *position1 = aValue1.GetCSSValueListValue();
    2089               0 :       const nsCSSValueList *position2 = aValue2.GetCSSValueListValue();
    2090               0 :       nsAutoPtr<nsCSSValueList> result;
    2091               0 :       nsCSSValueList **resultTail = getter_Transfers(result);
    2092               0 :       while (position1 && position2) {
    2093               0 :         nsCSSValueList *item = new nsCSSValueList;
    2094               0 :         if (!item) {
    2095               0 :           return false;
    2096                 :         }
    2097               0 :         *resultTail = item;
    2098               0 :         resultTail = &item->mNext;
    2099                 : 
    2100               0 :         nsCSSValue::Array* bgPos1 = position1->mValue.GetArrayValue();
    2101               0 :         nsCSSValue::Array* bgPos2 = position2->mValue.GetArrayValue();
    2102               0 :         nsCSSValue::Array* bgPosRes = nsCSSValue::Array::Create(4);
    2103               0 :         item->mValue.SetArrayValue(bgPosRes, eCSSUnit_Array);
    2104                 : 
    2105               0 :         PRUint32 restrictions = nsCSSProps::ValueRestrictions(aProperty);
    2106                 : 
    2107                 :         /* Only iterate over elements 1 and 3. The background position is
    2108                 :          * 'uncomputed' to only those elements.
    2109                 :          */
    2110               0 :         for (int i = 1; i < 4; i+=2) {
    2111               0 :           const nsCSSValue& v1 = bgPos1->Item(i);
    2112               0 :           const nsCSSValue& v2 = bgPos2->Item(i);
    2113               0 :           nsCSSValue& vr = bgPosRes->Item(i);
    2114                 : 
    2115               0 :           nsCSSUnit unit = GetCommonUnit(aProperty, v1.GetUnit(), v2.GetUnit());
    2116                 : 
    2117               0 :           if (!AddCSSValuePixelPercentCalc(restrictions, unit, aCoeff1, v1,
    2118               0 :                                            aCoeff2, v2, vr) ) {
    2119               0 :             if (v1 != v2) {
    2120               0 :               return false;
    2121                 :             }
    2122               0 :             vr = v1;
    2123                 :           }
    2124                 :         }
    2125                 : 
    2126               0 :         position1 = position1->mNext;
    2127               0 :         position2 = position2->mNext;
    2128                 :       }
    2129                 : 
    2130                 :       // Check for different lengths
    2131               0 :       if (position1 || position2) {
    2132               0 :         return false;
    2133                 :       }
    2134                 : 
    2135                 :       aResultValue.SetAndAdoptCSSValueListValue(result.forget(),
    2136               0 :                                                 eUnit_BackgroundPosition);
    2137               0 :       return true;
    2138                 :     }
    2139                 :     case eUnit_CSSValuePairList: {
    2140               0 :       const nsCSSValuePairList *list1 = aValue1.GetCSSValuePairListValue();
    2141               0 :       const nsCSSValuePairList *list2 = aValue2.GetCSSValuePairListValue();
    2142               0 :       nsAutoPtr<nsCSSValuePairList> result;
    2143               0 :       nsCSSValuePairList **resultTail = getter_Transfers(result);
    2144               0 :       do {
    2145               0 :         nsCSSValuePairList *item = new nsCSSValuePairList;
    2146               0 :         if (!item) {
    2147               0 :           return false;
    2148                 :         }
    2149               0 :         *resultTail = item;
    2150               0 :         resultTail = &item->mNext;
    2151                 : 
    2152                 :         static nsCSSValue nsCSSValuePairList::* const pairListValues[] = {
    2153                 :           &nsCSSValuePairList::mXValue,
    2154                 :           &nsCSSValuePairList::mYValue,
    2155                 :         };
    2156               0 :         PRUint32 restrictions = nsCSSProps::ValueRestrictions(aProperty);
    2157               0 :         for (PRUint32 i = 0; i < ArrayLength(pairListValues); ++i) {
    2158               0 :           const nsCSSValue &v1 = list1->*(pairListValues[i]);
    2159               0 :           const nsCSSValue &v2 = list2->*(pairListValues[i]);
    2160               0 :           nsCSSValue &vr = item->*(pairListValues[i]);
    2161                 :           nsCSSUnit unit =
    2162               0 :             GetCommonUnit(aProperty, v1.GetUnit(), v2.GetUnit());
    2163               0 :           if (unit == eCSSUnit_Null) {
    2164               0 :             return false;
    2165                 :           }
    2166               0 :           if (!AddCSSValuePixelPercentCalc(restrictions, unit, aCoeff1, v1,
    2167               0 :                                            aCoeff2, v2, vr) ) {
    2168               0 :             if (v1 != v2) {
    2169               0 :               return false;
    2170                 :             }
    2171               0 :             vr = v1;
    2172                 :           }
    2173                 :         }
    2174               0 :         list1 = list1->mNext;
    2175               0 :         list2 = list2->mNext;
    2176                 :       } while (list1 && list2);
    2177               0 :       if (list1 || list2) {
    2178                 :         // We can't interpolate lists of different lengths.
    2179               0 :         return false;
    2180                 :       }
    2181                 : 
    2182               0 :       aResultValue.SetAndAdoptCSSValuePairListValue(result.forget());
    2183               0 :       return true;
    2184                 :     }
    2185                 :   }
    2186                 : 
    2187               0 :   NS_ABORT_IF_FALSE(false, "Can't interpolate using the given common unit");
    2188               0 :   return false;
    2189                 : }
    2190                 : 
    2191                 : already_AddRefed<css::StyleRule>
    2192               0 : BuildStyleRule(nsCSSProperty aProperty,
    2193                 :                dom::Element* aTargetElement,
    2194                 :                const nsAString& aSpecifiedValue,
    2195                 :                bool aUseSVGMode)
    2196                 : {
    2197                 :   // Set up an empty CSS Declaration
    2198               0 :   nsAutoPtr<css::Declaration> declaration(new css::Declaration());
    2199               0 :   declaration->InitializeEmpty();
    2200                 : 
    2201                 :   bool changed; // ignored, but needed as outparam for ParseProperty
    2202               0 :   nsIDocument* doc = aTargetElement->OwnerDoc();
    2203               0 :   nsCOMPtr<nsIURI> baseURI = aTargetElement->GetBaseURI();
    2204               0 :   nsCSSParser parser(doc->CSSLoader());
    2205                 : 
    2206               0 :   if (aUseSVGMode) {
    2207               0 :     parser.SetSVGMode(true);
    2208                 :   }
    2209                 : 
    2210               0 :   nsCSSProperty propertyToCheck = nsCSSProps::IsShorthand(aProperty) ?
    2211               0 :     nsCSSProps::SubpropertyEntryFor(aProperty)[0] : aProperty;
    2212                 : 
    2213                 :   // Get a parser, parse the property, and check for CSS parsing errors.
    2214                 :   // If any of these steps fails, we bail out and delete the declaration.
    2215               0 :   if (NS_FAILED(parser.ParseProperty(aProperty, aSpecifiedValue,
    2216                 :                                      doc->GetDocumentURI(), baseURI,
    2217                 :                                      aTargetElement->NodePrincipal(),
    2218                 :                                      declaration, &changed, false)) ||
    2219                 :       // check whether property parsed without CSS parsing errors
    2220               0 :       !declaration->HasNonImportantValueFor(propertyToCheck)) {
    2221               0 :     NS_WARNING("failure in BuildStyleRule");
    2222               0 :     return nsnull;
    2223                 :   }
    2224                 : 
    2225               0 :   nsRefPtr<css::StyleRule> rule = new css::StyleRule(nsnull, declaration.forget());
    2226               0 :   return rule.forget();
    2227                 : }
    2228                 : 
    2229                 : inline
    2230                 : already_AddRefed<nsStyleContext>
    2231               0 : LookupStyleContext(dom::Element* aElement)
    2232                 : {
    2233               0 :   nsIDocument* doc = aElement->GetCurrentDoc();
    2234               0 :   nsIPresShell* shell = doc->GetShell();
    2235               0 :   if (!shell) {
    2236               0 :     return nsnull;
    2237                 :   }
    2238               0 :   return nsComputedDOMStyle::GetStyleContextForElement(aElement, nsnull, shell);
    2239                 : }
    2240                 : 
    2241                 : bool
    2242               0 : nsStyleAnimation::ComputeValue(nsCSSProperty aProperty,
    2243                 :                                dom::Element* aTargetElement,
    2244                 :                                const nsAString& aSpecifiedValue,
    2245                 :                                bool aUseSVGMode,
    2246                 :                                Value& aComputedValue,
    2247                 :                                bool* aIsContextSensitive)
    2248                 : {
    2249               0 :   NS_ABORT_IF_FALSE(aTargetElement, "null target element");
    2250               0 :   NS_ABORT_IF_FALSE(aTargetElement->GetCurrentDoc(),
    2251                 :                     "we should only be able to actively animate nodes that "
    2252                 :                     "are in a document");
    2253                 : 
    2254                 :   nsCSSProperty propToParse =
    2255               0 :     nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_REPORT_OTHER_NAME)
    2256               0 :       ? nsCSSProps::OtherNameFor(aProperty) : aProperty;
    2257                 : 
    2258                 :   // Parse specified value into a temporary css::StyleRule
    2259                 :   nsRefPtr<css::StyleRule> styleRule =
    2260               0 :     BuildStyleRule(propToParse, aTargetElement, aSpecifiedValue, aUseSVGMode);
    2261               0 :   if (!styleRule) {
    2262               0 :     return false;
    2263                 :   }
    2264                 : 
    2265               0 :   if (nsCSSProps::IsShorthand(aProperty) ||
    2266               0 :       nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
    2267                 :     // Just capture the specified value
    2268               0 :     aComputedValue.SetUnparsedStringValue(nsString(aSpecifiedValue));
    2269               0 :     if (aIsContextSensitive) {
    2270                 :       // Since we're just returning the string as-is, aComputedValue isn't going
    2271                 :       // to change depending on the context
    2272               0 :       *aIsContextSensitive = false;
    2273                 :     }
    2274               0 :     return true;
    2275                 :   }
    2276                 : 
    2277                 :   // Look up style context for our target element
    2278               0 :   nsRefPtr<nsStyleContext> styleContext = LookupStyleContext(aTargetElement);
    2279               0 :   if (!styleContext) {
    2280               0 :     return false;
    2281                 :   }
    2282               0 :   nsStyleSet* styleSet = styleContext->PresContext()->StyleSet();
    2283                 : 
    2284               0 :   nsRefPtr<nsStyleContext> tmpStyleContext;
    2285               0 :   if (aIsContextSensitive) {
    2286               0 :     nsCOMArray<nsIStyleRule> ruleArray;
    2287               0 :     ruleArray.AppendObject(styleSet->InitialStyleRule());
    2288               0 :     ruleArray.AppendObject(styleRule);
    2289               0 :     styleRule->RuleMatched();
    2290                 :     tmpStyleContext =
    2291               0 :       styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
    2292               0 :     if (!tmpStyleContext) {
    2293               0 :       return false;
    2294                 :     }
    2295                 : 
    2296                 :     // Force walk of rule tree
    2297               0 :     nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty];
    2298               0 :     tmpStyleContext->GetStyleData(sid);
    2299                 : 
    2300                 :     // If the rule node will have cached style data if the value is not
    2301                 :     // context-sensitive. So if there's nothing cached, it's not context
    2302                 :     // sensitive.
    2303                 :     *aIsContextSensitive =
    2304               0 :       !tmpStyleContext->GetRuleNode()->NodeHasCachedData(sid);
    2305                 :   }
    2306                 : 
    2307                 :   // If we're not concerned whether the property is context sensitive then just
    2308                 :   // add the rule to a new temporary style context alongside the target
    2309                 :   // element's style context.
    2310                 :   // Also, if we previously discovered that this property IS context-sensitive
    2311                 :   // then we need to throw the temporary style context out since the property's
    2312                 :   // value may have been biased by the 'initial' values supplied.
    2313               0 :   if (!aIsContextSensitive || *aIsContextSensitive) {
    2314               0 :     nsCOMArray<nsIStyleRule> ruleArray;
    2315               0 :     ruleArray.AppendObject(styleRule);
    2316               0 :     styleRule->RuleMatched();
    2317                 :     tmpStyleContext =
    2318               0 :       styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
    2319               0 :     if (!tmpStyleContext) {
    2320               0 :       return false;
    2321                 :     }
    2322                 :   }
    2323                 : 
    2324                 :   // Extract computed value of our property from the temporary style rule
    2325               0 :   return ExtractComputedValue(aProperty, tmpStyleContext, aComputedValue);
    2326                 : }
    2327                 : 
    2328                 : bool
    2329               0 : nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty,
    2330                 :                                  nsPresContext* aPresContext,
    2331                 :                                  const Value& aComputedValue,
    2332                 :                                  nsCSSValue& aSpecifiedValue)
    2333                 : {
    2334               0 :   NS_ABORT_IF_FALSE(aPresContext, "null pres context");
    2335                 : 
    2336               0 :   switch (aComputedValue.GetUnit()) {
    2337                 :     case eUnit_Normal:
    2338               0 :       aSpecifiedValue.SetNormalValue();
    2339               0 :       break;
    2340                 :     case eUnit_Auto:
    2341               0 :       aSpecifiedValue.SetAutoValue();
    2342               0 :       break;
    2343                 :     case eUnit_None:
    2344               0 :       aSpecifiedValue.SetNoneValue();
    2345               0 :       break;
    2346                 :     case eUnit_Enumerated:
    2347                 :     case eUnit_Visibility:
    2348                 :       aSpecifiedValue.
    2349               0 :         SetIntValue(aComputedValue.GetIntValue(), eCSSUnit_Enumerated);
    2350               0 :       break;
    2351                 :     case eUnit_Integer:
    2352                 :       aSpecifiedValue.
    2353               0 :         SetIntValue(aComputedValue.GetIntValue(), eCSSUnit_Integer);
    2354               0 :       break;
    2355                 :     case eUnit_Coord:
    2356               0 :       nscoordToCSSValue(aComputedValue.GetCoordValue(), aSpecifiedValue);
    2357               0 :       break;
    2358                 :     case eUnit_Percent:
    2359               0 :       aSpecifiedValue.SetPercentValue(aComputedValue.GetPercentValue());
    2360               0 :       break;
    2361                 :     case eUnit_Float:
    2362                 :       aSpecifiedValue.
    2363               0 :         SetFloatValue(aComputedValue.GetFloatValue(), eCSSUnit_Number);
    2364               0 :       break;
    2365                 :     case eUnit_Color:
    2366                 :       // colors can be alone, or part of a paint server
    2367               0 :       aSpecifiedValue.SetColorValue(aComputedValue.GetColorValue());
    2368               0 :       break;
    2369                 :     case eUnit_Calc: {
    2370               0 :       nsCSSValue *val = aComputedValue.GetCSSValueValue();
    2371               0 :       NS_ABORT_IF_FALSE(val->GetUnit() == eCSSUnit_Calc, "unexpected unit");
    2372               0 :       aSpecifiedValue = *val;
    2373               0 :       break;
    2374                 :     }
    2375                 :     case eUnit_CSSValuePair: {
    2376                 :       // Rule node processing expects pair values to be collapsed to a
    2377                 :       // single value if both halves would be equal, for most but not
    2378                 :       // all properties.  At present, all animatable properties that
    2379                 :       // use pairs do expect collapsing.
    2380               0 :       const nsCSSValuePair* pair = aComputedValue.GetCSSValuePairValue();
    2381               0 :       if (pair->mXValue == pair->mYValue) {
    2382               0 :         aSpecifiedValue = pair->mXValue;
    2383                 :       } else {
    2384               0 :         aSpecifiedValue.SetPairValue(pair);
    2385                 :       }
    2386               0 :     } break;
    2387                 :     case eUnit_CSSValueTriplet: {
    2388                 :       // Rule node processing expects triplet values to be collapsed to a
    2389                 :       // single value if both halves would be equal, for most but not
    2390                 :       // all properties.  At present, all animatable properties that
    2391                 :       // use pairs do expect collapsing.
    2392               0 :       const nsCSSValueTriplet* triplet = aComputedValue.GetCSSValueTripletValue();
    2393               0 :       if (triplet->mXValue == triplet->mYValue && triplet->mYValue == triplet->mZValue) {
    2394               0 :         aSpecifiedValue = triplet->mXValue;
    2395                 :       } else {
    2396               0 :         aSpecifiedValue.SetTripletValue(triplet);
    2397                 :       }
    2398               0 :     } break;
    2399                 :     case eUnit_CSSRect: {
    2400               0 :       nsCSSRect& rect = aSpecifiedValue.SetRectValue();
    2401               0 :       rect = *aComputedValue.GetCSSRectValue();
    2402               0 :     } break;
    2403                 :     case eUnit_Dasharray:
    2404                 :     case eUnit_Shadow:
    2405                 :     case eUnit_Transform:
    2406                 :     case eUnit_BackgroundPosition:
    2407                 :       aSpecifiedValue.
    2408               0 :         SetDependentListValue(aComputedValue.GetCSSValueListValue());
    2409               0 :       break;
    2410                 :     case eUnit_CSSValuePairList:
    2411                 :       aSpecifiedValue.
    2412               0 :         SetDependentPairListValue(aComputedValue.GetCSSValuePairListValue());
    2413               0 :       break;
    2414                 :     default:
    2415               0 :       return false;
    2416                 :   }
    2417               0 :   return true;
    2418                 : }
    2419                 : 
    2420                 : bool
    2421               0 : nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty,
    2422                 :                                  nsPresContext* aPresContext,
    2423                 :                                  const Value& aComputedValue,
    2424                 :                                  nsAString& aSpecifiedValue)
    2425                 : {
    2426               0 :   NS_ABORT_IF_FALSE(aPresContext, "null pres context");
    2427               0 :   aSpecifiedValue.Truncate(); // Clear outparam, if it's not already empty
    2428                 : 
    2429               0 :   if (aComputedValue.GetUnit() == eUnit_UnparsedString) {
    2430               0 :     aComputedValue.GetStringValue(aSpecifiedValue);
    2431               0 :     return true;
    2432                 :   }
    2433               0 :   nsCSSValue val;
    2434               0 :   if (!nsStyleAnimation::UncomputeValue(aProperty, aPresContext,
    2435               0 :                                         aComputedValue, val)) {
    2436               0 :     return false;
    2437                 :   }
    2438                 : 
    2439               0 :   val.AppendToString(aProperty, aSpecifiedValue);
    2440               0 :   return true;
    2441                 : }
    2442                 : 
    2443                 : inline const void*
    2444               0 : StyleDataAtOffset(const void* aStyleStruct, ptrdiff_t aOffset)
    2445                 : {
    2446               0 :   return reinterpret_cast<const char*>(aStyleStruct) + aOffset;
    2447                 : }
    2448                 : 
    2449                 : inline void*
    2450                 : StyleDataAtOffset(void* aStyleStruct, ptrdiff_t aOffset)
    2451                 : {
    2452                 :   return reinterpret_cast<char*>(aStyleStruct) + aOffset;
    2453                 : }
    2454                 : 
    2455                 : static void
    2456               0 : ExtractBorderColor(nsStyleContext* aStyleContext, const void* aStyleBorder,
    2457                 :                    mozilla::css::Side aSide, nsStyleAnimation::Value& aComputedValue)
    2458                 : {
    2459                 :   nscolor color;
    2460                 :   bool foreground;
    2461                 :   static_cast<const nsStyleBorder*>(aStyleBorder)->
    2462               0 :     GetBorderColor(aSide, color, foreground);
    2463               0 :   if (foreground) {
    2464                 :     // FIXME: should add test for this
    2465               0 :     color = aStyleContext->GetStyleColor()->mColor;
    2466                 :   }
    2467               0 :   aComputedValue.SetColorValue(color);
    2468               0 : }
    2469                 : 
    2470                 : static bool
    2471               0 : StyleCoordToValue(const nsStyleCoord& aCoord, nsStyleAnimation::Value& aValue)
    2472                 : {
    2473               0 :   switch (aCoord.GetUnit()) {
    2474                 :     case eStyleUnit_Normal:
    2475               0 :       aValue.SetNormalValue();
    2476               0 :       break;
    2477                 :     case eStyleUnit_Auto:
    2478               0 :       aValue.SetAutoValue();
    2479               0 :       break;
    2480                 :     case eStyleUnit_None:
    2481               0 :       aValue.SetNoneValue();
    2482               0 :       break;
    2483                 :     case eStyleUnit_Percent:
    2484               0 :       aValue.SetPercentValue(aCoord.GetPercentValue());
    2485               0 :       break;
    2486                 :     case eStyleUnit_Factor:
    2487               0 :       aValue.SetFloatValue(aCoord.GetFactorValue());
    2488               0 :       break;
    2489                 :     case eStyleUnit_Coord:
    2490               0 :       aValue.SetCoordValue(aCoord.GetCoordValue());
    2491               0 :       break;
    2492                 :     case eStyleUnit_Enumerated:
    2493                 :       aValue.SetIntValue(aCoord.GetIntValue(),
    2494               0 :                          nsStyleAnimation::eUnit_Enumerated);
    2495               0 :       break;
    2496                 :     case eStyleUnit_Integer:
    2497                 :       aValue.SetIntValue(aCoord.GetIntValue(),
    2498               0 :                          nsStyleAnimation::eUnit_Integer);
    2499               0 :       break;
    2500                 :     case eStyleUnit_Calc: {
    2501               0 :       nsAutoPtr<nsCSSValue> val(new nsCSSValue);
    2502               0 :       SetCalcValue(aCoord.GetCalcValue(), *val);
    2503                 :       aValue.SetAndAdoptCSSValueValue(val.forget(),
    2504               0 :                                       nsStyleAnimation::eUnit_Calc);
    2505                 :       break;
    2506                 :     }
    2507                 :     default:
    2508               0 :       return false;
    2509                 :   }
    2510               0 :   return true;
    2511                 : }
    2512                 : 
    2513                 : static bool
    2514               0 : StyleCoordToCSSValue(const nsStyleCoord& aCoord, nsCSSValue& aCSSValue)
    2515                 : {
    2516               0 :   switch (aCoord.GetUnit()) {
    2517                 :     case eStyleUnit_Coord:
    2518               0 :       nscoordToCSSValue(aCoord.GetCoordValue(), aCSSValue);
    2519               0 :       break;
    2520                 :     case eStyleUnit_Percent:
    2521               0 :       aCSSValue.SetPercentValue(aCoord.GetPercentValue());
    2522               0 :       break;
    2523                 :     case eStyleUnit_Calc:
    2524               0 :       SetCalcValue(aCoord.GetCalcValue(), aCSSValue);
    2525               0 :       break;
    2526                 :     default:
    2527               0 :       NS_ABORT_IF_FALSE(false, "unexpected unit");
    2528               0 :       return false;
    2529                 :   }
    2530               0 :   return true;
    2531                 : }
    2532                 : 
    2533                 : /*
    2534                 :  * Assign |aOutput = aInput|, except with any non-pixel lengths
    2535                 :  * replaced with the equivalent in pixels, and any non-canonical calc()
    2536                 :  * expressions replaced with canonical ones.
    2537                 :  */
    2538                 : static void
    2539               0 : SubstitutePixelValues(nsStyleContext* aStyleContext,
    2540                 :                       const nsCSSValue& aInput, nsCSSValue& aOutput)
    2541                 : {
    2542               0 :   if (aInput.IsCalcUnit()) {
    2543               0 :     bool canStoreInRuleTree = true;
    2544                 :     nsRuleNode::ComputedCalc c =
    2545                 :       nsRuleNode::SpecifiedCalcToComputedCalc(aInput, aStyleContext,
    2546                 :                                               aStyleContext->PresContext(),
    2547               0 :                                               canStoreInRuleTree);
    2548                 :     nsStyleCoord::Calc c2;
    2549               0 :     c2.mLength = c.mLength;
    2550               0 :     c2.mPercent = c.mPercent;
    2551               0 :     c2.mHasPercent = true; // doesn't matter for transform translate
    2552               0 :     SetCalcValue(&c2, aOutput);
    2553               0 :   } else if (aInput.UnitHasArrayValue()) {
    2554               0 :     const nsCSSValue::Array *inputArray = aInput.GetArrayValue();
    2555                 :     nsRefPtr<nsCSSValue::Array> outputArray =
    2556               0 :       nsCSSValue::Array::Create(inputArray->Count());
    2557               0 :     for (size_t i = 0, i_end = inputArray->Count(); i < i_end; ++i) {
    2558                 :       SubstitutePixelValues(aStyleContext,
    2559               0 :                             inputArray->Item(i), outputArray->Item(i));
    2560                 :     }
    2561               0 :     aOutput.SetArrayValue(outputArray, aInput.GetUnit());
    2562               0 :   } else if (aInput.IsLengthUnit() &&
    2563               0 :              aInput.GetUnit() != eCSSUnit_Pixel) {
    2564               0 :     bool canStoreInRuleTree = true;
    2565                 :     nscoord len = nsRuleNode::CalcLength(aInput, aStyleContext,
    2566                 :                                          aStyleContext->PresContext(),
    2567               0 :                                          canStoreInRuleTree);
    2568                 :     aOutput.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(len),
    2569               0 :                           eCSSUnit_Pixel);
    2570                 :   } else {
    2571               0 :     aOutput = aInput;
    2572                 :   }
    2573               0 : }
    2574                 : 
    2575                 : bool
    2576               0 : nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty,
    2577                 :                                        nsStyleContext* aStyleContext,
    2578                 :                                        Value& aComputedValue)
    2579                 : {
    2580               0 :   NS_ABORT_IF_FALSE(0 <= aProperty &&
    2581                 :                     aProperty < eCSSProperty_COUNT_no_shorthands,
    2582                 :                     "bad property");
    2583                 :   const void* styleStruct =
    2584               0 :     aStyleContext->GetStyleData(nsCSSProps::kSIDTable[aProperty]);
    2585               0 :   ptrdiff_t ssOffset = nsCSSProps::kStyleStructOffsetTable[aProperty];
    2586               0 :   nsStyleAnimType animType = nsCSSProps::kAnimTypeTable[aProperty];
    2587               0 :   NS_ABORT_IF_FALSE(0 <= ssOffset || animType == eStyleAnimType_Custom,
    2588                 :                     "must be dealing with animatable property");
    2589               0 :   switch (animType) {
    2590                 :     case eStyleAnimType_Custom:
    2591               0 :       switch (aProperty) {
    2592                 :         // For border-width, ignore the border-image business (which
    2593                 :         // only exists until we update our implementation to the current
    2594                 :         // spec) and use GetComputedBorder
    2595                 : 
    2596                 :         #define BORDER_WIDTH_CASE(prop_, side_)                               \
    2597                 :         case prop_:                                                           \
    2598                 :           aComputedValue.SetCoordValue(                                       \
    2599                 :             static_cast<const nsStyleBorder*>(styleStruct)->                  \
    2600                 :               GetComputedBorder().side_);                                     \
    2601                 :           break;
    2602               0 :         BORDER_WIDTH_CASE(eCSSProperty_border_bottom_width, bottom)
    2603               0 :         BORDER_WIDTH_CASE(eCSSProperty_border_left_width_value, left)
    2604               0 :         BORDER_WIDTH_CASE(eCSSProperty_border_right_width_value, right)
    2605               0 :         BORDER_WIDTH_CASE(eCSSProperty_border_top_width, top)
    2606                 :         #undef BORDER_WIDTH_CASE
    2607                 : 
    2608                 :         case eCSSProperty__moz_column_rule_width:
    2609                 :           aComputedValue.SetCoordValue(
    2610                 :             static_cast<const nsStyleColumn*>(styleStruct)->
    2611               0 :               GetComputedColumnRuleWidth());
    2612               0 :           break;
    2613                 : 
    2614                 :         case eCSSProperty_border_bottom_color:
    2615                 :           ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_BOTTOM,
    2616               0 :                              aComputedValue);
    2617               0 :           break;
    2618                 :         case eCSSProperty_border_left_color_value:
    2619                 :           ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_LEFT,
    2620               0 :                              aComputedValue);
    2621               0 :           break;
    2622                 :         case eCSSProperty_border_right_color_value:
    2623                 :           ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_RIGHT,
    2624               0 :                              aComputedValue);
    2625               0 :           break;
    2626                 :         case eCSSProperty_border_top_color:
    2627                 :           ExtractBorderColor(aStyleContext, styleStruct, NS_SIDE_TOP,
    2628               0 :                              aComputedValue);
    2629               0 :           break;
    2630                 : 
    2631                 :         case eCSSProperty_outline_color: {
    2632                 :           const nsStyleOutline *styleOutline =
    2633               0 :             static_cast<const nsStyleOutline*>(styleStruct);
    2634                 :           nscolor color;
    2635               0 :           if (!styleOutline->GetOutlineColor(color))
    2636               0 :             color = aStyleContext->GetStyleColor()->mColor;
    2637               0 :           aComputedValue.SetColorValue(color);
    2638               0 :           break;
    2639                 :         }
    2640                 : 
    2641                 :         case eCSSProperty__moz_column_rule_color: {
    2642                 :           const nsStyleColumn *styleColumn =
    2643               0 :             static_cast<const nsStyleColumn*>(styleStruct);
    2644                 :           nscolor color;
    2645               0 :           if (styleColumn->mColumnRuleColorIsForeground) {
    2646               0 :             color = aStyleContext->GetStyleColor()->mColor;
    2647                 :           } else {
    2648               0 :             color = styleColumn->mColumnRuleColor;
    2649                 :           }
    2650               0 :           aComputedValue.SetColorValue(color);
    2651               0 :           break;
    2652                 :         }
    2653                 : 
    2654                 :         case eCSSProperty__moz_column_count: {
    2655                 :           const nsStyleColumn *styleColumn =
    2656               0 :             static_cast<const nsStyleColumn*>(styleStruct);
    2657               0 :           if (styleColumn->mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) {
    2658               0 :             aComputedValue.SetAutoValue();
    2659                 :           } else {
    2660                 :             aComputedValue.SetIntValue(styleColumn->mColumnCount,
    2661               0 :                                        eUnit_Integer);
    2662                 :           }
    2663               0 :           break;
    2664                 :         }
    2665                 : 
    2666                 :         case eCSSProperty_text_decoration_color: {
    2667                 :           const nsStyleTextReset *styleTextReset =
    2668               0 :             static_cast<const nsStyleTextReset*>(styleStruct);
    2669                 :           nscolor color;
    2670                 :           bool isForeground;
    2671               0 :           styleTextReset->GetDecorationColor(color, isForeground);
    2672               0 :           if (isForeground) {
    2673               0 :             color = aStyleContext->GetStyleColor()->mColor;
    2674                 :           }
    2675               0 :           aComputedValue.SetColorValue(color);
    2676               0 :           break;
    2677                 :         }
    2678                 : 
    2679                 :         case eCSSProperty_text_decoration_style: {
    2680                 :           PRUint8 decorationStyle =
    2681                 :             static_cast<const nsStyleTextReset*>(styleStruct)->
    2682               0 :               GetDecorationStyle();
    2683               0 :           aComputedValue.SetIntValue(decorationStyle, eUnit_Enumerated);
    2684               0 :           break;
    2685                 :         }
    2686                 : 
    2687                 :         case eCSSProperty_border_spacing: {
    2688                 :           const nsStyleTableBorder *styleTableBorder =
    2689               0 :             static_cast<const nsStyleTableBorder*>(styleStruct);
    2690               0 :           nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair);
    2691               0 :           if (!pair) {
    2692               0 :             return false;
    2693                 :           }
    2694               0 :           nscoordToCSSValue(styleTableBorder->mBorderSpacingX, pair->mXValue);
    2695               0 :           nscoordToCSSValue(styleTableBorder->mBorderSpacingY, pair->mYValue);
    2696                 :           aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(),
    2697               0 :                                                       eUnit_CSSValuePair);
    2698               0 :           break;
    2699                 :         }
    2700                 : 
    2701                 :         case eCSSProperty__moz_transform_origin: {
    2702                 :           const nsStyleDisplay *styleDisplay =
    2703               0 :             static_cast<const nsStyleDisplay*>(styleStruct);
    2704               0 :           nsAutoPtr<nsCSSValueTriplet> triplet(new nsCSSValueTriplet);
    2705               0 :           if (!triplet ||
    2706                 :               !StyleCoordToCSSValue(styleDisplay->mTransformOrigin[0],
    2707               0 :                                     triplet->mXValue) ||
    2708                 :               !StyleCoordToCSSValue(styleDisplay->mTransformOrigin[1],
    2709               0 :                                     triplet->mYValue) ||
    2710                 :               !StyleCoordToCSSValue(styleDisplay->mTransformOrigin[2],
    2711               0 :                                     triplet->mZValue)) {
    2712               0 :             return false;
    2713                 :           }
    2714               0 :           if (triplet->mZValue.GetUnit() == eCSSUnit_Pixel &&
    2715               0 :               triplet->mZValue.GetFloatValue() == 0.0f) {
    2716               0 :             triplet->mZValue.Reset();
    2717                 :           }
    2718                 :           aComputedValue.SetAndAdoptCSSValueTripletValue(triplet.forget(),
    2719               0 :                                                          eUnit_CSSValueTriplet);
    2720               0 :           break;
    2721                 :         }
    2722                 : 
    2723                 :         case eCSSProperty_perspective_origin: {
    2724                 :           const nsStyleDisplay *styleDisplay =
    2725               0 :             static_cast<const nsStyleDisplay*>(styleStruct);
    2726               0 :           nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair);
    2727               0 :           if (!pair ||
    2728                 :               !StyleCoordToCSSValue(styleDisplay->mPerspectiveOrigin[0],
    2729               0 :                                     pair->mXValue) ||
    2730                 :               !StyleCoordToCSSValue(styleDisplay->mPerspectiveOrigin[1],
    2731               0 :                                     pair->mYValue)) {
    2732               0 :             return false;
    2733                 :           }
    2734                 :           aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(),
    2735               0 :                                                       eUnit_CSSValuePair);
    2736               0 :           break;
    2737                 :         }
    2738                 : 
    2739                 :         case eCSSProperty_stroke_dasharray: {
    2740               0 :           const nsStyleSVG *svg = static_cast<const nsStyleSVG*>(styleStruct);
    2741               0 :           NS_ABORT_IF_FALSE((svg->mStrokeDasharray != nsnull) ==
    2742                 :                             (svg->mStrokeDasharrayLength != 0),
    2743                 :                             "pointer/length mismatch");
    2744               0 :           nsAutoPtr<nsCSSValueList> result;
    2745               0 :           if (svg->mStrokeDasharray) {
    2746               0 :             NS_ABORT_IF_FALSE(svg->mStrokeDasharrayLength > 0,
    2747                 :                               "non-null list should have positive length");
    2748               0 :             nsCSSValueList **resultTail = getter_Transfers(result);
    2749               0 :             for (PRUint32 i = 0, i_end = svg->mStrokeDasharrayLength;
    2750                 :                  i != i_end; ++i) {
    2751               0 :               nsCSSValueList *item = new nsCSSValueList;
    2752               0 :               if (!item) {
    2753               0 :                 return false;
    2754                 :               }
    2755               0 :               *resultTail = item;
    2756               0 :               resultTail = &item->mNext;
    2757                 : 
    2758               0 :               const nsStyleCoord &coord = svg->mStrokeDasharray[i];
    2759               0 :               nsCSSValue &value = item->mValue;
    2760               0 :               switch (coord.GetUnit()) {
    2761                 :                 case eStyleUnit_Coord:
    2762                 :                   // Number means the same thing as length; we want to
    2763                 :                   // animate them the same way.  Normalize both to number
    2764                 :                   // since it has more accuracy (float vs nscoord).
    2765                 :                   value.SetFloatValue(nsPresContext::
    2766                 :                     AppUnitsToFloatCSSPixels(coord.GetCoordValue()),
    2767               0 :                     eCSSUnit_Number);
    2768               0 :                   break;
    2769                 :                 case eStyleUnit_Factor:
    2770                 :                   value.SetFloatValue(coord.GetFactorValue(),
    2771               0 :                                       eCSSUnit_Number);
    2772               0 :                   break;
    2773                 :                 case eStyleUnit_Percent:
    2774               0 :                   value.SetPercentValue(coord.GetPercentValue());
    2775               0 :                   break;
    2776                 :                 default:
    2777               0 :                   NS_ABORT_IF_FALSE(false, "unexpected unit");
    2778               0 :                   return false;
    2779                 :               }
    2780                 :             }
    2781                 :           } else {
    2782               0 :             result = new nsCSSValueList;
    2783               0 :             if (!result) {
    2784               0 :               return false;
    2785                 :             }
    2786               0 :             result->mValue.SetNoneValue();
    2787                 :           }
    2788                 :           aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
    2789               0 :                                                       eUnit_Dasharray);
    2790               0 :           break;
    2791                 :         }
    2792                 : 
    2793                 :         case eCSSProperty_font_stretch: {
    2794                 :           PRInt16 stretch =
    2795               0 :             static_cast<const nsStyleFont*>(styleStruct)->mFont.stretch;
    2796                 :           MOZ_STATIC_ASSERT(NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED == -4 &&
    2797                 :                             NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED == 4,
    2798                 :                             "font stretch constants not as expected");
    2799               0 :           if (stretch < NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED ||
    2800                 :               stretch > NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED) {
    2801               0 :             return false;
    2802                 :           }
    2803               0 :           aComputedValue.SetIntValue(stretch, eUnit_Enumerated);
    2804               0 :           return true;
    2805                 :         }
    2806                 : 
    2807                 :         case eCSSProperty_font_weight: {
    2808                 :           PRUint16 weight =
    2809               0 :             static_cast<const nsStyleFont*>(styleStruct)->mFont.weight;
    2810               0 :           if (weight % 100 != 0) {
    2811               0 :             return false;
    2812                 :           }
    2813               0 :           aComputedValue.SetIntValue(weight, eUnit_Integer);
    2814               0 :           return true;
    2815                 :         }
    2816                 : 
    2817                 :         case eCSSProperty_image_region: {
    2818                 :           const nsStyleList *list =
    2819               0 :             static_cast<const nsStyleList*>(styleStruct);
    2820               0 :           const nsRect &srect = list->mImageRegion;
    2821               0 :           if (srect.IsEmpty()) {
    2822               0 :             aComputedValue.SetAutoValue();
    2823               0 :             break;
    2824                 :           }
    2825                 : 
    2826               0 :           nsCSSRect *vrect = new nsCSSRect;
    2827               0 :           nscoordToCSSValue(srect.x, vrect->mLeft);
    2828               0 :           nscoordToCSSValue(srect.y, vrect->mTop);
    2829               0 :           nscoordToCSSValue(srect.XMost(), vrect->mRight);
    2830               0 :           nscoordToCSSValue(srect.YMost(), vrect->mBottom);
    2831               0 :           aComputedValue.SetAndAdoptCSSRectValue(vrect, eUnit_CSSRect);
    2832               0 :           break;
    2833                 :         }
    2834                 : 
    2835                 :         case eCSSProperty_clip: {
    2836                 :           const nsStyleDisplay *display =
    2837               0 :             static_cast<const nsStyleDisplay*>(styleStruct);
    2838               0 :           if (!(display->mClipFlags & NS_STYLE_CLIP_RECT)) {
    2839               0 :             aComputedValue.SetAutoValue();
    2840                 :           } else {
    2841               0 :             nsCSSRect *vrect = new nsCSSRect;
    2842               0 :             const nsRect &srect = display->mClip;
    2843               0 :             if (display->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) {
    2844               0 :               vrect->mTop.SetAutoValue();
    2845                 :             } else {
    2846               0 :               nscoordToCSSValue(srect.y, vrect->mTop);
    2847                 :             }
    2848               0 :             if (display->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) {
    2849               0 :               vrect->mRight.SetAutoValue();
    2850                 :             } else {
    2851               0 :               nscoordToCSSValue(srect.XMost(), vrect->mRight);
    2852                 :             }
    2853               0 :             if (display->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) {
    2854               0 :               vrect->mBottom.SetAutoValue();
    2855                 :             } else {
    2856               0 :               nscoordToCSSValue(srect.YMost(), vrect->mBottom);
    2857                 :             }
    2858               0 :             if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) {
    2859               0 :               vrect->mLeft.SetAutoValue();
    2860                 :             } else {
    2861               0 :               nscoordToCSSValue(srect.x, vrect->mLeft);
    2862                 :             }
    2863               0 :             aComputedValue.SetAndAdoptCSSRectValue(vrect, eUnit_CSSRect);
    2864                 :           }
    2865               0 :           break;
    2866                 :         }
    2867                 : 
    2868                 :         case eCSSProperty_background_position: {
    2869                 :           const nsStyleBackground *bg =
    2870               0 :             static_cast<const nsStyleBackground*>(styleStruct);
    2871               0 :           nsAutoPtr<nsCSSValueList> result;
    2872               0 :           nsCSSValueList **resultTail = getter_Transfers(result);
    2873               0 :           NS_ABORT_IF_FALSE(bg->mPositionCount > 0, "unexpected count");
    2874               0 :           for (PRUint32 i = 0, i_end = bg->mPositionCount; i != i_end; ++i) {
    2875               0 :             nsCSSValueList *item = new nsCSSValueList;
    2876               0 :             *resultTail = item;
    2877               0 :             resultTail = &item->mNext;
    2878               0 :             nsRefPtr<nsCSSValue::Array> bgArray = nsCSSValue::Array::Create(4);
    2879               0 :             item->mValue.SetArrayValue(bgArray.get(), eCSSUnit_Array);
    2880                 : 
    2881               0 :             const nsStyleBackground::Position &pos = bg->mLayers[i].mPosition;
    2882                 :             // XXXbz is there a good reason we can't just
    2883                 :             // SetCalcValue(&pos.mXPosition, item->mXValue) here?
    2884               0 :             nsCSSValue &xValue = bgArray->Item(1),
    2885               0 :                        &yValue = bgArray->Item(3);
    2886               0 :             if (!pos.mXPosition.mHasPercent) {
    2887               0 :               NS_ABORT_IF_FALSE(pos.mXPosition.mPercent == 0.0f,
    2888                 :                                 "Shouldn't have mPercent!");
    2889               0 :               nscoordToCSSValue(pos.mXPosition.mLength, xValue);
    2890               0 :             } else if (pos.mXPosition.mLength == 0) {
    2891               0 :               xValue.SetPercentValue(pos.mXPosition.mPercent);
    2892                 :             } else {
    2893               0 :               SetCalcValue(&pos.mXPosition, xValue);
    2894                 :             }
    2895                 : 
    2896               0 :             if (!pos.mYPosition.mHasPercent) {
    2897               0 :               NS_ABORT_IF_FALSE(pos.mYPosition.mPercent == 0.0f,
    2898                 :                                 "Shouldn't have mPercent!");
    2899               0 :               nscoordToCSSValue(pos.mYPosition.mLength, yValue);
    2900               0 :             } else if (pos.mYPosition.mLength == 0) {
    2901               0 :               yValue.SetPercentValue(pos.mYPosition.mPercent);
    2902                 :             } else {
    2903               0 :               SetCalcValue(&pos.mYPosition, yValue);
    2904                 :             }
    2905                 :           }
    2906                 : 
    2907                 :           aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
    2908               0 :                                                       eUnit_BackgroundPosition);
    2909                 :           break;
    2910                 :         }
    2911                 : 
    2912                 :         case eCSSProperty_background_size: {
    2913                 :           const nsStyleBackground *bg =
    2914               0 :             static_cast<const nsStyleBackground*>(styleStruct);
    2915               0 :           nsAutoPtr<nsCSSValuePairList> result;
    2916               0 :           nsCSSValuePairList **resultTail = getter_Transfers(result);
    2917               0 :           NS_ABORT_IF_FALSE(bg->mSizeCount > 0, "unexpected count");
    2918               0 :           for (PRUint32 i = 0, i_end = bg->mSizeCount; i != i_end; ++i) {
    2919               0 :             nsCSSValuePairList *item = new nsCSSValuePairList;
    2920               0 :             *resultTail = item;
    2921               0 :             resultTail = &item->mNext;
    2922                 : 
    2923               0 :             const nsStyleBackground::Size &size = bg->mLayers[i].mSize;
    2924               0 :             switch (size.mWidthType) {
    2925                 :               case nsStyleBackground::Size::eContain:
    2926                 :               case nsStyleBackground::Size::eCover:
    2927                 :                 item->mXValue.SetIntValue(size.mWidthType,
    2928               0 :                                           eCSSUnit_Enumerated);
    2929               0 :                 break;
    2930                 :               case nsStyleBackground::Size::eAuto:
    2931               0 :                 item->mXValue.SetAutoValue();
    2932               0 :                 break;
    2933                 :               case nsStyleBackground::Size::eLengthPercentage:
    2934                 :                 // XXXbz is there a good reason we can't just
    2935                 :                 // SetCalcValue(&size.mWidth, item->mXValue) here?
    2936               0 :                 if (!size.mWidth.mHasPercent &&
    2937                 :                     // negative values must have come from calc()
    2938                 :                     size.mWidth.mLength >= 0) {
    2939               0 :                   NS_ABORT_IF_FALSE(size.mWidth.mPercent == 0.0f,
    2940                 :                                     "Shouldn't have mPercent");
    2941               0 :                   nscoordToCSSValue(size.mWidth.mLength, item->mXValue);
    2942               0 :                 } else if (size.mWidth.mLength == 0 &&
    2943                 :                            // negative values must have come from calc()
    2944                 :                            size.mWidth.mPercent >= 0.0f) {
    2945               0 :                   item->mXValue.SetPercentValue(size.mWidth.mPercent);
    2946                 :                 } else {
    2947               0 :                   SetCalcValue(&size.mWidth, item->mXValue);
    2948                 :                 }
    2949               0 :                 break;
    2950                 :             }
    2951                 : 
    2952               0 :             switch (size.mHeightType) {
    2953                 :               case nsStyleBackground::Size::eContain:
    2954                 :               case nsStyleBackground::Size::eCover:
    2955                 :                 // leave it null
    2956               0 :                 break;
    2957                 :               case nsStyleBackground::Size::eAuto:
    2958               0 :                 item->mYValue.SetAutoValue();
    2959               0 :                 break;
    2960                 :               case nsStyleBackground::Size::eLengthPercentage:
    2961                 :                 // XXXbz is there a good reason we can't just
    2962                 :                 // SetCalcValue(&size.mHeight, item->mYValue) here?
    2963               0 :                 if (!size.mHeight.mHasPercent &&
    2964                 :                     // negative values must have come from calc()
    2965                 :                     size.mHeight.mLength >= 0) {
    2966               0 :                   NS_ABORT_IF_FALSE(size.mHeight.mPercent == 0.0f,
    2967                 :                                     "Shouldn't have mPercent");
    2968               0 :                   nscoordToCSSValue(size.mHeight.mLength, item->mYValue);
    2969               0 :                 } else if (size.mHeight.mLength == 0 &&
    2970                 :                            // negative values must have come from calc()
    2971                 :                            size.mHeight.mPercent >= 0.0f) {
    2972               0 :                   item->mYValue.SetPercentValue(size.mHeight.mPercent);
    2973                 :                 } else {
    2974               0 :                   SetCalcValue(&size.mHeight, item->mYValue);
    2975                 :                 }
    2976               0 :                 break;
    2977                 :             }
    2978                 :           }
    2979                 : 
    2980               0 :           aComputedValue.SetAndAdoptCSSValuePairListValue(result.forget());
    2981                 :           break;
    2982                 :         }
    2983                 : 
    2984                 :         case eCSSProperty__moz_transform: {
    2985                 :           const nsStyleDisplay *display =
    2986               0 :             static_cast<const nsStyleDisplay*>(styleStruct);
    2987               0 :           nsAutoPtr<nsCSSValueList> result;
    2988               0 :           if (display->mSpecifiedTransform) {
    2989                 :             // Clone, and convert all lengths (not percents) to pixels.
    2990               0 :             nsCSSValueList **resultTail = getter_Transfers(result);
    2991               0 :             for (const nsCSSValueList *l = display->mSpecifiedTransform;
    2992                 :                  l; l = l->mNext) {
    2993               0 :               nsCSSValueList *clone = new nsCSSValueList;
    2994               0 :               *resultTail = clone;
    2995               0 :               resultTail = &clone->mNext;
    2996                 : 
    2997               0 :               SubstitutePixelValues(aStyleContext, l->mValue, clone->mValue);
    2998                 :             }
    2999                 :           } else {
    3000               0 :             result = new nsCSSValueList();
    3001               0 :             result->mValue.SetNoneValue();
    3002                 :           }
    3003                 : 
    3004                 :           aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
    3005               0 :                                                       eUnit_Transform);
    3006                 :           break;
    3007                 :         }
    3008                 : 
    3009                 :         default:
    3010               0 :           NS_ABORT_IF_FALSE(false, "missing property implementation");
    3011               0 :           return false;
    3012                 :       };
    3013               0 :       return true;
    3014                 :     case eStyleAnimType_Coord:
    3015                 :       return StyleCoordToValue(*static_cast<const nsStyleCoord*>(
    3016               0 :         StyleDataAtOffset(styleStruct, ssOffset)), aComputedValue);
    3017                 :     case eStyleAnimType_Sides_Top:
    3018                 :     case eStyleAnimType_Sides_Right:
    3019                 :     case eStyleAnimType_Sides_Bottom:
    3020                 :     case eStyleAnimType_Sides_Left: {
    3021                 :       MOZ_STATIC_ASSERT(
    3022                 :        NS_SIDE_TOP    == eStyleAnimType_Sides_Top   -eStyleAnimType_Sides_Top &&
    3023                 :        NS_SIDE_RIGHT  == eStyleAnimType_Sides_Right -eStyleAnimType_Sides_Top &&
    3024                 :        NS_SIDE_BOTTOM == eStyleAnimType_Sides_Bottom-eStyleAnimType_Sides_Top &&
    3025                 :        NS_SIDE_LEFT   == eStyleAnimType_Sides_Left  -eStyleAnimType_Sides_Top,
    3026                 :        "box side constants out of sync with animation side constants");
    3027                 : 
    3028                 :       const nsStyleCoord &coord = static_cast<const nsStyleSides*>(
    3029               0 :         StyleDataAtOffset(styleStruct, ssOffset))->
    3030               0 :           Get(mozilla::css::Side(animType - eStyleAnimType_Sides_Top));
    3031               0 :       return StyleCoordToValue(coord, aComputedValue);
    3032                 :     }
    3033                 :     case eStyleAnimType_Corner_TopLeft:
    3034                 :     case eStyleAnimType_Corner_TopRight:
    3035                 :     case eStyleAnimType_Corner_BottomRight:
    3036                 :     case eStyleAnimType_Corner_BottomLeft: {
    3037                 :       MOZ_STATIC_ASSERT(
    3038                 :        NS_CORNER_TOP_LEFT     == eStyleAnimType_Corner_TopLeft -
    3039                 :                                  eStyleAnimType_Corner_TopLeft        &&
    3040                 :        NS_CORNER_TOP_RIGHT    == eStyleAnimType_Corner_TopRight -
    3041                 :                                  eStyleAnimType_Corner_TopLeft        &&
    3042                 :        NS_CORNER_BOTTOM_RIGHT == eStyleAnimType_Corner_BottomRight -
    3043                 :                                  eStyleAnimType_Corner_TopLeft        &&
    3044                 :        NS_CORNER_BOTTOM_LEFT  == eStyleAnimType_Corner_BottomLeft -
    3045                 :                                  eStyleAnimType_Corner_TopLeft,
    3046                 :        "box corner constants out of sync with animation corner constants");
    3047                 : 
    3048                 :       const nsStyleCorners *corners = static_cast<const nsStyleCorners*>(
    3049               0 :         StyleDataAtOffset(styleStruct, ssOffset));
    3050               0 :       PRUint8 fullCorner = animType - eStyleAnimType_Corner_TopLeft;
    3051                 :       const nsStyleCoord &horiz =
    3052               0 :         corners->Get(NS_FULL_TO_HALF_CORNER(fullCorner, false));
    3053                 :       const nsStyleCoord &vert =
    3054               0 :         corners->Get(NS_FULL_TO_HALF_CORNER(fullCorner, true));
    3055               0 :       nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair);
    3056               0 :       if (!pair ||
    3057               0 :           !StyleCoordToCSSValue(horiz, pair->mXValue) ||
    3058               0 :           !StyleCoordToCSSValue(vert, pair->mYValue)) {
    3059               0 :         return false;
    3060                 :       }
    3061                 :       aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(),
    3062               0 :                                                   eUnit_CSSValuePair);
    3063               0 :       return true;
    3064                 :     }
    3065                 :     case eStyleAnimType_nscoord:
    3066                 :       aComputedValue.SetCoordValue(*static_cast<const nscoord*>(
    3067               0 :         StyleDataAtOffset(styleStruct, ssOffset)));
    3068               0 :       return true;
    3069                 :     case eStyleAnimType_EnumU8:
    3070                 :       aComputedValue.SetIntValue(*static_cast<const PRUint8*>(
    3071               0 :         StyleDataAtOffset(styleStruct, ssOffset)), eUnit_Enumerated);
    3072               0 :       return true;
    3073                 :     case eStyleAnimType_float:
    3074                 :       aComputedValue.SetFloatValue(*static_cast<const float*>(
    3075               0 :         StyleDataAtOffset(styleStruct, ssOffset)));
    3076               0 :       if (aProperty == eCSSProperty_font_size_adjust &&
    3077               0 :           aComputedValue.GetFloatValue() == 0.0f) {
    3078                 :         // In nsStyleFont, we set mFont.sizeAdjust to 0 to represent
    3079                 :         // font-size-adjust: none.  Here, we have to treat this as a keyword
    3080                 :         // instead of a float value, to make sure we don't end up doing
    3081                 :         // interpolation with it.
    3082               0 :         aComputedValue.SetNoneValue();
    3083                 :       }
    3084               0 :       return true;
    3085                 :     case eStyleAnimType_Color:
    3086                 :       aComputedValue.SetColorValue(*static_cast<const nscolor*>(
    3087               0 :         StyleDataAtOffset(styleStruct, ssOffset)));
    3088               0 :       return true;
    3089                 :     case eStyleAnimType_PaintServer: {
    3090                 :       const nsStyleSVGPaint &paint = *static_cast<const nsStyleSVGPaint*>(
    3091               0 :         StyleDataAtOffset(styleStruct, ssOffset));
    3092               0 :       if (paint.mType == eStyleSVGPaintType_Color) {
    3093               0 :         aComputedValue.SetColorValue(paint.mPaint.mColor);
    3094               0 :         return true;
    3095                 :       }
    3096               0 :       if (paint.mType == eStyleSVGPaintType_Server) {
    3097               0 :         if (!paint.mPaint.mPaintServer) {
    3098               0 :           NS_WARNING("Null paint server");
    3099               0 :           return false;
    3100                 :         }
    3101               0 :         nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair);
    3102                 :         nsRefPtr<nsStringBuffer> uriAsStringBuffer =
    3103               0 :           GetURIAsUtf16StringBuffer(paint.mPaint.mPaintServer);
    3104               0 :         NS_ENSURE_TRUE(!!uriAsStringBuffer, false);
    3105               0 :         nsIDocument* doc = aStyleContext->PresContext()->Document();
    3106                 :         nsRefPtr<nsCSSValue::URL> url =
    3107                 :           new nsCSSValue::URL(paint.mPaint.mPaintServer,
    3108                 :                               uriAsStringBuffer,
    3109                 :                               doc->GetDocumentURI(),
    3110               0 :                               doc->NodePrincipal());
    3111               0 :         pair->mXValue.SetURLValue(url);
    3112               0 :         pair->mYValue.SetColorValue(paint.mFallbackColor);
    3113                 :         aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(),
    3114               0 :                                                     eUnit_CSSValuePair);
    3115               0 :         return true;
    3116                 :       }
    3117               0 :       NS_ABORT_IF_FALSE(paint.mType == eStyleSVGPaintType_None,
    3118                 :           "Unexpected SVG paint type");
    3119               0 :       aComputedValue.SetNoneValue();
    3120               0 :       return true;
    3121                 :     }
    3122                 :     case eStyleAnimType_Shadow: {
    3123                 :       const nsCSSShadowArray *shadowArray =
    3124                 :         *static_cast<const nsRefPtr<nsCSSShadowArray>*>(
    3125               0 :           StyleDataAtOffset(styleStruct, ssOffset));
    3126               0 :       if (!shadowArray) {
    3127               0 :         aComputedValue.SetAndAdoptCSSValueListValue(nsnull, eUnit_Shadow);
    3128               0 :         return true;
    3129                 :       }
    3130               0 :       nsAutoPtr<nsCSSValueList> result;
    3131               0 :       nsCSSValueList **resultTail = getter_Transfers(result);
    3132               0 :       for (PRUint32 i = 0, i_end = shadowArray->Length(); i < i_end; ++i) {
    3133               0 :         const nsCSSShadowItem *shadow = shadowArray->ShadowAt(i);
    3134                 :         // X, Y, Radius, Spread, Color, Inset
    3135               0 :         nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(6);
    3136               0 :         nscoordToCSSValue(shadow->mXOffset, arr->Item(0));
    3137               0 :         nscoordToCSSValue(shadow->mYOffset, arr->Item(1));
    3138               0 :         nscoordToCSSValue(shadow->mRadius, arr->Item(2));
    3139                 :         // NOTE: This code sometimes stores mSpread: 0 even when
    3140                 :         // the parser would be required to leave it null.
    3141               0 :         nscoordToCSSValue(shadow->mSpread, arr->Item(3));
    3142               0 :         if (shadow->mHasColor) {
    3143               0 :           arr->Item(4).SetColorValue(shadow->mColor);
    3144                 :         }
    3145               0 :         if (shadow->mInset) {
    3146               0 :           arr->Item(5).SetIntValue(NS_STYLE_BOX_SHADOW_INSET,
    3147               0 :                                    eCSSUnit_Enumerated);
    3148                 :         }
    3149                 : 
    3150               0 :         nsCSSValueList *resultItem = new nsCSSValueList;
    3151               0 :         if (!resultItem) {
    3152               0 :           return false;
    3153                 :         }
    3154               0 :         resultItem->mValue.SetArrayValue(arr, eCSSUnit_Array);
    3155               0 :         *resultTail = resultItem;
    3156               0 :         resultTail = &resultItem->mNext;
    3157                 :       }
    3158                 :       aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
    3159               0 :                                                   eUnit_Shadow);
    3160               0 :       return true;
    3161                 :     }
    3162                 :     case eStyleAnimType_None:
    3163               0 :       NS_NOTREACHED("shouldn't use on non-animatable properties");
    3164                 :   }
    3165               0 :   return false;
    3166                 : }
    3167                 : 
    3168               0 : nsStyleAnimation::Value::Value(PRInt32 aInt, Unit aUnit,
    3169                 :                                IntegerConstructorType)
    3170                 : {
    3171               0 :   NS_ASSERTION(IsIntUnit(aUnit), "unit must be of integer type");
    3172               0 :   mUnit = aUnit;
    3173               0 :   mValue.mInt = aInt;
    3174               0 : }
    3175                 : 
    3176            1464 : nsStyleAnimation::Value::Value(nscoord aLength, CoordConstructorType)
    3177                 : {
    3178            1464 :   mUnit = eUnit_Coord;
    3179            1464 :   mValue.mCoord = aLength;
    3180            1464 : }
    3181                 : 
    3182            1464 : nsStyleAnimation::Value::Value(float aPercent, PercentConstructorType)
    3183                 : {
    3184            1464 :   mUnit = eUnit_Percent;
    3185            1464 :   mValue.mFloat = aPercent;
    3186            1464 : }
    3187                 : 
    3188            1464 : nsStyleAnimation::Value::Value(float aFloat, FloatConstructorType)
    3189                 : {
    3190            1464 :   mUnit = eUnit_Float;
    3191            1464 :   mValue.mFloat = aFloat;
    3192            1464 : }
    3193                 : 
    3194            1464 : nsStyleAnimation::Value::Value(nscolor aColor, ColorConstructorType)
    3195                 : {
    3196            1464 :   mUnit = eUnit_Color;
    3197            1464 :   mValue.mColor = aColor;
    3198            1464 : }
    3199                 : 
    3200                 : nsStyleAnimation::Value&
    3201               0 : nsStyleAnimation::Value::operator=(const Value& aOther)
    3202                 : {
    3203               0 :   FreeValue();
    3204                 : 
    3205               0 :   mUnit = aOther.mUnit;
    3206               0 :   switch (mUnit) {
    3207                 :     case eUnit_Null:
    3208                 :     case eUnit_Normal:
    3209                 :     case eUnit_Auto:
    3210                 :     case eUnit_None:
    3211               0 :       break;
    3212                 :     case eUnit_Enumerated:
    3213                 :     case eUnit_Visibility:
    3214                 :     case eUnit_Integer:
    3215               0 :       mValue.mInt = aOther.mValue.mInt;
    3216               0 :       break;
    3217                 :     case eUnit_Coord:
    3218               0 :       mValue.mCoord = aOther.mValue.mCoord;
    3219               0 :       break;
    3220                 :     case eUnit_Percent:
    3221                 :     case eUnit_Float:
    3222               0 :       mValue.mFloat = aOther.mValue.mFloat;
    3223               0 :       break;
    3224                 :     case eUnit_Color:
    3225               0 :       mValue.mColor = aOther.mValue.mColor;
    3226               0 :       break;
    3227                 :     case eUnit_Calc:
    3228               0 :       NS_ABORT_IF_FALSE(aOther.mValue.mCSSValue, "values may not be null");
    3229               0 :       mValue.mCSSValue = new nsCSSValue(*aOther.mValue.mCSSValue);
    3230               0 :       if (!mValue.mCSSValue) {
    3231               0 :         mUnit = eUnit_Null;
    3232                 :       }
    3233               0 :       break;
    3234                 :     case eUnit_CSSValuePair:
    3235               0 :       NS_ABORT_IF_FALSE(aOther.mValue.mCSSValuePair,
    3236                 :                         "value pairs may not be null");
    3237               0 :       mValue.mCSSValuePair = new nsCSSValuePair(*aOther.mValue.mCSSValuePair);
    3238               0 :       if (!mValue.mCSSValuePair) {
    3239               0 :         mUnit = eUnit_Null;
    3240                 :       }
    3241               0 :       break;
    3242                 :     case eUnit_CSSValueTriplet:
    3243               0 :       NS_ABORT_IF_FALSE(aOther.mValue.mCSSValueTriplet,
    3244                 :                         "value triplets may not be null");
    3245               0 :       mValue.mCSSValueTriplet = new nsCSSValueTriplet(*aOther.mValue.mCSSValueTriplet);
    3246               0 :       if (!mValue.mCSSValueTriplet) {
    3247               0 :         mUnit = eUnit_Null;
    3248                 :       }
    3249               0 :       break;
    3250                 :     case eUnit_CSSRect:
    3251               0 :       NS_ABORT_IF_FALSE(aOther.mValue.mCSSRect, "rects may not be null");
    3252               0 :       mValue.mCSSRect = new nsCSSRect(*aOther.mValue.mCSSRect);
    3253               0 :       if (!mValue.mCSSRect) {
    3254               0 :         mUnit = eUnit_Null;
    3255                 :       }
    3256               0 :       break;
    3257                 :     case eUnit_Dasharray:
    3258                 :     case eUnit_Shadow:
    3259                 :     case eUnit_Transform:
    3260                 :     case eUnit_BackgroundPosition:
    3261               0 :       NS_ABORT_IF_FALSE(mUnit == eUnit_Shadow || aOther.mValue.mCSSValueList,
    3262                 :                         "value lists other than shadows may not be null");
    3263               0 :       if (aOther.mValue.mCSSValueList) {
    3264               0 :         mValue.mCSSValueList = aOther.mValue.mCSSValueList->Clone();
    3265               0 :         if (!mValue.mCSSValueList) {
    3266               0 :           mUnit = eUnit_Null;
    3267                 :         }
    3268                 :       } else {
    3269               0 :         mValue.mCSSValueList = nsnull;
    3270                 :       }
    3271               0 :       break;
    3272                 :     case eUnit_CSSValuePairList:
    3273               0 :       NS_ABORT_IF_FALSE(aOther.mValue.mCSSValuePairList,
    3274                 :                         "value pair lists may not be null");
    3275               0 :       mValue.mCSSValuePairList = aOther.mValue.mCSSValuePairList->Clone();
    3276               0 :       if (!mValue.mCSSValuePairList) {
    3277               0 :         mUnit = eUnit_Null;
    3278                 :       }
    3279               0 :       break;
    3280                 :     case eUnit_UnparsedString:
    3281               0 :       NS_ABORT_IF_FALSE(aOther.mValue.mString, "expecting non-null string");
    3282               0 :       mValue.mString = aOther.mValue.mString;
    3283               0 :       mValue.mString->AddRef();
    3284               0 :       break;
    3285                 :   }
    3286                 : 
    3287               0 :   return *this;
    3288                 : }
    3289                 : 
    3290                 : void
    3291               0 : nsStyleAnimation::Value::SetNormalValue()
    3292                 : {
    3293               0 :   FreeValue();
    3294               0 :   mUnit = eUnit_Normal;
    3295               0 : }
    3296                 : 
    3297                 : void
    3298               0 : nsStyleAnimation::Value::SetAutoValue()
    3299                 : {
    3300               0 :   FreeValue();
    3301               0 :   mUnit = eUnit_Auto;
    3302               0 : }
    3303                 : 
    3304                 : void
    3305               0 : nsStyleAnimation::Value::SetNoneValue()
    3306                 : {
    3307               0 :   FreeValue();
    3308               0 :   mUnit = eUnit_None;
    3309               0 : }
    3310                 : 
    3311                 : void
    3312               0 : nsStyleAnimation::Value::SetIntValue(PRInt32 aInt, Unit aUnit)
    3313                 : {
    3314               0 :   NS_ASSERTION(IsIntUnit(aUnit), "unit must be of integer type");
    3315               0 :   FreeValue();
    3316               0 :   mUnit = aUnit;
    3317               0 :   mValue.mInt = aInt;
    3318               0 : }
    3319                 : 
    3320                 : void
    3321               0 : nsStyleAnimation::Value::SetCoordValue(nscoord aLength)
    3322                 : {
    3323               0 :   FreeValue();
    3324               0 :   mUnit = eUnit_Coord;
    3325               0 :   mValue.mCoord = aLength;
    3326               0 : }
    3327                 : 
    3328                 : void
    3329               0 : nsStyleAnimation::Value::SetPercentValue(float aPercent)
    3330                 : {
    3331               0 :   FreeValue();
    3332               0 :   mUnit = eUnit_Percent;
    3333               0 :   mValue.mFloat = aPercent;
    3334               0 : }
    3335                 : 
    3336                 : void
    3337               0 : nsStyleAnimation::Value::SetFloatValue(float aFloat)
    3338                 : {
    3339               0 :   FreeValue();
    3340               0 :   mUnit = eUnit_Float;
    3341               0 :   mValue.mFloat = aFloat;
    3342               0 : }
    3343                 : 
    3344                 : void
    3345               0 : nsStyleAnimation::Value::SetColorValue(nscolor aColor)
    3346                 : {
    3347               0 :   FreeValue();
    3348               0 :   mUnit = eUnit_Color;
    3349               0 :   mValue.mColor = aColor;
    3350               0 : }
    3351                 : 
    3352                 : void
    3353               0 : nsStyleAnimation::Value::SetUnparsedStringValue(const nsString& aString)
    3354                 : {
    3355               0 :   FreeValue();
    3356               0 :   mUnit = eUnit_UnparsedString;
    3357               0 :   mValue.mString = nsCSSValue::BufferFromString(aString).get();
    3358               0 :   if (NS_UNLIKELY(!mValue.mString)) {
    3359                 :     // not much we can do here; just make sure that our promise of a
    3360                 :     // non-null mValue.mString holds for string units.
    3361               0 :     mUnit = eUnit_Null;
    3362                 :   }
    3363               0 : }
    3364                 : 
    3365                 : void
    3366               0 : nsStyleAnimation::Value::SetAndAdoptCSSValueValue(nsCSSValue *aValue,
    3367                 :                                                   Unit aUnit)
    3368                 : {
    3369               0 :   FreeValue();
    3370               0 :   NS_ABORT_IF_FALSE(IsCSSValueUnit(aUnit), "bad unit");
    3371               0 :   NS_ABORT_IF_FALSE(aValue != nsnull, "values may not be null");
    3372               0 :   mUnit = aUnit;
    3373               0 :   mValue.mCSSValue = aValue; // take ownership
    3374               0 : }
    3375                 : 
    3376                 : void
    3377               0 : nsStyleAnimation::Value::SetAndAdoptCSSValuePairValue(
    3378                 :                            nsCSSValuePair *aValuePair, Unit aUnit)
    3379                 : {
    3380               0 :   FreeValue();
    3381               0 :   NS_ABORT_IF_FALSE(IsCSSValuePairUnit(aUnit), "bad unit");
    3382               0 :   NS_ABORT_IF_FALSE(aValuePair != nsnull, "value pairs may not be null");
    3383               0 :   mUnit = aUnit;
    3384               0 :   mValue.mCSSValuePair = aValuePair; // take ownership
    3385               0 : }
    3386                 : 
    3387                 : void
    3388               0 : nsStyleAnimation::Value::SetAndAdoptCSSValueTripletValue(
    3389                 :                            nsCSSValueTriplet *aValueTriplet, Unit aUnit)
    3390                 : {
    3391               0 :     FreeValue();
    3392               0 :     NS_ABORT_IF_FALSE(IsCSSValueTripletUnit(aUnit), "bad unit");
    3393               0 :     NS_ABORT_IF_FALSE(aValueTriplet != nsnull, "value pairs may not be null");
    3394               0 :     mUnit = aUnit;
    3395               0 :     mValue.mCSSValueTriplet = aValueTriplet; // take ownership
    3396               0 : }
    3397                 : 
    3398                 : void
    3399               0 : nsStyleAnimation::Value::SetAndAdoptCSSRectValue(nsCSSRect *aRect, Unit aUnit)
    3400                 : {
    3401               0 :   FreeValue();
    3402               0 :   NS_ABORT_IF_FALSE(IsCSSRectUnit(aUnit), "bad unit");
    3403               0 :   NS_ABORT_IF_FALSE(aRect != nsnull, "value pairs may not be null");
    3404               0 :   mUnit = aUnit;
    3405               0 :   mValue.mCSSRect = aRect; // take ownership
    3406               0 : }
    3407                 : 
    3408                 : void
    3409               0 : nsStyleAnimation::Value::SetAndAdoptCSSValueListValue(
    3410                 :                            nsCSSValueList *aValueList, Unit aUnit)
    3411                 : {
    3412               0 :   FreeValue();
    3413               0 :   NS_ABORT_IF_FALSE(IsCSSValueListUnit(aUnit), "bad unit");
    3414               0 :   NS_ABORT_IF_FALSE(aUnit != eUnit_Dasharray || aValueList != nsnull,
    3415                 :                     "dasharrays may not be null");
    3416               0 :   mUnit = aUnit;
    3417               0 :   mValue.mCSSValueList = aValueList; // take ownership
    3418               0 : }
    3419                 : 
    3420                 : void
    3421               0 : nsStyleAnimation::Value::SetAndAdoptCSSValuePairListValue(
    3422                 :                            nsCSSValuePairList *aValuePairList)
    3423                 : {
    3424               0 :   FreeValue();
    3425               0 :   NS_ABORT_IF_FALSE(aValuePairList, "may not be null");
    3426               0 :   mUnit = eUnit_CSSValuePairList;
    3427               0 :   mValue.mCSSValuePairList = aValuePairList; // take ownership
    3428               0 : }
    3429                 : 
    3430                 : void
    3431            5948 : nsStyleAnimation::Value::FreeValue()
    3432                 : {
    3433            5948 :   if (IsCSSValueUnit(mUnit)) {
    3434               0 :     delete mValue.mCSSValue;
    3435            5948 :   } else if (IsCSSValueListUnit(mUnit)) {
    3436               0 :     delete mValue.mCSSValueList;
    3437            5948 :   } else if (IsCSSValuePairUnit(mUnit)) {
    3438               0 :     delete mValue.mCSSValuePair;
    3439            5948 :   } else if (IsCSSValueTripletUnit(mUnit)) {
    3440               0 :     delete mValue.mCSSValueTriplet;
    3441            5948 :   } else if (IsCSSRectUnit(mUnit)) {
    3442               0 :     delete mValue.mCSSRect;
    3443            5948 :   } else if (IsCSSValuePairListUnit(mUnit)) {
    3444               0 :     delete mValue.mCSSValuePairList;
    3445            5948 :   } else if (IsStringUnit(mUnit)) {
    3446               0 :     NS_ABORT_IF_FALSE(mValue.mString, "expecting non-null string");
    3447               0 :     mValue.mString->Release();
    3448                 :   }
    3449            5948 : }
    3450                 : 
    3451                 : bool
    3452               0 : nsStyleAnimation::Value::operator==(const Value& aOther) const
    3453                 : {
    3454               0 :   if (mUnit != aOther.mUnit) {
    3455               0 :     return false;
    3456                 :   }
    3457                 : 
    3458               0 :   switch (mUnit) {
    3459                 :     case eUnit_Null:
    3460                 :     case eUnit_Normal:
    3461                 :     case eUnit_Auto:
    3462                 :     case eUnit_None:
    3463               0 :       return true;
    3464                 :     case eUnit_Enumerated:
    3465                 :     case eUnit_Visibility:
    3466                 :     case eUnit_Integer:
    3467               0 :       return mValue.mInt == aOther.mValue.mInt;
    3468                 :     case eUnit_Coord:
    3469               0 :       return mValue.mCoord == aOther.mValue.mCoord;
    3470                 :     case eUnit_Percent:
    3471                 :     case eUnit_Float:
    3472               0 :       return mValue.mFloat == aOther.mValue.mFloat;
    3473                 :     case eUnit_Color:
    3474               0 :       return mValue.mColor == aOther.mValue.mColor;
    3475                 :     case eUnit_Calc:
    3476               0 :       return *mValue.mCSSValue == *aOther.mValue.mCSSValue;
    3477                 :     case eUnit_CSSValuePair:
    3478               0 :       return *mValue.mCSSValuePair == *aOther.mValue.mCSSValuePair;
    3479                 :     case eUnit_CSSValueTriplet:
    3480               0 :       return *mValue.mCSSValueTriplet == *aOther.mValue.mCSSValueTriplet;
    3481                 :     case eUnit_CSSRect:
    3482               0 :       return *mValue.mCSSRect == *aOther.mValue.mCSSRect;
    3483                 :     case eUnit_Dasharray:
    3484                 :     case eUnit_Shadow:
    3485                 :     case eUnit_Transform:
    3486                 :     case eUnit_BackgroundPosition:
    3487               0 :       return *mValue.mCSSValueList == *aOther.mValue.mCSSValueList;
    3488                 :     case eUnit_CSSValuePairList:
    3489               0 :       return *mValue.mCSSValuePairList == *aOther.mValue.mCSSValuePairList;
    3490                 :     case eUnit_UnparsedString:
    3491                 :       return (NS_strcmp(GetStringBufferValue(),
    3492               0 :                         aOther.GetStringBufferValue()) == 0);
    3493                 :   }
    3494                 : 
    3495               0 :   NS_NOTREACHED("incomplete case");
    3496               0 :   return false;
    3497                 : }
    3498                 : 

Generated by: LCOV version 1.7