Bug 1162282 - When canvas.drawImage is called on a corrupt image that's not in the broken state, don't throw. r=gw280
authorSeth Fowler <mark.seth.fowler@gmail.com>
Thu, 07 May 2015 09:25:10 -0700
changeset 274198 b6db7c0824d63402fec6a1685bd22cd5def8d9fe
parent 274197 aba073bd3884c727cef1424b85034eb756f2eac2
child 274199 914258721d1f01fb00e242b5b39ddd276c099daf
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw280
bugs1162282
milestone40.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 1162282 - When canvas.drawImage is called on a corrupt image that's not in the broken state, don't throw. r=gw280
dom/canvas/CanvasRenderingContext2D.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -4312,18 +4312,21 @@ CanvasRenderingContext2D::DrawImage(cons
     // for a different canvas, but CanvasImageCache should be fixed if we
     // see misses due to different elements drawing the same image.
     nsLayoutUtils::SurfaceFromElementResult res =
       CachedSurfaceFromElement(element);
     if (!res.mSourceSurface)
       res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget);
 
     if (!res.mSourceSurface && !res.mDrawInfo.mImgContainer) {
-      // Spec says to silently do nothing if the element is still loading.
-      if (!res.mIsStillLoading) {
+      // The spec says to silently do nothing in the following cases:
+      //   - The element is still loading.
+      //   - The image is bad, but it's not in the broken state (i.e., we could
+      //     decode the headers and get the size).
+      if (!res.mIsStillLoading && !res.mHasSize) {
         error.Throw(NS_ERROR_NOT_AVAILABLE);
       }
       return;
     }
 
     imgSize = res.mSize;
 
     // Scale sw/sh based on aspect ratio
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6606,16 +6606,17 @@ nsLayoutUtils::SurfaceFromElement(nsIIma
   nsCOMPtr<imgIRequest> imgRequest;
   rv = aElement->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                             getter_AddRefs(imgRequest));
   if (NS_FAILED(rv) || !imgRequest)
     return result;
 
   uint32_t status;
   imgRequest->GetImageStatus(&status);
+  result.mHasSize = status & imgIRequest::STATUS_SIZE_AVAILABLE;
   if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0) {
     // Spec says to use GetComplete, but that only works on
     // nsIDOMHTMLImageElement, and we support all sorts of other stuff
     // here.  Do this for now pending spec clarification.
     result.mIsStillLoading = (status & imgIRequest::STATUS_ERROR) == 0;
     return result;
   }
 
@@ -6726,16 +6727,17 @@ nsLayoutUtils::SurfaceFromElement(HTMLCa
       result.mSourceSurface = opt;
     }
   }
 
   // Ensure that any future changes to the canvas trigger proper invalidation,
   // in case this is being used by -moz-element()
   aElement->MarkContextClean();
 
+  result.mHasSize = true;
   result.mSize = size;
   result.mPrincipal = aElement->NodePrincipal();
   result.mIsWriteOnly = aElement->IsWriteOnly();
 
   return result;
 }
 
 nsLayoutUtils::SurfaceFromElementResult
@@ -6778,16 +6780,17 @@ nsLayoutUtils::SurfaceFromElement(HTMLVi
   if (aTarget) {
     RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
     if (opt) {
       result.mSourceSurface = opt;
     }
   }
 
   result.mCORSUsed = aElement->GetCORSMode() != CORS_NONE;
+  result.mHasSize = true;
   result.mSize = size;
   result.mPrincipal = principal.forget();
   result.mIsWriteOnly = false;
 
   return result;
 }
 
 nsLayoutUtils::SurfaceFromElementResult
@@ -7834,16 +7837,17 @@ nsLayoutUtils::IsAPZTestLoggingEnabled()
 {
   return gfxPrefs::APZTestLoggingEnabled();
 }
 
 nsLayoutUtils::SurfaceFromElementResult::SurfaceFromElementResult()
   // Use safe default values here
   : mIsWriteOnly(true)
   , mIsStillLoading(false)
+  , mHasSize(false)
   , mCORSUsed(false)
   , mIsPremultiplied(true)
 {
 }
 
 bool
 nsLayoutUtils::IsNonWrapperBlock(nsIFrame* aFrame)
 {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2012,16 +2012,18 @@ public:
     nsCOMPtr<nsIPrincipal> mPrincipal;
     /* The image request, if the element is an nsIImageLoadingContent */
     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 has a valid size. */
+    bool mHasSize;
     /* 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,