Backed out changeset 20b75bf44c1e (bug 997014)
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 17 Apr 2014 08:43:43 +0200
changeset 178957 a31da56c8d8f720abdfdbc5e7faa2ec38e7e7f51
parent 178956 a7c93f92a08ac0c61b4c806d72b60d869ed5e24c
child 178958 07330eba610687c1a1f90199aabbd6cc868a64c9
push id42404
push usercbook@mozilla.com
push dateThu, 17 Apr 2014 06:44:16 +0000
treeherdermozilla-inbound@07330eba6106 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs997014
milestone31.0a1
backs out20b75bf44c1ece055a25b729e8b54bebef579a29
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
Backed out changeset 20b75bf44c1e (bug 997014)
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/html/content/public/HTMLCanvasElement.h
content/html/content/src/HTMLCanvasElement.cpp
gfx/thebes/gfxUtils.cpp
gfx/thebes/gfxUtils.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -1029,17 +1029,17 @@ protected:
     nsLayoutUtils::SurfaceFromElementResult SurfaceFromElement(ElementType* aElement) {
         MOZ_ASSERT(aElement);
         uint32_t flags =
              nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
 
         if (mPixelStoreColorspaceConversion == LOCAL_GL_NONE)
             flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
         if (!mPixelStorePremultiplyAlpha)
-            flags |= nsLayoutUtils::SFE_PREFER_NO_PREMULTIPLY_ALPHA;
+            flags |= nsLayoutUtils::SFE_NO_PREMULTIPLY_ALPHA;
         return nsLayoutUtils::SurfaceFromElement(aElement, flags);
     }
     template<class ElementType>
     nsLayoutUtils::SurfaceFromElementResult SurfaceFromElement(ElementType& aElement)
     {
       return SurfaceFromElement(&aElement);
     }
 
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -24,17 +24,16 @@
 #include "gfxPlatform.h"
 #include "GLContext.h"
 
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsLayoutUtils.h"
 
 #include "CanvasUtils.h"
-#include "gfxUtils.h"
 
 #include "jsfriendapi.h"
 
 #include "WebGLTexelConversions.h"
 #include "WebGLValidateStrings.h"
 #include <algorithm>
 
 // needed to check if current OS is lower than 10.7
@@ -2517,20 +2516,16 @@ WebGLContext::SurfaceFromElementResultTo
     if (!res.mSourceSurface)
         return NS_OK;
     RefPtr<DataSourceSurface> data = res.mSourceSurface->GetDataSurface();
     if (!data) {
         // SurfaceFromElement lied!
         return NS_OK;
     }
 
-    if (!mPixelStorePremultiplyAlpha && res.mIsPremultiplied) {
-      data = gfxUtils::UnpremultiplyDataSurface(data);
-    }
-
     // We disallow loading cross-domain images and videos that have not been validated
     // with CORS as WebGL textures. The reason for doing that is that timing
     // attacks on WebGL shaders are able to retrieve approximations of the
     // pixel values in WebGL textures; see bug 655987.
     //
     // To prevent a loophole where a Canvas2D would be used as a proxy to load
     // cross-domain textures, we also disallow loading textures from write-only
     // Canvas2D's.
--- a/content/html/content/public/HTMLCanvasElement.h
+++ b/content/html/content/public/HTMLCanvasElement.h
@@ -21,19 +21,16 @@ class nsIDOMFile;
 class nsITimerCallback;
 
 namespace mozilla {
 
 namespace layers {
 class CanvasLayer;
 class LayerManager;
 }
-namespace gfx {
-class SourceSurface;
-}
 
 namespace dom {
 
 class FileCallback;
 class HTMLCanvasPrintState;
 class PrintCallback;
 
 class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement,
@@ -164,17 +161,16 @@ public:
 
   /*
    * nsICanvasElementExternal -- for use outside of content/layout
    */
   NS_IMETHOD_(nsIntSize) GetSizeExternal() MOZ_OVERRIDE;
   NS_IMETHOD RenderContextsExternal(gfxContext *aContext,
                                     GraphicsFilter aFilter,
                                     uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
-  virtual TemporaryRef<gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr);
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) MOZ_OVERRIDE;
   nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, int32_t aModType) const MOZ_OVERRIDE;
 
   // SetAttr override.  C++ is stupid, so have to override both
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -33,17 +33,16 @@
 #include "nsStreamUtils.h"
 #include "ActiveLayerTracker.h"
 
 #ifdef MOZ_WEBGL
 #include "../canvas/src/WebGL2Context.h"
 #endif
 
 using namespace mozilla::layers;
