Bug 781053 - Part 1 - Allow conversion of nsImageBoxFrame to an ImageLayer. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 25 Sep 2012 08:29:14 +1200
changeset 114591 b12bf692dc2d37acca3100faed7bd169a727169b
parent 114590 3c1da25b84528191a84a41cf7455b2cddf018be0
child 114592 213b15f0c3c332809f523304dff530da44a67403
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs781053
milestone18.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 781053 - Part 1 - Allow conversion of nsImageBoxFrame to an ImageLayer. r=roc
layout/base/FrameLayerBuilder.cpp
layout/base/nsDisplayList.h
layout/generic/nsImageFrame.h
layout/xul/base/src/nsImageBoxFrame.cpp
layout/xul/base/src/nsImageBoxFrame.h
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -9,17 +9,16 @@
 #include "nsPresContext.h"
 #include "nsLayoutUtils.h"
 #include "Layers.h"
 #include "BasicLayers.h"
 #include "nsSubDocumentFrame.h"
 #include "nsCSSRendering.h"
 #include "nsCSSFrameConstructor.h"
 #include "gfxUtils.h"
-#include "nsImageFrame.h"
 #include "nsRenderingContext.h"
 #include "MaskLayerImageCache.h"
 #include "nsIScrollableFrame.h"
 #include "nsPrintfCString.h"
 #include "LayerTreeInvalidation.h"
 #include "nsSVGIntegrationUtils.h"
 
 #include "mozilla/Preferences.h"
@@ -330,17 +329,17 @@ protected:
      * part of its surface.
      */
     bool mForceTransparentSurface;
 
     /**
      * Stores the pointer to the nsDisplayImage if we want to
      * convert this to an ImageLayer.
      */
-    nsDisplayImage* mImage;
+    nsDisplayImageContainer* mImage;
     /**
      * Stores the clip that we need to apply to the image or, if there is no
      * image, a clip for SOME item in the layer. There is no guarantee which
      * item's clip will be stored here and mItemClip should not be used to clip
      * the whole layer - only some part of the clip should be used, as determined
      * by ThebesDisplayItemLayerUserData::GetCommonClipCount() - which may even be
      * no part at all.
      */
@@ -1777,18 +1776,20 @@ ContainerState::ThebesLayerData::Accumul
     // Note that the transform (if any) on the ThebesLayer is always an integer translation so
     // we don't have to factor that in here.
     aItem->DisableComponentAlpha();
   }
 
   /* Mark as available for conversion to image layer if this is a nsDisplayImage and
    * we are the first visible item in the ThebesLayerData object.
    */
-  if (mVisibleRegion.IsEmpty() && aItem->GetType() == nsDisplayItem::TYPE_IMAGE) {
-    mImage = static_cast<nsDisplayImage*>(aItem);
+  if (mVisibleRegion.IsEmpty() &&
+      (aItem->GetType() == nsDisplayItem::TYPE_IMAGE ||
+       aItem->GetType() == nsDisplayItem::TYPE_XUL_IMAGE)) {
+    mImage = static_cast<nsDisplayImageContainer*>(aItem);
   } else {
     mImage = nullptr;
   }
   mItemClip = aClip;
 
   if (!mIsSolidColorInVisibleRegion && mOpaqueRegion.Contains(aDrawRect) &&
       mVisibleRegion.Contains(aVisibleRect)) {
     // A very common case! Most pages have a ThebesLayer with the page
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2728,9 +2728,22 @@ public:
             t == nsDisplayItem::TYPE_TEXT_SHADOW)
       ? static_cast<nsCharClipDisplayItem*>(aItem) : nullptr;
   }
 
   nscoord mLeftEdge;  // length from the left side
   nscoord mRightEdge; // length from the right side
 };
 
+class nsDisplayImageContainer : public nsDisplayItem {
+public:
+  typedef mozilla::layers::ImageContainer ImageContainer;
+  typedef mozilla::layers::ImageLayer ImageLayer;
+
+  nsDisplayImageContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+    : nsDisplayItem(aBuilder, aFrame)
+  {}
+
+  virtual already_AddRefed<ImageContainer> GetContainer() = 0;
+  virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) = 0;
+};
+
 #endif /*NSDISPLAYLIST_H_*/
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -357,53 +357,51 @@ public:
 };
 
 /**
  * Note that nsDisplayImage does not receive events. However, an image element
  * is replaced content so its background will be z-adjacent to the
  * image itself, and hence receive events just as if the image itself
  * received events.
  */
