Bug 967895 - Add an option to return a placeholder when extracting image data (Tor 6253). r=jrmuizel
authorChung-Sheng Fu <cfu@mozilla.com>
Tue, 22 Aug 2017 11:12:49 +0800
changeset 386102 96d4c5d83b4cb1e33b58007aee8216d40beaf99b
parent 386101 0c8403512a191485985a14707bf35c0a9060dfe6
child 386103 1e1c64f987b708e95a62beb39313ff6c637287de
push id32675
push userarchaeopteryx@coole-files.de
push dateFri, 13 Oct 2017 21:36:21 +0000
treeherdermozilla-central@684b9ee0468e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs967895
milestone58.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 967895 - Add an option to return a placeholder when extracting image data (Tor 6253). r=jrmuizel MozReview-Commit-ID: 1zTOUL7CZ1E
dom/base/ImageEncoder.cpp
dom/base/ImageEncoder.h
--- a/dom/base/ImageEncoder.cpp
+++ b/dom/base/ImageEncoder.cpp
@@ -150,51 +150,55 @@ public:
   EncodingRunnable(const nsAString& aType,
                    const nsAString& aOptions,
                    UniquePtr<uint8_t[]> aImageBuffer,
                    layers::Image* aImage,
                    imgIEncoder* aEncoder,
                    EncodingCompleteEvent* aEncodingCompleteEvent,
                    int32_t aFormat,
                    const nsIntSize aSize,
+                   bool aUsePlaceholder,
                    bool aUsingCustomOptions)
     : Runnable("EncodingRunnable")
     , mType(aType)
     , mOptions(aOptions)
     , mImageBuffer(Move(aImageBuffer))
     , mImage(aImage)
     , mEncoder(aEncoder)
     , mEncodingCompleteEvent(aEncodingCompleteEvent)
     , mFormat(aFormat)
     , mSize(aSize)