-using namespace mozilla::gfx;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
 
 namespace {
 
 typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
 HTMLImageOrCanvasOrVideoElement;
 
@@ -945,19 +944,10 @@ NS_IMETHODIMP
 HTMLCanvasElement::RenderContextsExternal(gfxContext *aContext, GraphicsFilter aFilter, uint32_t aFlags)
 {
   if (!mCurrentContext)
     return NS_OK;
 
   return mCurrentContext->Render(aContext, aFilter, aFlags);
 }
 
-TemporaryRef<SourceSurface>
-HTMLCanvasElement::GetSurfaceSnapshot(bool* aPremultAlpha)
-{
-  if (!mCurrentContext)
-    return nullptr;
-
-  return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha);
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -136,76 +136,16 @@ gfxUtils::UnpremultiplyImageSurface(gfxI
           *dstRow++ = UnpremultiplyValue(a, r);
           *dstRow++ = UnpremultiplyValue(a, g);
           *dstRow++ = UnpremultiplyValue(a, b);
 #endif
         }
     }
 }
 
-TemporaryRef<DataSourceSurface>
-gfxUtils::UnpremultiplyDataSurface(DataSourceSurface* aSurface)
-{
-    // Only premultiply ARGB32
-    if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) {
-        return aSurface;
-    }
-
-    DataSourceSurface::MappedSurface map;
-    if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
-        return nullptr;
-    }
-
-    RefPtr<DataSourceSurface> dest = Factory::CreateDataSourceSurfaceWithStride(aSurface->GetSize(),
-                                                                                aSurface->GetFormat(),
-                                                                                map.mStride);
-
-    DataSourceSurface::MappedSurface destMap;
-    if (!dest->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
-        aSurface->Unmap();
-        return nullptr;
-    }
-
-    uint8_t *src = map.mData;
-    uint8_t *dst = destMap.mData;
-
-    for (int32_t i = 0; i < aSurface->GetSize().height; ++i) {
-        uint8_t *srcRow = src + (i * map.mStride);
-        uint8_t *dstRow = dst + (i * destMap.mStride);
-
-        for (int32_t j = 0; j < aSurface->GetSize().width; ++j) {
-#ifdef IS_LITTLE_ENDIAN
-          uint8_t b = *srcRow++;
-          uint8_t g = *srcRow++;
-          uint8_t r = *srcRow++;
-          uint8_t a = *srcRow++;
-
-          *dstRow++ = UnpremultiplyValue(a, b);
-          *dstRow++ = UnpremultiplyValue(a, g);
-          *dstRow++ = UnpremultiplyValue(a, r);
-          *dstRow++ = a;
-#else
-          uint8_t a = *srcRow++;
-          uint8_t r = *srcRow++;
-          uint8_t g = *srcRow++;
-          uint8_t b = *srcRow++;
-
-          *dstRow++ = a;
-          *dstRow++ = UnpremultiplyValue(a, r);
-          *dstRow++ = UnpremultiplyValue(a, g);
-          *dstRow++ = UnpremultiplyValue(a, b);
-#endif
-        }
-    }
-
-    aSurface->Unmap();
-    dest->Unmap();
-    return dest;
-}
-
 void
 gfxUtils::ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
                             gfxImageSurface *aDestSurface) {
     if (!aDestSurface)
         aDestSurface = aSourceSurface;
 
     MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
                aSourceSurface->Width()  == aDestSurface->Width() &&
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -39,17 +39,16 @@ public:
      *
      * If the source is not gfxImageFormat::ARGB32, no operation is performed.  If
      * aDestSurface is given, the data is copied over.
      */
     static void PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
                                         gfxImageSurface *aDestSurface = nullptr);
     static void UnpremultiplyImageSurface(gfxImageSurface *aSurface,
                                           gfxImageSurface *aDestSurface = nullptr);