-class nsDisplayImage : public nsDisplayItem {
+class nsDisplayImage : public nsDisplayImageContainer {
 public:
-  typedef mozilla::layers::ImageContainer ImageContainer;
-  typedef mozilla::layers::ImageLayer ImageLayer;
   typedef mozilla::layers::LayerManager LayerManager;
 
   nsDisplayImage(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame,
                  imgIContainer* aImage)
-    : nsDisplayItem(aBuilder, aFrame), mImage(aImage) {
+    : nsDisplayImageContainer(aBuilder, aFrame), mImage(aImage) {
     MOZ_COUNT_CTOR(nsDisplayImage);
   }
   virtual ~nsDisplayImage() {
     MOZ_COUNT_DTOR(nsDisplayImage);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
 
   /**
    * Returns an ImageContainer for this image if the image type
    * supports it (TYPE_RASTER only).
    */
-  already_AddRefed<ImageContainer> GetContainer();
+  virtual already_AddRefed<ImageContainer> GetContainer() MOZ_OVERRIDE;
 
   gfxRect GetDestRect();
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerParameters& aParameters) MOZ_OVERRIDE;
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
 
   /**
    * Configure an ImageLayer for this display item.
    * Set the required filter and scaling transform.
    */
-  void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset);
+  virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE)
 private:
   nsCOMPtr<imgIContainer> mImage;
 };
 
 #endif /* nsImageFrame_h___ */
--- a/layout/xul/base/src/nsImageBoxFrame.cpp
+++ b/layout/xul/base/src/nsImageBoxFrame.cpp
@@ -39,21 +39,25 @@
 
 #include "nsIServiceManager.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsDisplayList.h"
+#include "ImageLayers.h"
+#include "ImageContainer.h"
 
 #include "nsContentUtils.h"
 
 #define ONLOAD_CALLED_TOO_EARLY 1
 
+using namespace mozilla::layers;
+
 class nsImageBoxFrameEvent : public nsRunnable
 {
 public:
   nsImageBoxFrameEvent(nsIContent *content, uint32_t message)
     : mContent(content), mMessage(message) {}
 
   NS_IMETHOD Run();
 
@@ -277,46 +281,16 @@ nsImageBoxFrame::UpdateLoadFlags()
       mLoadFlags = nsIRequest::VALIDATE_NEVER|nsIRequest::LOAD_FROM_CACHE;
       break;
     default:
       mLoadFlags = nsIRequest::LOAD_NORMAL;
       break;
   }
 }
 
-class nsDisplayXULImage : public nsDisplayItem {
-public:
-  nsDisplayXULImage(nsDisplayListBuilder* aBuilder,
-                    nsImageBoxFrame* aFrame) :
-    nsDisplayItem(aBuilder, aFrame) {
-    MOZ_COUNT_CTOR(nsDisplayXULImage);
-  }
-#ifdef NS_BUILD_REFCNT_LOGGING
-  virtual ~nsDisplayXULImage() {
-    MOZ_COUNT_DTOR(nsDisplayXULImage);
-  }
-#endif
-
-  // Doesn't handle HitTest because nsLeafBoxFrame already creates an
-  // event receiver for us
-  virtual void Paint(nsDisplayListBuilder* aBuilder,
-                     nsRenderingContext* aCtx);
-  NS_DISPLAY_DECL_NAME("XULImage", TYPE_XUL_IMAGE)
-};
-
-void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder,
-                              nsRenderingContext* aCtx)
-{
-  static_cast<nsImageBoxFrame*>(mFrame)->
-    PaintImage(*aCtx, mVisibleRect, ToReferenceFrame(),
-               aBuilder->ShouldSyncDecodeImages()
-                 ? (uint32_t) imgIContainer::FLAG_SYNC_DECODE
-                 : (uint32_t) imgIContainer::FLAG_NONE);
-}
-
 NS_IMETHODIMP
 nsImageBoxFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                   const nsRect&           aDirtyRect,
                                   const nsDisplayListSet& aLists)
 {
   nsresult rv = nsLeafBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -358,16 +332,84 @@ nsImageBoxFrame::PaintImage(nsRenderingC
   if (imgCon) {
     bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
     nsLayoutUtils::DrawSingleImage(&aRenderingContext, imgCon,
         nsLayoutUtils::GetGraphicsFilterForFrame(this),
         rect, dirty, aFlags, hasSubRect ? &mSubRect : nullptr);
   }
 }
 
+void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder,
+                              nsRenderingContext* aCtx)
+{
+  static_cast<nsImageBoxFrame*>(mFrame)->
+    PaintImage(*aCtx, mVisibleRect, ToReferenceFrame(),
+               aBuilder->ShouldSyncDecodeImages()
+                 ? (uint32_t) imgIContainer::FLAG_SYNC_DECODE
+                 : (uint32_t) imgIContainer::FLAG_NONE);
+}
+
+void
+nsDisplayXULImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset)
+{
+  aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
+
+  int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
+  nsImageBoxFrame* imageFrame = static_cast<nsImageBoxFrame*>(mFrame);
+
+  nsRect dest;
+  imageFrame->GetClientRect(dest);
+  dest += ToReferenceFrame();
+  gfxRect destRect(dest.x, dest.y, dest.width, dest.height);
+  destRect.ScaleInverse(factor); 
+
+  nsCOMPtr<imgIContainer> imgCon;
+  imageFrame->mImageRequest->GetImage(getter_AddRefs(imgCon));
+  int32_t imageWidth;
+  int32_t imageHeight;
+  imgCon->GetWidth(&imageWidth);
+  imgCon->GetHeight(&imageHeight);
+
+  NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
+
+  gfxMatrix transform;
+  transform.Translate(destRect.TopLeft() + aOffset);
+  transform.Scale(destRect.Width()/imageWidth,
+                  destRect.Height()/imageHeight);
+  aLayer->SetBaseTransform(gfx3DMatrix::From2D(transform));
+
+  aLayer->SetVisibleRegion(nsIntRect(0, 0, imageWidth, imageHeight));
+}
+
+already_AddRefed<ImageContainer>
+nsDisplayXULImage::GetContainer()
+{
+  return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer();
+}
+
+already_AddRefed<ImageContainer>
+nsImageBoxFrame::GetContainer()
+{
+  bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
+  if (hasSubRect || !mImageRequest) {
+    return nullptr;
+  }
+
+  nsCOMPtr<imgIContainer> imgCon;
+  mImageRequest->GetImage(getter_AddRefs(imgCon));
+  if (!imgCon) {
+    return nullptr;
+  }
+  
+  nsRefPtr<ImageContainer> container;
+  nsresult rv = imgCon->GetImageContainer(getter_AddRefs(container));
+  NS_ENSURE_SUCCESS(rv, nullptr);
+  return container.forget();
+}
+
 
 //
 // DidSetStyleContext
 //
 // When the style context changes, make sure that all of our image is up to date.
 //
 /* virtual */ void
 nsImageBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
