Bug 1130328 - Part 2: Update nsImageFrame to always use InvalidateLayer when handling FRAME_UPDATE. r=tn, a=sledru
authorSeth Fowler <seth@mozilla.com>
Wed, 11 Feb 2015 01:11:43 -0800
changeset 243766 95d83f3422fc
parent 243765 eb77152f1233
child 243767 57f79302248f
push id4468
push userryanvm@gmail.com
push date2015-02-12 16:23 +0000
treeherdermozilla-beta@57f79302248f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, sledru
bugs1130328
milestone36.0
Bug 1130328 - Part 2: Update nsImageFrame to always use InvalidateLayer when handling FRAME_UPDATE. r=tn, a=sledru
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -379,63 +379,31 @@ nsImageFrame::GetSourceToDestTransform(n
                         float(destRect.height) /
                         float(mIntrinsicSize.height.GetCoordValue()));
     return true;
   }
 
   return 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.
- */
+// This function checks whether the given request is the current request for our
+// mContent.
 bool
 nsImageFrame::IsPendingLoad(imgIRequest* aRequest) const
 {
   // Default to pending load in case of errors
   nsCOMPtr<nsIImageLoadingContent> imageLoader(do_QueryInterface(mContent));
   NS_ASSERTION(imageLoader, "No image loading content?");
 
   int32_t requestType = nsIImageLoadingContent::UNKNOWN_REQUEST;
   imageLoader->GetRequestType(aRequest, &requestType);
 
   return requestType != nsIImageLoadingContent::CURRENT_REQUEST;
 }
 
-bool
-nsImageFrame::IsPendingLoad(imgIContainer* aContainer) const
-{
-  //  default to pending load in case of errors
-  if (!aContainer) {
-    NS_ERROR("No image container!");
-    return true;
-  }
-
-  nsCOMPtr<nsIImageLoadingContent> imageLoader(do_QueryInterface(mContent));
-  NS_ASSERTION(imageLoader, "No image loading content?");
-  
-  nsCOMPtr<imgIRequest> currentRequest;
-  imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
-                          getter_AddRefs(currentRequest));
-  if (!currentRequest) {
-    NS_ERROR("No current request");
-    return true;
-  }
-
-  nsCOMPtr<imgIContainer> currentContainer;
-  currentRequest->GetImage(getter_AddRefs(currentContainer));
-
-  return currentContainer != aContainer;
-  
-}
-
 nsRect
 nsImageFrame::SourceRectToDest(const nsIntRect& aRect)
 {
   // When scaling the image, row N of the source image may (depending on
   // the scaling function) be used to draw any row in the destination image
   // between floor(F * (N-1)) and ceil(F * (N+1)), where F is the
   // floating-point scaling factor.  The same holds true for columns.
   // So, we start by computing that bound without the floor and ceiling.
@@ -627,57 +595,62 @@ nsImageFrame::OnSizeAvailable(imgIReques
   }
 
   return NS_OK;
 }
 
 nsresult
 nsImageFrame::OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect)
 {
-  if (mFirstFrameComplete) {
-    nsCOMPtr<imgIContainer> container;
-    aRequest->GetImage(getter_AddRefs(container));
-    return FrameChanged(aRequest, container);
-  }
-
-  // XXX do we need to make sure that the reflow from the OnSizeAvailable has
-  // been processed before we start calling invalidate?
-
   NS_ENSURE_ARG_POINTER(aRect);
 
   if (!(mState & IMAGE_GOTINITIALREFLOW)) {
     // Don't bother to do anything; we have a reflow coming up!
     return NS_OK;
   }
   
+  if (mFirstFrameComplete && !StyleVisibility()->IsVisible()) {
+    return NS_OK;
+  }
+
   if (IsPendingLoad(aRequest)) {
     // We don't care
     return NS_OK;
   }
 
-  nsIntRect rect = mImage ? mImage->GetImageSpaceInvalidationRect(*aRect)
-                          : *aRect;
-
-#ifdef DEBUG_decode
-  printf("Source rect (%d,%d,%d,%d)\n",
-         aRect->x, aRect->y, aRect->width, aRect->height);
-#endif
+  nsIntRect layerInvalidRect = mImage
+                             ? mImage->GetImageSpaceInvalidationRect(*aRect)
+                             : *aRect;
 
-  if (rect.IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
-    InvalidateFrame(nsDisplayItem::TYPE_IMAGE);
-    InvalidateFrame(nsDisplayItem::TYPE_ALT_FEEDBACK);
-  } else {
-    nsRect invalid = SourceRectToDest(rect);
-    InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_IMAGE);
-    InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_ALT_FEEDBACK);
+  if (layerInvalidRect.IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
+    // Invalidate our entire area.
+    InvalidateSelf(nullptr, nullptr);
+    return NS_OK;
   }
 
