Bug 276431 Patch 3b: Make nsImageFrame compute its transform on-demand. r=roc a=blocking
authorDaniel Holbert <dholbert@cs.stanford.edu>
Wed, 08 Sep 2010 13:40:38 -0700
changeset 52206 53aad62ff820185e724cc5002a74f971187fda04
parent 52205 f3874d6012b62649fb573e199baff43193511302
child 52207 996dd51c979ae84d6ec81f906828ca3b60aab0d2
push id15573
push userdholbert@mozilla.com
push dateWed, 08 Sep 2010 20:57:52 +0000
treeherdermozilla-central@ec53c1b41f3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, blocking
bugs276431
milestone2.0b6pre
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 276431 Patch 3b: Make nsImageFrame compute its transform on-demand. r=roc a=blocking
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -50,16 +50,17 @@
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsINodeInfo.h"
 #include "nsContentUtils.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsStyleContext.h"
 #include "nsStyleConsts.h"
 #include "nsStyleCoord.h"
+#include "nsTransform2D.h"
 #include "nsImageMap.h"
 #include "nsILinkHandler.h"
 #include "nsIURL.h"
 #include "nsIIOService.h"
 #include "nsIURL.h"
 #include "nsILoadGroup.h"
 #include "nsISupportsPriority.h"
 #include "nsIServiceManager.h"
@@ -320,46 +321,43 @@ nsImageFrame::UpdateIntrinsicRatio(imgIC
                       "dimensions must have coord units (not percent units)");
     mIntrinsicRatio.width = mIntrinsicSize.width.GetCoordValue();
     mIntrinsicRatio.height = mIntrinsicSize.height.GetCoordValue();
   }
 
   return mIntrinsicRatio != oldIntrinsicRatio;
 }
 