--- a/layout/xul/base/src/nsImageBoxFrame.h
+++ b/layout/xul/base/src/nsImageBoxFrame.h
@@ -10,16 +10,18 @@
 
 #include "imgILoader.h"
 #include "imgIRequest.h"
 #include "imgIContainer.h"
 #include "nsStubImageDecoderObserver.h"
 
 class nsImageBoxFrame;
 
+class nsDisplayXULImage;
+
 class nsImageBoxListener : public nsStubImageDecoderObserver
 {
 public:
   nsImageBoxListener();
   virtual ~nsImageBoxListener();
 
   NS_DECL_ISUPPORTS
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
@@ -38,16 +40,17 @@ public:
 
 private:
   nsImageBoxFrame *mFrame;
 };
 
 class nsImageBoxFrame : public nsLeafBoxFrame
 {
 public:
+  friend class nsDisplayXULImage;
   NS_DECL_FRAMEARENA_HELPERS
 
   virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState);
   virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState);
   virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE;
 
   friend nsIFrame* NS_NewImageBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
@@ -98,16 +101,17 @@ public:
                           const nsIntRect *aDirtyRect);
 
   virtual ~nsImageBoxFrame();
 
   void  PaintImage(nsRenderingContext& aRenderingContext,
                    const nsRect& aDirtyRect,
                    nsPoint aPt, uint32_t aFlags);
 
+  already_AddRefed<mozilla::layers::ImageContainer> GetContainer();
 protected:
   nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext);
 
   virtual void GetImageSize();
 
 private:
 
   nsRect mSubRect; ///< If set, indicates that only the portion of the image specified by the rect should be used.
@@ -122,9 +126,32 @@ private:
   nsCOMPtr<imgIDecoderObserver> mListener;
 
   int32_t mLoadFlags;
 
   bool mUseSrcAttr; ///< Whether or not the image src comes from an attribute.
   bool mSuppressStyleCheck;
 }; // class nsImageBoxFrame
 
+class nsDisplayXULImage : public nsDisplayImageContainer {
+public:
+  nsDisplayXULImage(nsDisplayListBuilder* aBuilder,
+                    nsImageBoxFrame* aFrame) :
+    nsDisplayImageContainer(aBuilder, aFrame) {
+    MOZ_COUNT_CTOR(nsDisplayXULImage);
+  }
+#ifdef NS_BUILD_REFCNT_LOGGING
+  virtual ~nsDisplayXULImage() {
+    MOZ_COUNT_DTOR(nsDisplayXULImage);
+  }
+#endif
+
+  virtual already_AddRefed<ImageContainer> GetContainer() MOZ_OVERRIDE;
+  virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) MOZ_OVERRIDE;
+
+  // Doesn't handle HitTest because nsLeafBoxFrame already creates an
+  // event receiver for us
+  virtual void Paint(nsDisplayListBuilder* aBuilder,
+                     nsRenderingContext* aCtx);
+  NS_DISPLAY_DECL_NAME("XULImage", TYPE_XUL_IMAGE)
+};
+
 #endif /* nsImageBoxFrame_h___ */