Bug 1416540 - Convert a bunch of scaling code to avoid unnecessary double conversion. r?mattwoodrow draft
authorKartikaya Gupta <kgupta@mozilla.com>
Sun, 12 Nov 2017 18:37:33 -0500
changeset 696907 1bc7d3dc967d8b4217caf641ed87f75678ada857
parent 696906 8fe17cd35f04a1386ce047f6a45393e660947e6d
child 696908 0845666302cbf8c4eac3ff2a6987bcb7438364a6
push id88821
push userkgupta@mozilla.com
push dateSun, 12 Nov 2017 23:37:55 +0000
reviewersmattwoodrow
bugs1416540
milestone58.0a1
Bug 1416540 - Convert a bunch of scaling code to avoid unnecessary double conversion. r?mattwoodrow The code in ComputeSuitableScaleForAnimation feeds its double-based computation results into GetSuitableScale, which takes and returns floats. Also the double-based computation that it's doing involves calling UpdateMinMaxScale a bunch which explicitly uses the float variant of std::min and std::max. And all of this is used from ChooseScaleAndSetTransform which does other things like call a "RoundToFloatPrecision" function, and casts the final values to floats before setting the layer's prescale. So let's just use floats all the way through. MozReview-Commit-ID: BE3WC5hv89d
gfx/thebes/gfxUtils.cpp
gfx/thebes/gfxUtils.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/painting/FrameLayerBuilder.cpp
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -647,54 +647,54 @@ gfxUtils::ClipToRegion(DrawTarget* aTarg
     for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
       AppendRectToPath(pathBuilder, Rect(iter.Get()));
     }
     RefPtr<Path> path = pathBuilder->Finish();
     aTarget->PushClip(path);
   }
 }
 
-/*static*/ gfxFloat
-gfxUtils::ClampToScaleFactor(gfxFloat aVal, bool aRoundDown)
+/*static*/ float
+gfxUtils::ClampToScaleFactor(float aVal, bool aRoundDown)
 {
   // Arbitary scale factor limitation. We can increase this
   // for better scaling performance at the cost of worse
   // quality.
-  static const gfxFloat kScaleResolution = 2;
+  static const float kScaleResolution = 2;
 
   // Negative scaling is just a flip and irrelevant to
   // our resolution calculation.
   if (aVal < 0.0) {
     aVal = -aVal;
   }
 
   bool inverse = false;
   if (aVal < 1.0) {
     inverse = true;
     aVal = 1 / aVal;
   }
 
-  gfxFloat power = log(aVal)/log(kScaleResolution);
+  float power = logf(aVal)/logf(kScaleResolution);
 
   // If power is within 1e-5 of an integer, round to nearest to
   // prevent floating point errors, otherwise round up to the
   // next integer value.
   if (fabs(power - NS_round(power)) < 1e-5) {
     power = NS_round(power);
   // Use floor when we are either inverted or rounding down, but
   // not both.
   } else if (inverse != aRoundDown) {
     power = floor(power);
   // Otherwise, ceil when we are not inverted and not rounding
   // down, or we are inverted and rounding down.
   } else {
     power = ceil(power);
   }
 
-  gfxFloat scale = pow(kScaleResolution, power);
+  float scale = powf(kScaleResolution, power);
 
   if (inverse) {
     scale = 1 / scale;
   }
 
   return scale;
 }
 
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -144,17 +144,17 @@ public:
     static gfxQuad TransformToQuad(const gfxRect& aRect,
                                    const mozilla::gfx::Matrix4x4& aMatrix);
 
     /**
      * Return the smallest power of kScaleResolution (2) greater than or equal to
      * aVal. If aRoundDown is specified, the power of 2 will rather be less than
      * or equal to aVal.
      */
