Bug 828531; fix scaling CSS pixels for animations; r=roc
authorNicholas Cameron <ncameron@mozilla.com>
Wed, 13 Feb 2013 10:00:54 +1300
changeset 131548 300ea51c6353c180a71d8454f94249abd3abd61a
parent 131547 b061b91098b29338d6bd0eb624907224949640fa
child 131549 d47438ef23c1744a3447a903a81a40572d0460af
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs828531
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 828531; fix scaling CSS pixels for animations; r=roc
gfx/layers/Layers.h
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/PLayers.ipdl
layout/base/nsDisplayList.cpp
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -856,16 +856,18 @@ public:
   const gfx3DMatrix GetTransform();
   const gfx3DMatrix& GetBaseTransform() { return mTransform; }
   float GetPostXScale() { return mPostXScale; }
   float GetPostYScale() { return mPostYScale; }
   bool GetIsFixedPosition() { return mIsFixedPosition; }
   gfxPoint GetFixedPositionAnchor() { return mAnchor; }
   Layer* GetMaskLayer() { return mMaskLayer; }
 
+  // Note that all lengths in animation data are either in CSS pixels or app
+  // units and must be converted to device pixels by the compositor.
   AnimationArray& GetAnimations() { return mAnimations; }
   InfallibleTArray<AnimData>& GetAnimationData() { return mAnimationData; }
 
   uint64_t GetAnimationGeneration() { return mAnimationGeneration; }
   void SetAnimationGeneration(uint64_t aCount) { mAnimationGeneration = aCount; }
 
   /**
    * DRAWING PHASE ONLY
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -713,31 +713,40 @@ SampleValue(float aPortion, Animation& a
     *aValue = interpolatedValue.GetFloatValue();
     return;
   }
 
   nsCSSValueList* interpolatedList = interpolatedValue.GetCSSValueListValue();
 
   TransformData& data = aAnimation.data().get_TransformData();
   nsPoint origin = data.origin();
-  int32_t auPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
+  // 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,
-                                                     data.mozOrigin(),
-                                                     data.perspectiveOrigin(),
+                                                     mozOrigin,
+                                                     perspectiveOrigin,
                                                      data.perspective());
   gfx3DMatrix transform =
-    nsDisplayTransform::GetResultingTransformMatrix(props, data.origin(),
-                                                    nsDeviceContext::AppUnitsPerCSSPixel(),
+    nsDisplayTransform::GetResultingTransformMatrix(props, origin,
+                                                    data.appUnitsPerDevPixel(),
                                                     &data.bounds());
-  // NB: See nsDisplayTransform::GetTransform().
-  gfxPoint3D newOrigin =
-    gfxPoint3D(NS_round(NSAppUnitsToFloatPixels(origin.x, auPerCSSPixel)),
-               NS_round(NSAppUnitsToFloatPixels(origin.y, auPerCSSPixel)),
+  gfxPoint3D scaledOrigin =
+    gfxPoint3D(NS_round(NSAppUnitsToFloatPixels(origin.x, data.appUnitsPerDevPixel())),
+               NS_round(NSAppUnitsToFloatPixels(origin.y, data.appUnitsPerDevPixel())),
                0.0f);
-  transform.Translate(newOrigin);
+
+  transform.Translate(scaledOrigin);
 
   InfallibleTArray<TransformFunction> functions;
   functions.AppendElement(TransformMatrix(transform));
   *aValue = functions;
 }
 
 static bool
 SampleAnimations(Layer* aLayer, TimeStamp aPoint)
--- a/gfx/layers/ipc/PLayers.ipdl
+++ b/gfx/layers/ipc/PLayers.ipdl
@@ -134,21 +134,25 @@ struct AnimationSegment {
   float startPortion;
   float endPortion;
   TimingFunction sampleFn;
 };
 
 // Transforms need extra information to correctly convert the list of transform
 // functions to a gfx3DMatrix that can be applied directly to the layer.
 struct TransformData {
+  // the origin of the frame being transformed in app units
   nsPoint origin;
+  // the -moz-transform-origin property for the transform in css pixels
   gfxPoint3D mozOrigin;
+  // the -moz-perspective-origin property for the transform in css pixels
   gfxPoint3D perspectiveOrigin;
   nsRect bounds;
   nscoord perspective;
+  int32_t appUnitsPerDevPixel;
 };
 
 union AnimationData {
   null_t;
   TransformData;
 };
 
 struct Animation {
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -295,17 +295,18 @@ static void
 AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
                          ElementAnimation* ea, Layer* aLayer,
                          AnimationData& aData)
 {
   NS_ASSERTION(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
   nsStyleContext* styleContext = aFrame->GetStyleContext();
   nsPresContext* presContext = aFrame->PresContext();
   nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
-  float scale = presContext->AppUnitsPerDevPixel();
+  // all data passed directly to the compositor should be in css pixels
+  float scale = nsDeviceContext::AppUnitsPerCSSPixel();
 
   TimeStamp startTime = ea->mStartTime + ea->mDelay;
   TimeDuration duration = ea->mIterationDuration;
   float iterations = ea->mIterationCount != NS_IEEEPositiveInfinity()
                      ? ea->mIterationCount : -1;
   int direction = ea->mDirection;
 
   Animation* animation = aLayer->AddAnimation(startTime, duration,
@@ -374,33 +375,35 @@ AddAnimationsAndTransitionsToLayer(Layer
     return;
   }
 
   mozilla::TimeStamp currentTime =
     frame->PresContext()->RefreshDriver()->MostRecentRefresh();
   AnimationData data;
   if (aProperty == eCSSProperty_transform) {
     nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(frame);
+    // all data passed directly to the compositor should be in css pixels
     float scale = nsDeviceContext::AppUnitsPerCSSPixel();
     gfxPoint3D offsetToTransformOrigin =
       nsDisplayTransform::GetDeltaToMozTransformOrigin(frame, scale, &bounds);
     gfxPoint3D offsetToPerspectiveOrigin =
       nsDisplayTransform::GetDeltaToMozPerspectiveOrigin(frame, scale);
     nscoord perspective = 0.0;
     nsStyleContext* parentStyleContext = frame->GetStyleContext()->GetParent();
     if (parentStyleContext) {
       const nsStyleDisplay* disp = parentStyleContext->GetStyleDisplay();
       if (disp && disp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
         perspective = disp->mChildPerspective.GetCoordValue();
       }
     }
     nsPoint origin = aItem->ToReferenceFrame();
 
     data = TransformData(origin, offsetToTransformOrigin,
-                         offsetToPerspectiveOrigin, bounds, perspective);
+                         offsetToPerspectiveOrigin, bounds, perspective,
+                         frame->PresContext()->AppUnitsPerDevPixel());
   } else if (aProperty == eCSSProperty_opacity) {
     data = null_t();
   }
 
   if (et) {
     for (uint32_t tranIdx = 0; tranIdx < et->mPropertyTransitions.Length(); tranIdx++) {
       ElementPropertyTransition* pt = &et->mPropertyTransitions[tranIdx];
       if (pt->mProperty != aProperty || !pt->IsRunningAt(currentTime)) {