Bug 1031576 (Part 2) - Use dynamic images in the implementation of -moz-element. r=nrc
authorSeth Fowler <seth@mozilla.com>
Mon, 21 Jul 2014 17:59:23 -0700
changeset 195382 fe38d8c189e541af26b62e6dcabc0299420f2673
parent 195381 ab8ac3c0de7feb48f1f65b919c9c59c86cf9bf6f
child 195383 f1d7b63dc997a6ac00e0f2c340f3ec0698fa9557
push id46576
push usermfowler@mozilla.com
push dateTue, 22 Jul 2014 00:59:51 +0000
treeherdermozilla-inbound@fd4c9f4cd1f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnrc
bugs1031576
milestone34.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 1031576 (Part 2) - Use dynamic images in the implementation of -moz-element. r=nrc
layout/base/nsCSSRendering.cpp
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -4780,19 +4780,22 @@ nsImageRenderer::Draw(nsPresContext*    
     case eStyleImageType_Element:
     {
       nsRefPtr<gfxDrawable> drawable = DrawableForElement(aDest,
                                                           aRenderingContext);
       if (!drawable) {
         NS_WARNING("Could not create drawable for element");
         return;
       }
-      nsLayoutUtils::DrawPixelSnapped(&aRenderingContext, aPresContext,
-                                      drawable, graphicsFilter,
-                                      aDest, aFill, aDest.TopLeft(), aDirtyRect);
+
+      nsCOMPtr<imgIContainer> image(ImageOps::CreateFromDrawable(drawable));
+      nsLayoutUtils::DrawImage(&aRenderingContext, aPresContext, image,
+                               graphicsFilter, aDest, aFill,
+                               aDest.TopLeft(), aDirtyRect, 
+                               ConvertImageRendererToDrawFlags(mFlags));
       return;
     }
     case eStyleImageType_Null:
     default:
       return;
   }
 }
 
@@ -4947,24 +4950,44 @@ nsImageRenderer::DrawBorderImageComponen
   if (!mIsReady) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     return;
   }
   if (aFill.IsEmpty() || aSrc.IsEmpty()) {
     return;
   }
 