-    static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface);
 
     static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
                                   gfxImageSurface *aDestSurface = nullptr);
 
     /**
      * Draw something drawable while working around limitations like bad support
      * for EXTEND_PAD, lack of source-clipping, or cairo / pixman bugs with
      * extreme user-space-to-image-space transforms.
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5382,20 +5382,18 @@ nsLayoutUtils::SurfaceFromElement(nsIIma
   uint32_t noRasterize = aSurfaceFlags & SFE_NO_RASTERIZING_VECTORS;
 
   uint32_t whichFrame = (aSurfaceFlags & SFE_WANT_FIRST_FRAME)
                         ? (uint32_t) imgIContainer::FRAME_FIRST
                         : (uint32_t) imgIContainer::FRAME_CURRENT;
   uint32_t frameFlags = imgIContainer::FLAG_SYNC_DECODE;
   if (aSurfaceFlags & SFE_NO_COLORSPACE_CONVERSION)
     frameFlags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION;
-  if (aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) {
+  if (aSurfaceFlags & SFE_NO_PREMULTIPLY_ALPHA)
     frameFlags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
-    result.mIsPremultiplied = false;
-  }
 
   int32_t imgWidth, imgHeight;
   rv = imgContainer->GetWidth(&imgWidth);
   nsresult rv2 = imgContainer->GetHeight(&imgHeight);
   if (NS_FAILED(rv) || NS_FAILED(rv2))
     return result;
 
   if (!noRasterize || imgContainer->GetType() == imgIContainer::TYPE_RASTER) {
@@ -5447,38 +5445,62 @@ nsLayoutUtils::SurfaceFromElement(HTMLIm
 }
 
 nsLayoutUtils::SurfaceFromElementResult
 nsLayoutUtils::SurfaceFromElement(HTMLCanvasElement* aElement,
                                   uint32_t aSurfaceFlags,
                                   DrawTarget* aTarget)
 {
   SurfaceFromElementResult result;
-
-  bool* isPremultiplied = nullptr;
-  if (aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) {
-    isPremultiplied = &result.mIsPremultiplied;
-  }
+  nsresult rv;
+
+  bool premultAlpha = (aSurfaceFlags & SFE_NO_PREMULTIPLY_ALPHA) == 0;
 
   gfxIntSize size = aElement->GetSize();
 
-  result.mSourceSurface = aElement->GetSurfaceSnapshot(isPremultiplied);
+  if (premultAlpha && aElement->CountContexts() == 1) {
+    nsICanvasRenderingContextInternal *srcCanvas = aElement->GetContextAtIndex(0);
+    result.mSourceSurface = srcCanvas->GetSurfaceSnapshot();
+  }
+
   if (!result.mSourceSurface) {
-     // If the element doesn't have a context then we won't get a snapshot. The canvas spec wants us to not error and just
-     // draw nothing, so return an empty surface.
-     DrawTarget *ref = aTarget ? aTarget : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
-     RefPtr<DrawTarget> dt = ref->CreateSimilarDrawTarget(IntSize(size.width, size.height),
-                                                          SurfaceFormat::B8G8R8A8);
-     if (dt) {
-       result.mSourceSurface = dt->Snapshot();
-     }
-  } else if (aTarget) {
-    RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
-    if (opt) {
-      result.mSourceSurface = opt;
+    nsRefPtr<gfxContext> ctx;
+    RefPtr<DrawTarget> dt;
+    if (premultAlpha) {
+      if (aTarget) {
+        dt = aTarget->CreateSimilarDrawTarget(IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8);
+      } else {
+        dt = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(size.width, size.height),
+                                                                          SurfaceFormat::B8G8R8A8);
+      }
+      if (!dt) {
+        return result;
+      }
+      ctx = new gfxContext(dt);
+    } else {
+      // TODO: RenderContextsExternal expects to get a gfxImageFormat
+      // so that it can un-premultiply.
+      RefPtr<DataSourceSurface> data = Factory::CreateDataSourceSurface(IntSize(size.width, size.height),
+                                                                        SurfaceFormat::B8G8R8A8);
+      memset(data->GetData(), 0, data->Stride() * size.height);
+      result.mSourceSurface = data;
+      nsRefPtr<gfxImageSurface> image = new gfxImageSurface(data->GetData(),
+                                                            gfxIntSize(size.width, size.height),
+                                                            data->Stride(),
+                                                            gfxImageFormat::ARGB32);
+      ctx = new gfxContext(image);
+    }
+    // XXX shouldn't use the external interface, but maybe we can layerify this
+    uint32_t flags = premultAlpha ? HTMLCanvasElement::RenderFlagPremultAlpha : 0;
+    rv = aElement->RenderContextsExternal(ctx, GraphicsFilter::FILTER_NEAREST, flags);
+    if (NS_FAILED(rv))
+      return result;
+
+    if (premultAlpha) {
+      result.mSourceSurface = dt->Snapshot();
     }
   }
 
   // Ensure that any future changes to the canvas trigger proper invalidation,
   // in case this is being used by -moz-element()
   aElement->MarkContextClean();
 
   result.mSize = size;
@@ -5490,17 +5512,17 @@ nsLayoutUtils::SurfaceFromElement(HTMLCa
 
 nsLayoutUtils::SurfaceFromElementResult
 nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement,
                                   uint32_t aSurfaceFlags,
                                   DrawTarget* aTarget)
 {
   SurfaceFromElementResult result;
 
-  NS_WARN_IF_FALSE((aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) == 0, "We can't support non-premultiplied alpha for video!");
+  NS_WARN_IF_FALSE((aSurfaceFlags & SFE_NO_PREMULTIPLY_ALPHA) == 0, "We can't support non-premultiplied alpha for video!");
 
   uint16_t readyState;
   if (NS_SUCCEEDED(aElement->GetReadyState(&readyState)) &&
       (readyState == nsIDOMHTMLMediaElement::HAVE_NOTHING ||
        readyState == nsIDOMHTMLMediaElement::HAVE_METADATA)) {
     result.mIsStillLoading = true;
     return result;
   }
@@ -5514,23 +5536,16 @@ nsLayoutUtils::SurfaceFromElement(HTMLVi
   if (!container)
     return result;
 
   mozilla::gfx::IntSize size;
   result.mSourceSurface = container->GetCurrentAsSourceSurface(&size);
   if (!result.mSourceSurface)
     return result;
 
-  if (aTarget) {
-    RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
-    if (opt) {
-      result.mSourceSurface = opt;
-    }
-  }
-
   result.mCORSUsed = aElement->GetCORSMode() != CORS_NONE;
   result.mSize = ThebesIntSize(size);
   result.mPrincipal = principal.forget();
   result.mIsWriteOnly = false;
 
   return result;
 }
 
@@ -6489,20 +6504,17 @@ nsLayoutUtils::WantSubAPZC()
      wantSubAPZC = false;
    }
 #endif
    return wantSubAPZC;
  }
 
 nsLayoutUtils::SurfaceFromElementResult::SurfaceFromElementResult()
   // Use safe default values here
-  : mIsWriteOnly(true)
-  , mIsStillLoading(false)
-  , mCORSUsed(false)
-  , mIsPremultiplied(true)
+  : mIsWriteOnly(true), mIsStillLoading(false), mCORSUsed(false)
 {
 }
 
 bool
 nsLayoutUtils::IsNonWrapperBlock(nsIFrame* aFrame)
 {
   return GetAsBlock(aFrame) && !aFrame->IsBlockWrapper();
 }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1690,20 +1690,20 @@ public:
   enum {
     /* When creating a new surface, create an image surface */
     SFE_WANT_IMAGE_SURFACE = 1 << 0,
     /* Whether to extract the first frame (as opposed to the
        current frame) in the case that the element is an image. */
     SFE_WANT_FIRST_FRAME = 1 << 1,
     /* Whether we should skip colorspace/gamma conversion */
     SFE_NO_COLORSPACE_CONVERSION = 1 << 2,