-void
-nsImageFrame::RecalculateTransform(PRBool aInnerAreaChanged)
+PRBool
+nsImageFrame::GetSourceToDestTransform(nsTransform2D& aTransform)
 {
-  // In any case, we need to translate this over appropriately.  Set
-  // translation _before_ setting scaling so that it does not get
-  // scaled!
-
+  // Set the translation components.
   // XXXbz does this introduce rounding errors because of the cast to
   // float?  Should we just manually add that stuff in every time
   // instead?
-  if (aInnerAreaChanged) {
-    nsRect innerArea = GetInnerArea();
-    mTransform.SetToTranslate(float(innerArea.x),
-                              float(innerArea.y - GetContinuationOffset()));
-  }
-  
-  // Set the scale factors
+  nsRect innerArea = GetInnerArea();
+  aTransform.SetToTranslate(float(innerArea.x),
+                            float(innerArea.y - GetContinuationOffset()));
+
+  // Set the scale factors.
   if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
       mIntrinsicSize.width.GetCoordValue() != 0 &&
       mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord &&
       mIntrinsicSize.height.GetCoordValue() != 0 &&
       mIntrinsicSize.width.GetCoordValue() != mComputedSize.width &&
       mIntrinsicSize.height.GetCoordValue() != mComputedSize.height) {
-    mTransform.SetScale(float(mComputedSize.width)  /
+
+    aTransform.SetScale(float(mComputedSize.width)  /
                         float(mIntrinsicSize.width.GetCoordValue()),
                         float(mComputedSize.height) /
                         float(mIntrinsicSize.height.GetCoordValue()));
-  } else {
-    mTransform.SetScale(1.0f, 1.0f);
+    return PR_TRUE;
   }
+
+  return PR_FALSE;
 }
 
 /*
  * These two functions basically do the same check.  The first one
  * checks that the given request is the current request for our
  * mContent.  The second checks that the given image container the
  * same as the image container on the current request for our
  * mContent.
@@ -413,20 +411,28 @@ nsImageFrame::SourceRectToDest(const nsI
   // floating-point scaling factor.  The same holds true for columns.
   // So, we start by computing that bound without the floor and ceiling.
 
   nsRect r(nsPresContext::CSSPixelsToAppUnits(aRect.x - 1),
            nsPresContext::CSSPixelsToAppUnits(aRect.y - 1),
            nsPresContext::CSSPixelsToAppUnits(aRect.width + 2),
            nsPresContext::CSSPixelsToAppUnits(aRect.height + 2));
 
-  mTransform.TransformCoord(&r.x, &r.y, &r.width, &r.height);
+  nsTransform2D sourceToDest;
+  if (!GetSourceToDestTransform(sourceToDest)) {
+    // Failed to generate transform matrix. Return our whole inner area,
+    // to be on the safe side (since this method is used for generating
+    // invalidation rects).
+    return GetInnerArea();
+  }
+
+  sourceToDest.TransformCoord(&r.x, &r.y, &r.width, &r.height);
 
   // Now, round the edges out to the pixel boundary.
-  int scale = nsPresContext::CSSPixelsToAppUnits(1);
+  nscoord scale = nsPresContext::CSSPixelsToAppUnits(1);
   nscoord right = r.x + r.width;
   nscoord bottom = r.y + r.height;
 
   r.x -= (scale + (r.x % scale)) % scale;
   r.y -= (scale + (r.y % scale)) % scale;
   r.width = right + ((scale - (right % scale)) % scale) - r.x;
   r.height = bottom + ((scale - (bottom % scale)) % scale) - r.y;
 
@@ -523,24 +529,16 @@ nsImageFrame::OnStartContainer(imgIReque
     // We don't care
     return NS_OK;
   }
   
   UpdateIntrinsicSize(aImage);
   UpdateIntrinsicRatio(aImage);
 
   if (mState & IMAGE_GOTINITIALREFLOW) {
-    // If we previously set the intrinsic size (in EnsureIntrinsicSizeAndRatio)
-    // to the size of the loading-image icon and reflowed the frame,
-    // we'll have an mTransform computed from that intrinsic size.  But
-    // if we still have that transform when we get OnDataAvailable
-    // calls, we'll invalidate the wrong area.  So update the transform
-    // now.
-    RecalculateTransform(PR_FALSE);
-
     // Now we need to reflow if we have an unconstrained size and have
     // already gotten the initial reflow
     if (!(mState & IMAGE_SIZECONSTRAINED)) { 
       nsIPresShell *presShell = presContext->GetPresShell();
       NS_ASSERTION(presShell, "No PresShell.");
       if (presShell) { 
         presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
                                     NS_FRAME_IS_DIRTY);
@@ -805,17 +803,16 @@ nsImageFrame::Reflow(nsPresContext*     
   // XXXldb These two bits are almost exact opposites (except in the
   // middle of the initial reflow); remove IMAGE_GOTINITIALREFLOW.
   if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
     mState |= IMAGE_GOTINITIALREFLOW;
   }
 
   mComputedSize = 
     nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight());
-  RecalculateTransform(PR_TRUE);
 
   aMetrics.width = mComputedSize.width;
   aMetrics.height = mComputedSize.height;
 
   // add borders and padding
   aMetrics.width  += aReflowState.mComputedBorderPadding.LeftRight();
   aMetrics.height += aReflowState.mComputedBorderPadding.TopBottom();
   
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -43,32 +43,31 @@
 
 #include "nsSplittableFrame.h"
 #include "nsString.h"
 #include "nsAString.h"
 #include "nsIImageFrame.h"
 #include "nsIIOService.h"
 #include "nsIObserver.h"
 
-#include "nsTransform2D.h"
 #include "imgIRequest.h"
 #include "nsStubImageDecoderObserver.h"
 #include "imgIDecoderObserver.h"
 
 class nsIFrame;
 class nsImageMap;
 class nsIURI;
 class nsILoadGroup;
 struct nsHTMLReflowState;
 struct nsHTMLReflowMetrics;
 struct nsSize;
 class nsDisplayImage;
 class nsPresContext;
-
 class nsImageFrame;
+class nsTransform2D;
 
 class nsImageListener : public nsStubImageDecoderObserver
 {
 public:
   nsImageListener(nsImageFrame *aFrame);
   virtual ~nsImageListener();
 
   NS_DECL_ISUPPORTS
@@ -252,19 +251,25 @@ private:
    * Recalculate mIntrinsicRatio from the image.
    *
    * @return whether aImage's ratio did _not_
    *         match our previous intrinsic ratio.
    */
   PRBool UpdateIntrinsicRatio(imgIContainer* aImage);
 
   /**
-   * This function will recalculate mTransform.
+   * This function calculates the transform for converting between
+   * source space & destination space. May fail if our image has a
+   * percent-valued or zero-valued height or width.
+   *
+   * @param aTransform The transform object to populate.
+   *
+   * @return whether we succeeded in creating the transform.
    */
-  void RecalculateTransform(PRBool aInnerAreaChanged);
+  PRBool GetSourceToDestTransform(nsTransform2D& aTransform);
 
   /**
    * Helper functions to check whether the request or image container
    * corresponds to a load we don't care about.  Most of the decoder
    * observer methods will bail early if these return true.
    */
   PRBool IsPendingLoad(imgIRequest* aRequest) const;
   PRBool IsPendingLoad(imgIContainer* aContainer) const;
@@ -278,17 +283,16 @@ private:
   nsImageMap*         mImageMap;
 
   nsCOMPtr<imgIDecoderObserver> mListener;
 
   nsSize mComputedSize;
   nsIFrame::IntrinsicSize mIntrinsicSize;
   nsSize mIntrinsicRatio;
 
-  nsTransform2D mTransform;
   PRBool mDisplayingIcon;
 
   static nsIIOService* sIOService;
 
   /* loading / broken image icon support */
 
   // XXXbz this should be handled by the prescontext, I think; that
   // way we would have a single iconload per mozilla session instead