+    , mUsePlaceholder(aUsePlaceholder)
     , mUsingCustomOptions(aUsingCustomOptions)
   {}
 
   nsresult ProcessImageData(uint64_t* aImgSize, void** aImgData)
   {
     nsCOMPtr<nsIInputStream> stream;
     nsresult rv = ImageEncoder::ExtractDataInternal(mType,
                                                     mOptions,
                                                     mImageBuffer.get(),
                                                     mFormat,
                                                     mSize,
+                                                    mUsePlaceholder,
                                                     mImage,
                                                     nullptr,
                                                     nullptr,
                                                     getter_AddRefs(stream),
                                                     mEncoder);
 
     // If there are unrecognized custom parse options, we should fall back to
     // the default values for the encoder without any options at all.
     if (rv == NS_ERROR_INVALID_ARG && mUsingCustomOptions) {
       rv = ImageEncoder::ExtractDataInternal(mType,
                                              EmptyString(),
                                              mImageBuffer.get(),
                                              mFormat,
                                              mSize,
+                                             mUsePlaceholder,
                                              mImage,
                                              nullptr,
                                              nullptr,
                                              getter_AddRefs(stream),
                                              mEncoder);
     }
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -234,47 +238,51 @@ private:
   nsAutoString mType;
   nsAutoString mOptions;
   UniquePtr<uint8_t[]> mImageBuffer;
   RefPtr<layers::Image> mImage;
   nsCOMPtr<imgIEncoder> mEncoder;
   RefPtr<EncodingCompleteEvent> mEncodingCompleteEvent;
   int32_t mFormat;
   const nsIntSize mSize;
+  bool mUsePlaceholder;
   bool mUsingCustomOptions;
 };
 
 NS_IMPL_ISUPPORTS_INHERITED0(EncodingRunnable, Runnable);
 
 StaticRefPtr<nsIThreadPool> ImageEncoder::sThreadPool;
 
 /* static */
 nsresult
 ImageEncoder::ExtractData(nsAString& aType,
                           const nsAString& aOptions,
                           const nsIntSize aSize,
+                          bool aUsePlaceholder,
                           nsICanvasRenderingContextInternal* aContext,
                           layers::AsyncCanvasRenderer* aRenderer,
                           nsIInputStream** aStream)
 {
   nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
   if (!encoder) {
     return NS_IMAGELIB_ERROR_NO_ENCODER;
   }
 
-  return ExtractDataInternal(aType, aOptions, nullptr, 0, aSize, nullptr,
+  return ExtractDataInternal(aType, aOptions, nullptr, 0, aSize,
+                             aUsePlaceholder, nullptr,
                              aContext, aRenderer, aStream, encoder);
 }
 
 /* static */
 nsresult
 ImageEncoder::ExtractDataFromLayersImageAsync(nsAString& aType,
                                               const nsAString& aOptions,
                                               bool aUsingCustomOptions,
                                               layers::Image* aImage,
+                                              bool aUsePlaceholder,
                                               EncodeCompleteCallback* aEncodeCallback)
 {
   nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
   if (!encoder) {
     return NS_IMAGELIB_ERROR_NO_ENCODER;
   }
 
   nsresult rv = EnsureThreadPool();
@@ -289,28 +297,30 @@ ImageEncoder::ExtractDataFromLayersImage
   nsCOMPtr<nsIRunnable> event = new EncodingRunnable(aType,
                                                      aOptions,
                                                      nullptr,
                                                      aImage,
                                                      encoder,
                                                      completeEvent,
                                                      imgIEncoder::INPUT_FORMAT_HOSTARGB,
                                                      size,
+                                                     aUsePlaceholder,
                                                      aUsingCustomOptions);
   return sThreadPool->Dispatch(event, NS_DISPATCH_NORMAL);
 }
 
 /* static */
 nsresult
 ImageEncoder::ExtractDataAsync(nsAString& aType,
                                const nsAString& aOptions,
                                bool aUsingCustomOptions,
                                UniquePtr<uint8_t[]> aImageBuffer,
                                int32_t aFormat,
                                const nsIntSize aSize,
+                               bool aUsePlaceholder,
                                EncodeCompleteCallback* aEncodeCallback)
 {
   nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
   if (!encoder) {
     return NS_IMAGELIB_ERROR_NO_ENCODER;
   }
 
   nsresult rv = EnsureThreadPool();
@@ -324,16 +334,17 @@ ImageEncoder::ExtractDataAsync(nsAString
   nsCOMPtr<nsIRunnable> event = new EncodingRunnable(aType,
                                                      aOptions,
                                                      Move(aImageBuffer),
                                                      nullptr,
                                                      encoder,
                                                      completeEvent,
                                                      aFormat,
                                                      aSize,
+                                                     aUsePlaceholder,
                                                      aUsingCustomOptions);
   return sThreadPool->Dispatch(event, NS_DISPATCH_NORMAL);
 }
 
 /*static*/ nsresult
 ImageEncoder::GetInputStream(int32_t aWidth,
                              int32_t aHeight,
                              uint8_t* aImageBuffer,
@@ -354,54 +365,55 @@ ImageEncoder::GetInputStream(int32_t aWi
 
 /* static */
 nsresult
 ImageEncoder::ExtractDataInternal(const nsAString& aType,
                                   const nsAString& aOptions,
                                   uint8_t* aImageBuffer,
                                   int32_t aFormat,
                                   const nsIntSize aSize,
+                                  bool aUsePlaceholder,
                                   layers::Image* aImage,
                                   nsICanvasRenderingContextInternal* aContext,
                                   layers::AsyncCanvasRenderer* aRenderer,
                                   nsIInputStream** aStream,
                                   imgIEncoder* aEncoder)
 {
   if (aSize.IsEmpty()) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsCOMPtr<nsIInputStream> imgStream;
 
   // get image bytes
   nsresult rv;
-  if (aImageBuffer) {
+  if (aImageBuffer && !aUsePlaceholder) {
     if (BufferSizeFromDimensions(aSize.width, aSize.height, 4) == 0) {
       return NS_ERROR_INVALID_ARG;
     }
 
     rv = ImageEncoder::GetInputStream(
       aSize.width,
       aSize.height,
       aImageBuffer,
       aFormat,
       aEncoder,
       nsPromiseFlatString(aOptions).get(),
       getter_AddRefs(imgStream));
-  } else if (aContext) {
+  } else if (aContext && !aUsePlaceholder) {
     NS_ConvertUTF16toUTF8 encoderType(aType);
     rv = aContext->GetInputStream(encoderType.get(),
                                   nsPromiseFlatString(aOptions).get(),
                                   getter_AddRefs(imgStream));
-  } else if (aRenderer) {
+  } else if (aRenderer && !aUsePlaceholder) {
     NS_ConvertUTF16toUTF8 encoderType(aType);
     rv = aRenderer->GetInputStream(encoderType.get(),
                                    nsPromiseFlatString(aOptions).get(),
                                    getter_AddRefs(imgStream));
-  } else if (aImage) {
+  } else if (aImage && !aUsePlaceholder) {
     // It is safe to convert PlanarYCbCr format from YUV to RGB off-main-thread.
     // Other image formats could have problem to convert format off-main-thread.
     // So here it uses a help function GetBRGADataSourceSurfaceSync() to convert
     // format on main thread.
     if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
       nsTArray<uint8_t> data;
       layers::PlanarYCbCrImage* ycbcrImage = static_cast<layers::PlanarYCbCrImage*> (aImage);
       gfxImageFormat format = SurfaceFormat::A8R8G8B8_UINT32;
@@ -467,16 +479,20 @@ ImageEncoder::ExtractDataInternal(const 
     if (NS_WARN_IF(!emptyCanvas)) {
       return NS_ERROR_INVALID_ARG;
     }
 
     DataSourceSurface::MappedSurface map;
     if (!emptyCanvas->Map(DataSourceSurface::MapType::WRITE, &map)) {
       return NS_ERROR_INVALID_ARG;
     }
+    if (aUsePlaceholder) {
+      // If placeholder data was requested, return all-white, opaque image data.
+      memset(map.mData, 0xFF, 4 * aSize.width * aSize.height);
+    }
     rv = aEncoder->InitFromData(map.mData,
                                 aSize.width * aSize.height * 4,
                                 aSize.width,
                                 aSize.height,
                                 aSize.width * 4,
                                 imgIEncoder::INPUT_FORMAT_HOSTARGB,
                                 aOptions);
     emptyCanvas->Unmap();
--- a/dom/base/ImageEncoder.h
+++ b/dom/base/ImageEncoder.h
@@ -37,16 +37,17 @@ public:
   // represented by aContext. aType may change to "image/png" if we had to fall
   // back to a PNG encoder. A return value of NS_OK implies successful data
   // extraction. If there are any unrecognized custom parse options in
   // aOptions, NS_ERROR_INVALID_ARG will be returned. When encountering this
   // error it is usual to call this function again without any options at all.
   static nsresult ExtractData(nsAString& aType,
                               const nsAString& aOptions,
                               const nsIntSize aSize,
+                              bool aUsePlaceholder,
                               nsICanvasRenderingContextInternal* aContext,
                               layers::AsyncCanvasRenderer* aRenderer,
                               nsIInputStream** aStream);
 
   // Extracts data asynchronously. aType may change to "image/png" if we had to
   // fall back to a PNG encoder. aOptions are the options to be passed to the
   // encoder and aUsingCustomOptions specifies whether custom parse options were
   // used (i.e. by using -moz-parse-options). If there are any unrecognized
@@ -58,27 +59,29 @@ public:
   // Note: The callback has to set a valid parent for content for the generated
   // Blob object.
   static nsresult ExtractDataAsync(nsAString& aType,
                                    const nsAString& aOptions,
                                    bool aUsingCustomOptions,
                                    UniquePtr<uint8_t[]> aImageBuffer,
                                    int32_t aFormat,
                                    const nsIntSize aSize,
+                                   bool aUsePlaceholder,
                                    EncodeCompleteCallback* aEncodeCallback);
 
   // Extract an Image asynchronously. Its function is same as ExtractDataAsync
   // except for the parameters. aImage is the uncompressed data. aEncodeCallback
   // will be called on main thread when encoding process is success.
   // Note: The callback has to set a valid parent for content for the generated
   // Blob object.
   static nsresult ExtractDataFromLayersImageAsync(nsAString& aType,
                                                   const nsAString& aOptions,
                                                   bool aUsingCustomOptions,
                                                   layers::Image* aImage,
+                                                  bool aUsePlaceholder,
                                                   EncodeCompleteCallback* aEncodeCallback);
 
   // Gives you a stream containing the image represented by aImageBuffer.
   // The format is given in aFormat, for example
   // imgIEncoder::INPUT_FORMAT_HOSTARGB.
   static nsresult GetInputStream(int32_t aWidth,
                                  int32_t aHeight,
                                  uint8_t* aImageBuffer,
@@ -90,16 +93,17 @@ public:
 private:
   // When called asynchronously, aContext and aRenderer are null.
   static nsresult
   ExtractDataInternal(const nsAString& aType,
                       const nsAString& aOptions,
                       uint8_t* aImageBuffer,
                       int32_t aFormat,
                       const nsIntSize aSize,
+                      bool aUsePlaceholder,
                       layers::Image* aImage,
                       nsICanvasRenderingContextInternal* aContext,
                       layers::AsyncCanvasRenderer* aRenderer,
                       nsIInputStream** aStream,
                       imgIEncoder* aEncoder);
 
   // Creates and returns an encoder instance of the type specified in aType.
   // aType may change to "image/png" if no instance of the original type could