static void
SampleValue(float aPortion, Animation& aAnimation, nsStyleAnimation::Value& aStart,
            nsStyleAnimation::Value& aEnd, Animatable* aValue)
{
  nsStyleAnimation::Value interpolatedValue;
  NS_ASSERTION(aStart.GetUnit() == aEnd.GetUnit() ||
               aStart.GetUnit() == nsStyleAnimation::eUnit_None ||
               aEnd.GetUnit() == nsStyleAnimation::eUnit_None, "Must have same unit");
  nsStyleAnimation::Interpolate(aAnimation.property(), aStart, aEnd,
                                aPortion, interpolatedValue);
  if (aAnimation.property() == eCSSProperty_opacity) {
    *aValue = interpolatedValue.GetFloatValue();
    return;
  }

  nsCSSValueList* interpolatedList = interpolatedValue.GetCSSValueListValue();

  TransformData& data = aAnimation.data().get_TransformData();
  nsPoint origin = data.origin();
  // we expect all our transform data to arrive in css pixels, so here we must
  // adjust to dev pixels.
  double cssPerDev = double(nsDeviceContext::AppUnitsPerCSSPixel())
                     / double(data.appUnitsPerDevPixel());
  gfxPoint3D mozOrigin = data.mozOrigin();
  mozOrigin.x = mozOrigin.x * cssPerDev;
  mozOrigin.y = mozOrigin.y * cssPerDev;
  gfxPoint3D perspectiveOrigin = data.perspectiveOrigin();
  perspectiveOrigin.x = perspectiveOrigin.x * cssPerDev;
  perspectiveOrigin.y = perspectiveOrigin.y * cssPerDev;
  nsDisplayTransform::FrameTransformProperties props(interpolatedList,
                                                     mozOrigin,
                                                     perspectiveOrigin,
                                                     data.perspective());
  gfx3DMatrix transform =
    nsDisplayTransform::GetResultingTransformMatrix(props, origin,
                                                    data.appUnitsPerDevPixel(),
                                                    &data.bounds());
  gfxPoint3D scaledOrigin =
    gfxPoint3D(NS_round(NSAppUnitsToFloatPixels(origin.x, data.appUnitsPerDevPixel())),
               NS_round(NSAppUnitsToFloatPixels(origin.y, data.appUnitsPerDevPixel())),
               0.0f);

  transform.Translate(scaledOrigin);

  InfallibleTArray<TransformFunction> functions;
  functions.AppendElement(TransformMatrix(transform));
  *aValue = functions;
}
// Helper function to parse a string into a nsStyleAnimation::Value
static bool
ValueFromStringHelper(nsCSSProperty aPropID,
                      Element* aTargetElement,
                      nsPresContext* aPresContext,
                      const nsAString& aString,
                      nsStyleAnimation::Value& aStyleAnimValue,
                      bool* aIsContextSensitive)
{
  // If value is negative, we'll strip off the "-" so the CSS parser won't
  // barf, and then manually make the parsed value negative.
  // (This is a partial solution to let us accept some otherwise out-of-bounds
  // CSS values. Bug 501188 will provide a more complete fix.)
  bool isNegative = false;
  PRUint32 subStringBegin = 0;

  // NOTE: We need to opt-out 'stroke-dasharray' from the negative-number
  // check.  Its values might look negative (e.g. by starting with "-1"), but
  // they're more complicated than our simple negation logic here can handle.
  if (aPropID != eCSSProperty_stroke_dasharray) {
    PRInt32 absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
    if (absValuePos > 0) {
      isNegative = true;
      subStringBegin = (PRUint32)absValuePos; // Start parsing after '-' sign
    }
  }
  nsDependentSubstring subString(aString, subStringBegin);
  if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString,
                                      true, aStyleAnimValue,
                                      aIsContextSensitive)) {
    return false;
  }
  if (isNegative) {
    InvertSign(aStyleAnimValue);
  }
  
  if (aPropID == eCSSProperty_font_size) {
    // Divide out text-zoom, since SVG is supposed to ignore it
    NS_ABORT_IF_FALSE(aStyleAnimValue.GetUnit() ==
                        nsStyleAnimation::eUnit_Coord,
                      "'font-size' value with unexpected style unit");
    aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() /
                                  aPresContext->TextZoom());
  }
  return true;
}
// Helper function to parse a string into a nsStyleAnimation::Value
static PRBool
ValueFromStringHelper(nsCSSProperty aPropID,
                      nsIContent* aTargetElement,
                      nsPresContext* aPresContext,
                      const nsAString& aString,
                      nsStyleAnimation::Value& aStyleAnimValue)
{
  // If value is negative, we'll strip off the "-" so the CSS parser won't
  // barf, and then manually make the parsed value negative.
  // (This is a partial solution to let us accept some otherwise out-of-bounds
  // CSS values. Bug 501188 will provide a more complete fix.)
  PRBool isNegative = PR_FALSE;
  PRUint32 subStringBegin = 0;
  PRInt32 absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
  if (absValuePos > 0) {
    isNegative = PR_TRUE;
    subStringBegin = (PRUint32)absValuePos; // Start parsing after '-' sign
  }
  nsDependentSubstring subString(aString, subStringBegin);
  if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString,
                                      PR_TRUE, aStyleAnimValue)) {
    return PR_FALSE;
  }
  if (isNegative) {
    InvertSign(aStyleAnimValue);
  }
  
  if (aPropID == eCSSProperty_font_size) {
    // Divide out text-zoom, since SVG is supposed to ignore it
    NS_ABORT_IF_FALSE(aStyleAnimValue.GetUnit() ==
                        nsStyleAnimation::eUnit_Coord,
                      "'font-size' value with unexpected style unit");
    aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() /
                                  aPresContext->TextZoom());
  }
  return PR_TRUE;
}
static void
InvertSign(nsStyleAnimation::Value& aValue)
{
  switch (aValue.GetUnit()) {
    case nsStyleAnimation::eUnit_Coord:
      aValue.SetCoordValue(-aValue.GetCoordValue());
      break;
    case nsStyleAnimation::eUnit_Percent:
      aValue.SetPercentValue(-aValue.GetPercentValue());
      break;
    case nsStyleAnimation::eUnit_Float:
      aValue.SetFloatValue(-aValue.GetFloatValue());
      break;
    default:
      NS_NOTREACHED("Calling InvertSign with an unsupported unit");
      break;
  }
}