-  if (mType == eStyleImageType_Image) {
+  if (mType == eStyleImageType_Image || mType == eStyleImageType_Element) {
     nsCOMPtr<imgIContainer> subImage;
-    if ((subImage = mImage->GetSubImage(aIndex)) == nullptr) {
-      subImage = ImageOps::Clip(mImageContainer, nsIntRect(aSrc.x,
-                                                           aSrc.y,
-                                                           aSrc.width,
-                                                           aSrc.height));
-      mImage->SetSubImage(aIndex, subImage);
+
+    // Retrieve or create the subimage we'll draw.
+    nsIntRect srcRect(aSrc.x, aSrc.y, aSrc.width, aSrc.height);
+    if (mType == eStyleImageType_Image) {
+      if ((subImage = mImage->GetSubImage(aIndex)) == nullptr) {
+        subImage = ImageOps::Clip(mImageContainer, srcRect);
+        mImage->SetSubImage(aIndex, subImage);
+      }
+    } else {
+      // This path, for eStyleImageType_Element, is currently slower than it
+      // needs to be because we don't cache anything. (In particular, if we have
+      // to draw to a temporary surface inside ClippedImage, we don't cache that
+      // temporary surface since we immediately throw the ClippedImage we create
+      // here away.) However, if we did cache, we'd need to know when to
+      // invalidate that cache, and it's not clear that it's worth the trouble
+      // since using border-image with -moz-element is rare.
+
+      nsRefPtr<gfxDrawable> drawable = DrawableForElement(nsRect(nsPoint(), mSize),
+                                                          aRenderingContext);
+      if (!drawable) {
+        NS_WARNING("Could not create drawable for element");
+        return;
+      }
+
+      nsCOMPtr<imgIContainer> image(ImageOps::CreateFromDrawable(drawable));
+      subImage = ImageOps::Clip(image, srcRect);
     }
 
     GraphicsFilter graphicsFilter =
       nsLayoutUtils::GetGraphicsFilterForFrame(mForFrame);
 
     if (!RequiresScaling(aFill, aHFill, aVFill, aUnitSize)) {
       nsLayoutUtils::DrawSingleImage(&aRenderingContext,
                                      aPresContext,
@@ -4985,84 +5008,16 @@ nsImageRenderer::DrawBorderImageComponen
                              imgIContainer::FLAG_NONE);
     return;
   }
 
   nsRect destTile = RequiresScaling(aFill, aHFill, aVFill, aUnitSize)
                   ? ComputeTile(aFill, aHFill, aVFill, aUnitSize)
                   : aFill;
 
-  if (mType == eStyleImageType_Element) {
-    // This path is horribly slow - we read and copy the source nine times(!)
-    // It could be easily optimised by only reading the source once and caching
-    // it. It could be further optimised by caching the sub-images between draws
-    // but that would be a bit harder because you would have to know when to
-    // invalidate the cache. A special case optimisation would be when
-    // border-image-slice is proportional to the border widths, in which case
-    // the subimages do not need to be independently scaled, then we don't need
-    // subimages at all.
-    // In any case, such optimisations are probably not worth doing because it
-    // seems unlikely anyone would use -moz-element as the source for a border
-    // image.
-
-    // draw the source image slice into an intermediate surface
-    nsPresContext* presContext = mForFrame->PresContext();
-    gfxRect srcRect = gfxRect(presContext->CSSPixelsToDevPixels(aSrc.x),
-                              presContext->CSSPixelsToDevPixels(aSrc.y),
-                              presContext->CSSPixelsToDevPixels(aSrc.width),
-                              presContext->CSSPixelsToDevPixels(aSrc.height));
-    RefPtr<DrawTarget> srcSlice = gfxPlatform::GetPlatform()->
-      CreateOffscreenContentDrawTarget(IntSize(srcRect.width, srcRect.height),
-                             SurfaceFormat::B8G8R8A8);
-    if (!srcSlice) {
-      NS_ERROR("Could not create DrawTarget for element");
-      return;
-    }
-    nsRefPtr<gfxContext> ctx = new gfxContext(srcSlice);
-
-    // grab the entire source
-    nsRefPtr<gfxDrawable> drawable = DrawableForElement(nsRect(nsPoint(), mSize),
-                                                        aRenderingContext);
-    if (!drawable) {
-      NS_WARNING("Could not create drawable for element");
-      return;
-    }
-
-    // draw the source into our intermediate surface
-    GraphicsFilter graphicsFilter =
-      nsLayoutUtils::GetGraphicsFilterForFrame(mForFrame);
-    gfxMatrix transform;
-    transform.Translate(gfxPoint(srcRect.x, srcRect.y));
-    bool success = drawable->Draw(ctx,
-                                  gfxRect(0, 0, srcRect.width, srcRect.height),
-                                  false,
-                                  graphicsFilter,
-                                  transform);
-    if (!success) {
-      NS_WARNING("Could not copy element image");
-      return;
-    }
-
-    // Ensure that drawing the image gets flushed to the target.
-    ctx = nullptr;
-
-    // draw the slice
-    nsRefPtr<gfxSurfaceDrawable> srcSliceDrawable =
-      new gfxSurfaceDrawable(srcSlice,
-                             gfxIntSize(srcRect.width, srcRect.height));
-    nsPoint anchor(nsPresContext::CSSPixelsToAppUnits(aSrc.x),
-                   nsPresContext::CSSPixelsToAppUnits(aSrc.y));
-    nsLayoutUtils::DrawPixelSnapped(&aRenderingContext, aPresContext,
-                                    srcSliceDrawable,
-                                    graphicsFilter, destTile, aFill,
-                                    anchor, aDirtyRect);
-
-    return;
-  }
-
   Draw(aPresContext, aRenderingContext, aDirtyRect, aFill, destTile, aSrc);
 }
 
 bool
 nsImageRenderer::IsRasterImage()
 {
   if (mType != eStyleImageType_Image || !mImageContainer)
     return false;