-    /* Specifies that the caller wants unpremultiplied pixel data.
-       If this is can be done efficiently, the result will be a
-       DataSourceSurface and mIsPremultiplied with be set to false. */
-    SFE_PREFER_NO_PREMULTIPLY_ALPHA = 1 << 3,
+    /* Whether we should skip premultiplication -- the resulting
+       image will always be an image surface, and must not be given to
+       Thebes for compositing! */
+    SFE_NO_PREMULTIPLY_ALPHA = 1 << 3,
     /* Whether we should skip getting a surface for vector images and
        return a DirectDrawInfo containing an imgIContainer instead. */
     SFE_NO_RASTERIZING_VECTORS = 1 << 4
   };
 
   struct DirectDrawInfo {
     /* imgIContainer to directly draw to a context */
     nsCOMPtr<imgIContainer> mImgContainer;
@@ -1731,18 +1731,16 @@ public:
     nsCOMPtr<imgIRequest> mImageRequest;
     /* Whether the element was "write only", that is, the bits should not be exposed to content */
     bool mIsWriteOnly;
     /* Whether the element was still loading.  Some consumers need to handle
        this case specially. */
     bool mIsStillLoading;
     /* Whether the element used CORS when loading. */
     bool mCORSUsed;
-    /* Whether the returned image contains premultiplied pixel data */
-    bool mIsPremultiplied;
   };
 
   static SurfaceFromElementResult SurfaceFromElement(mozilla::dom::Element *aElement,
                                                      uint32_t aSurfaceFlags = 0,
                                                      DrawTarget *aTarget = nullptr);
   static SurfaceFromElementResult SurfaceFromElement(nsIImageLoadingContent *aElement,
                                                      uint32_t aSurfaceFlags = 0,
                                                      DrawTarget *aTarget = nullptr);