-    static gfxFloat ClampToScaleFactor(gfxFloat aVal, bool aRoundDown = false);
+    static float ClampToScaleFactor(float aVal, bool aRoundDown = false);
 
     /**
      * Clears surface to aColor (which defaults to transparent black).
      */
     static void ClearThebesSurface(gfxASurface* aSurface);
 
     static const float* YuvToRgbMatrix4x3RowMajor(mozilla::YUVColorSpace aYUVColorSpace);
     static const float* YuvToRgbMatrix3x3ColumnMajor(mozilla::YUVColorSpace aYUVColorSpace);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -538,32 +538,31 @@ GetSuitableScale(float aMaxScale, float 
     return aMaxScale;
   }
   return std::max(std::min(aMaxScale, displayVisibleRatio), aMinScale);
 }
 
 static inline void
 UpdateMinMaxScale(const nsIFrame* aFrame,
                   const AnimationValue& aValue,
-                  gfxSize& aMinScale,
-                  gfxSize& aMaxScale)
+                  Size& aMinScale,
+                  Size& aMaxScale)
 {
   gfxSize size = aValue.GetScaleValue(aFrame);
   aMaxScale.width = std::max<float>(aMaxScale.width, size.width);
   aMaxScale.height = std::max<float>(aMaxScale.height, size.height);
   aMinScale.width = std::min<float>(aMinScale.width, size.width);
   aMinScale.height = std::min<float>(aMinScale.height, size.height);
 }
 
 static void
 GetMinAndMaxScaleForAnimationProperty(const nsIFrame* aFrame,
-                                      nsTArray<RefPtr<dom::Animation>>&
-                                        aAnimations,
-                                      gfxSize& aMaxScale,
-                                      gfxSize& aMinScale)
+                                      nsTArray<RefPtr<dom::Animation>>& aAnimations,
+                                      Size& aMaxScale,
+                                      Size& aMinScale)
 {
   for (dom::Animation* anim : aAnimations) {
     // This method is only expected to be passed animations that are running on
     // the compositor and we only pass playing animations to the compositor,
     // which are, by definition, "relevant" animations (animations that are
     // not yet finished or which are filling forwards).
     MOZ_ASSERT(anim->IsRelevant());
 
@@ -592,41 +591,41 @@ GetMinAndMaxScaleForAnimationProperty(co
         if (segment.HasReplaceableToValue()) {
           UpdateMinMaxScale(aFrame, segment.mToValue, aMinScale, aMaxScale);
         }
       }
     }
   }
 }
 