+  nsRect frameInvalidRect = SourceRectToDest(layerInvalidRect);
+  InvalidateSelf(&layerInvalidRect, &frameInvalidRect);
   return NS_OK;
 }
 
+void
+nsImageFrame::InvalidateSelf(const nsIntRect* aLayerInvalidRect,
+                             const nsRect* aFrameInvalidRect)
+{
+  InvalidateLayer(nsDisplayItem::TYPE_IMAGE,
+                  aLayerInvalidRect,
+                  aFrameInvalidRect);
+
+  if (!mFirstFrameComplete) {
+    InvalidateLayer(nsDisplayItem::TYPE_ALT_FEEDBACK,
+                    aLayerInvalidRect,
+                    aFrameInvalidRect);
+  }
+}
+
 nsresult
 nsImageFrame::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
 {
   // Check what request type we're dealing with
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
   NS_ASSERTION(imageLoader, "Who's notifying us??");
   int32_t loadType = nsIImageLoadingContent::UNKNOWN_REQUEST;
   imageLoader->GetRequestType(aRequest, &loadType);
@@ -724,33 +697,16 @@ nsImageFrame::NotifyNewCurrentRequest(im
                                     NS_FRAME_IS_DIRTY);
       }
     }
     // Update border+content to account for image change
     InvalidateFrame();
   }
 }
 
-nsresult
-nsImageFrame::FrameChanged(imgIRequest *aRequest,
-                           imgIContainer *aContainer)
-{
-  if (!StyleVisibility()->IsVisible()) {
-    return NS_OK;
-  }
-
-  if (IsPendingLoad(aContainer)) {
-    // We don't care about it
-    return NS_OK;
-  }
-
-  InvalidateLayer(nsDisplayItem::TYPE_IMAGE);
-  return NS_OK;
-}
-
 void
 nsImageFrame::EnsureIntrinsicSizeAndRatio()
 {
   // If mIntrinsicSize.width and height are 0, then we need to update from the
   // image container.
   if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
       mIntrinsicSize.width.GetCoordValue() == 0 &&
       mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord &&
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -220,18 +220,17 @@ protected:
 
 protected:
   friend class nsImageListener;
   friend class nsImageLoadingContent;
 
   nsresult OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
   nsresult OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect);
   nsresult OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
-  nsresult FrameChanged(imgIRequest *aRequest,
-                        imgIContainer *aContainer);
+
   /**
    * Notification that aRequest will now be the current request.
    */
   void NotifyNewCurrentRequest(imgIRequest *aRequest, nsresult aStatus);
 
 private:
   // random helpers
   inline void SpecToURI(const nsAString& aSpec, nsIIOService *aIOService,
@@ -266,29 +265,40 @@ private:
    *
    * @param aTransform The transform object to populate.
    *
    * @return whether we succeeded in creating the transform.
    */
   bool 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.
+   * Helper function to check whether the request corresponds to a load we don't
+   * care about.  Most of the decoder observer methods will bail early if this
+   * returns true.
    */
   bool IsPendingLoad(imgIRequest* aRequest) const;
-  bool IsPendingLoad(imgIContainer* aContainer) const;
 
   /**
    * Function to convert a dirty rect in the source image to a dirty
    * rect for the image frame.
    */
   nsRect SourceRectToDest(const nsIntRect & aRect);
 
+  /**
+   * Triggers invalidation for both our image display item and, if appropriate,
+   * our alt-feedback display item.
+   *
+   * @param aLayerInvalidRect The area to invalidate in layer space. If null, the
+   *                          entire layer will be invalidated.
+   * @param aFrameInvalidRect The area to invalidate in frame space. If null, the
+   *                          entire frame will be invalidated.
+   */
+  void InvalidateSelf(const nsIntRect* aLayerInvalidRect,
+                      const nsRect* aFrameInvalidRect);
+
   nsImageMap*         mImageMap;
 
   nsCOMPtr<imgINotificationObserver> mListener;
 
   nsCOMPtr<imgIContainer> mImage;
   nsSize mComputedSize;
   mozilla::IntrinsicSize mIntrinsicSize;
   nsSize mIntrinsicRatio;