-gfxSize
+Size
 nsLayoutUtils::ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
                                                 const nsSize& aVisibleSize,
                                                 const nsSize& aDisplaySize)
 {
-  gfxSize maxScale(std::numeric_limits<gfxFloat>::min(),
-                   std::numeric_limits<gfxFloat>::min());
-  gfxSize minScale(std::numeric_limits<gfxFloat>::max(),
-                   std::numeric_limits<gfxFloat>::max());
+  Size maxScale(std::numeric_limits<float>::min(),
+                std::numeric_limits<float>::min());
+  Size minScale(std::numeric_limits<float>::max(),
+                std::numeric_limits<float>::max());
 
   nsTArray<RefPtr<dom::Animation>> compositorAnimations =
     EffectCompositor::GetAnimationsForCompositor(aFrame,
                                                  eCSSProperty_transform);
   GetMinAndMaxScaleForAnimationProperty(aFrame, compositorAnimations,
                                         maxScale, minScale);
 
-  if (maxScale.width == std::numeric_limits<gfxFloat>::min()) {
+  if (maxScale.width == std::numeric_limits<float>::min()) {
     // We didn't encounter a transform
-    return gfxSize(1.0, 1.0);
-  }
-
-  return gfxSize(GetSuitableScale(maxScale.width, minScale.width,
-                                  aVisibleSize.width, aDisplaySize.width),
-                 GetSuitableScale(maxScale.height, minScale.height,
-                                  aVisibleSize.height, aDisplaySize.height));
+    return Size(1.0, 1.0);
+  }
+
+  return Size(GetSuitableScale(maxScale.width, minScale.width,
+                               aVisibleSize.width, aDisplaySize.width),
+              GetSuitableScale(maxScale.height, minScale.height,
+                               aVisibleSize.height, aDisplaySize.height));
 }
 
 bool
 nsLayoutUtils::AreAsyncAnimationsEnabled()
 {
   static bool sAreAsyncAnimationsEnabled;
   static bool sAsyncPrefCached = false;
 
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -145,16 +145,17 @@ class nsLayoutUtils
   typedef mozilla::gfx::Color Color;
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::ExtendMode ExtendMode;
   typedef mozilla::gfx::SamplingFilter SamplingFilter;
   typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::Point Point;
   typedef mozilla::gfx::Rect Rect;
   typedef mozilla::gfx::RectDouble RectDouble;
+  typedef mozilla::gfx::Size Size;
   typedef mozilla::gfx::Matrix4x4 Matrix4x4;
   typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
   typedef mozilla::gfx::StrokeOptions StrokeOptions;
   typedef mozilla::image::DrawResult DrawResult;
 
 public:
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ScrollMetadata ScrollMetadata;
@@ -2333,19 +2334,19 @@ public:
    * element that run on the compositor thread.
    * It will check the maximum and minimum scale during the animations and
    * transitions and return a suitable value for performance and quality.
    * Will return scale(1,1) if there are no such animations.
    * Always returns a positive value.
    * @param aVisibleSize is the size of the area we want to paint
    * @param aDisplaySize is the size of the display area of the pres context
    */
-  static gfxSize ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
-                                                  const nsSize& aVisibleSize,
-                                                  const nsSize& aDisplaySize);
+  static Size ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
+                                               const nsSize& aVisibleSize,
+                                               const nsSize& aDisplaySize);
 
   /**
    * Checks whether we want to use the GPU to scale images when
    * possible.
    */
   static bool GPUImageScalingEnabled();
 
   /**
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -5338,22 +5338,17 @@ ContainerState::Finish(uint32_t* aTextCo
     Layer *layerToRemove = layer;
     layer = layer->GetNextSibling();
     mContainerLayer->RemoveChild(layerToRemove);
   }
 
   *aTextContentFlags = textContentFlags;
 }
 
-static inline gfxSize RoundToFloatPrecision(const gfxSize& aSize)
-{
-  return gfxSize(float(aSize.width), float(aSize.height));
-}
-
-static void RestrictScaleToMaxLayerSize(gfxSize& aScale,
+static void RestrictScaleToMaxLayerSize(Size& aScale,
                                         const nsRect& aVisibleRect,
                                         nsIFrame* aContainerFrame,
                                         Layer* aContainerLayer)
 {
   if (!aContainerLayer->Manager()->IsWidgetLayerManager()) {
     return;
   }
 
@@ -5439,17 +5434,17 @@ ChooseScaleAndSetTransform(FrameLayerBui
                           offset.y + aIncomingScale.mOffset.y,
                           0);
 
   if (transform.IsSingular()) {
     return false;
   }
 
   bool canDraw2D = transform.CanDraw2D(&transform2d);
-  gfxSize scale;
+  Size scale;
   // XXX Should we do something for 3D transforms?
   if (canDraw2D &&
       !aContainerFrame->Combines3DTransformWithAncestors() &&
       !aContainerFrame->HasPerspective()) {
     // If the container's transform is animated off main thread, fix a suitable scale size
     // for animation
     if (aContainerItem &&
         aContainerItem->GetType() == DisplayItemType::TYPE_TRANSFORM &&
@@ -5463,17 +5458,17 @@ ChooseScaleAndSetTransform(FrameLayerBui
                 displaySize);
       // multiply by the scale inherited from ancestors--we use a uniform
       // scale factor to prevent blurring when the layer is rotated.
       float incomingScale = std::max(aIncomingScale.mXScale, aIncomingScale.mYScale);
       scale.width *= incomingScale;
       scale.height *= incomingScale;
     } else {
       // Scale factors are normalized to a power of 2 to reduce the number of resolution changes
-      scale = RoundToFloatPrecision(ThebesMatrix(transform2d).ScaleFactors(true));
+      scale = transform2d.ScaleFactors(true);
       // For frames with a changing scale transform round scale factors up to
       // nearest power-of-2 boundary so that we don't keep having to redraw
       // the content as it scales up and down. Rounding up to nearest
       // power-of-2 boundary ensures we never scale up, only down --- avoiding
       // jaggies. It also ensures we never scale down by more than a factor of 2,
       // avoiding bad downscaling quality.
       Matrix frameTransform;
       if (ActiveLayerTracker::IsScaleSubjectToAnimation(aContainerFrame)) {
@@ -5494,34 +5489,34 @@ ChooseScaleAndSetTransform(FrameLayerBui
         }
       } else {
         // XXX Do we need to move nearly-integer values to integers here?
       }
     }
     // If the scale factors are too small, just use 1.0. The content is being
     // scaled out of sight anyway.
     if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) {
-      scale = gfxSize(1.0, 1.0);
+      scale = Size(1.0, 1.0);
     }
     // If this is a transform container layer, then pre-rendering might
     // mean we try render a layer bigger than the max texture size. If we have
     // tiling, that's not a problem, since we'll automatically choose a tiled
     // layer for layers of that size. If not, we need to apply clamping to
     // prevent this.
     if (aTransform && !gfxPrefs::LayersTilesEnabled()) {
       RestrictScaleToMaxLayerSize(scale, aVisibleRect, aContainerFrame, aLayer);
     }
   } else {
-    scale = gfxSize(1.0, 1.0);
+    scale = Size(1.0, 1.0);
   }
 
   // Store the inverse of our resolution-scale on the layer
   aLayer->SetBaseTransform(transform);
-  aLayer->SetPreScale(1.0f/float(scale.width),
-                      1.0f/float(scale.height));
+  aLayer->SetPreScale(1.0f/scale.width,
+                      1.0f/scale.height);
   aLayer->SetInheritedScale(aIncomingScale.mXScale,
                             aIncomingScale.mYScale);
 
   aOutgoingScale =
     ContainerLayerParameters(scale.width, scale.height, -offset, aIncomingScale);
   if (aTransform) {
     aOutgoingScale.mInTransformedSubtree = true;
     if (ActiveLayerTracker::IsStyleAnimated(aDisplayListBuilder, aContainerFrame,