Index: third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
index c7348a846eba46ffd10fd41e291155fc90e3dc5f..b3e1e9ff4b4331e3a0e5c79d0eaa903b15fb995d 100644 |
--- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
+++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
@@ -7,13 +7,30 @@ |
#include "core/html/HTMLCanvasElement.h" |
#include "core/html/HTMLVideoElement.h" |
#include "core/html/ImageData.h" |
+#include "platform/image-decoders/ImageDecoder.h" |
#include "third_party/skia/include/core/SkSurface.h" |
#include "wtf/RefPtr.h" |
namespace blink { |
static const char* imageOrientationFlipY = "flipY"; |
+static const char* imageBitmapOptionNone = "none"; |
+static void parseOptions(const ImageBitmapOptions& options, bool& imageOrientationFlipYFlag, bool& premultiplyAlphaEnabledFlag) |
+{ |
+ if (options.imageOrientation() == imageOrientationFlipY) |
+ imageOrientationFlipYFlag = true; |
+ else |
+ imageOrientationFlipYFlag = false; |
+ ASSERT(options.imageOrientation() == imageBitmapOptionNone); |
Justin Novosad
2016/02/05 22:33:01
The assert goes in the 'else'. You need to use bra
xidachen
2016/02/06 01:18:41
Acknowledged.
|
+ if (options.premultiplyAlpha() == imageBitmapOptionNone) |
+ premultiplyAlphaEnabledFlag = false; |
+ else |
+ premultiplyAlphaEnabledFlag = true; |
+ ASSERT(options.premultiplyAlpha() == "default"); |
Justin Novosad
2016/02/05 22:33:01
same here
xidachen
2016/02/06 01:18:41
Acknowledged.
|
+} |
+ |
+// The following two functions are helpers used in cropImage |
static inline IntRect normalizeRect(const IntRect& rect) |
{ |
return IntRect(std::min(rect.x(), rect.maxX()), |
@@ -22,7 +39,13 @@ static inline IntRect normalizeRect(const IntRect& rect) |
std::max(rect.height(), -rect.height())); |
} |
-// TODO(xidachen): this function needs to be changed later on when implementing premultiplyAlpha option |
+static bool frameIsValid(const SkBitmap& frameBitmap) |
+{ |
+ ASSERT(!frameBitmap.isNull() && !frameBitmap.empty()); |
+ return frameBitmap.isImmutable() |
+ && frameBitmap.colorType() == kN32_SkColorType; |
+} |
+ |
static SkImage* flipSkImageVertically(SkImage* input) |
{ |
int width = input->width(); |
@@ -41,21 +64,57 @@ static SkImage* flipSkImageVertically(SkImage* input) |
return SkImage::NewRasterCopy(info, imagePixels.get(), imageRowBytes); |
} |
-static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& cropRect, bool flipYEnabled) |
+// TODO(xidachen): the part of read an SkImage to a OwnPtr<uint8_t[]> has been used in multiple places, |
+// we should write it as a utility function here. |
+static SkImage* premulSkImageToUnPremul(SkImage* input) |
+{ |
+ int width = input->width(); |
+ int height = input->height(); |
+ SkImageInfo info = SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType); |
+ OwnPtr<uint8_t[]> dstPixels = adoptArrayPtr(new uint8_t[width * height * info.bytesPerPixel()]); |
+ size_t dstRowBytes = info.bytesPerPixel() * width; |
+ input->readPixels(info, dstPixels.get(), dstRowBytes, 0, 0); |
+ return SkImage::NewRasterCopy(info, dstPixels.get(), dstRowBytes); |
+} |
+ |
+static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& cropRect, bool flipYEnabled, bool premultiplyAlphaEnabled) |
{ |
ASSERT(image); |
IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); |
const IntRect srcRect = intersection(imgRect, cropRect); |
+ RefPtr<SkImage> skiaImage = image->imageForCurrentFrame(); |
+ // Attempt to get raw unpremultiplied image data. |
+ if (((!premultiplyAlphaEnabled && !skiaImage->isOpaque()) || !skiaImage) && image->data()) { |
+ // TODO(xidachen): GammaAndColorProfileApplied needs to be changed when working on color-space conversion |
+ OwnPtr<ImageDecoder> decoder(ImageDecoder::create( |
+ *(image->data()), ImageDecoder::AlphaNotPremultiplied, |
+ ImageDecoder::GammaAndColorProfileApplied)); |
+ if (!decoder) |
+ return nullptr; |
+ decoder->setData(image->data(), true); |
+ if (!decoder->frameCount()) |
+ return nullptr; |
+ ImageFrame* frame = decoder->frameBufferAtIndex(0); |
+ if (!frame || frame->status() != ImageFrame::FrameComplete) |
+ return nullptr; |
+ SkBitmap bitmap = frame->bitmap(); |
+ if (!frameIsValid(bitmap)) |
+ return nullptr; |
+ ASSERT(bitmap.isImmutable()); |
+ skiaImage = adoptRef(SkImage::NewFromBitmap(bitmap)); |
+ } |
+ |
if (cropRect == srcRect) { |
if (flipYEnabled) |
- return StaticBitmapImage::create(adoptRef(flipSkImageVertically(image->imageForCurrentFrame()->newSubset(srcRect)))); |
- return StaticBitmapImage::create(adoptRef(image->imageForCurrentFrame()->newSubset(srcRect))); |
+ return StaticBitmapImage::create(adoptRef(flipSkImageVertically(skiaImage->newSubset(srcRect)))); |
+ return StaticBitmapImage::create(adoptRef(skiaImage->newSubset(srcRect))); |
} |
RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul(cropRect.width(), cropRect.height())); |
- |
+ // In the case where cropRect doesn't intesect the source image, we return a premultiplied transparent black SkImage. |
+ // If we decide we want to grab meta data from m_image, we have to change this. |
if (srcRect.isEmpty()) |
return StaticBitmapImage::create(adoptRef(surface->newImageSnapshot())); |
@@ -65,18 +124,23 @@ static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& crop |
dstLeft = -cropRect.x(); |
if (cropRect.y() < 0) |
dstTop = -cropRect.y(); |
- surface->getCanvas()->drawImage(image->imageForCurrentFrame().get(), dstLeft, dstTop); |
+ surface->getCanvas()->drawImage(skiaImage.get(), dstLeft, dstTop); |
if (flipYEnabled) |
- return StaticBitmapImage::create(adoptRef(flipSkImageVertically(surface->newImageSnapshot()))); |
- return StaticBitmapImage::create(adoptRef(surface->newImageSnapshot())); |
+ skiaImage = adoptRef(flipSkImageVertically(surface->newImageSnapshot())); |
+ else |
+ skiaImage = adoptRef(surface->newImageSnapshot()); |
+ if (premultiplyAlphaEnabled) |
+ return StaticBitmapImage::create(skiaImage); |
+ return StaticBitmapImage::create(adoptRef(premulSkImageToUnPremul(skiaImage.get()))); |
} |
ImageBitmap::ImageBitmap(HTMLImageElement* image, const IntRect& cropRect, Document* document, const ImageBitmapOptions& options) |
{ |
- if (options.imageOrientation() == imageOrientationFlipY) |
- m_image = cropImage(image->cachedImage()->image(), cropRect, true); |
- else |
- m_image = cropImage(image->cachedImage()->image(), cropRect, false); |
+ bool imageOrientationFlipYFlag; |
+ bool premultiplyAlphaEnabledFlag; |
+ parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag); |
+ |
+ m_image = cropImage(image->cachedImage()->image(), cropRect, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag); |
m_image->setOriginClean(!image->wouldTaintOrigin(document->securityOrigin())); |
} |
@@ -104,10 +168,10 @@ ImageBitmap::ImageBitmap(HTMLVideoElement* video, const IntRect& cropRect, Docum |
ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, const IntRect& cropRect, const ImageBitmapOptions& options) |
{ |
ASSERT(canvas->isPaintable()); |
- if (options.imageOrientation() == imageOrientationFlipY) |
- m_image = cropImage(canvas->copiedImage(BackBuffer, PreferAcceleration).get(), cropRect, true); |
- else |
- m_image = cropImage(canvas->copiedImage(BackBuffer, PreferAcceleration).get(), cropRect, false); |
+ bool imageOrientationFlipYFlag; |
+ bool premultiplyAlphaEnabledFlag; |
+ parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag); |
+ m_image = cropImage(canvas->copiedImage(BackBuffer, PreferAcceleration).get(), cropRect, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag); |
m_image->setOriginClean(canvas->originClean()); |
} |
@@ -138,19 +202,19 @@ ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBi |
ImageBitmap::ImageBitmap(ImageBitmap* bitmap, const IntRect& cropRect, const ImageBitmapOptions& options) |
{ |
- if (options.imageOrientation() == imageOrientationFlipY) |
- m_image = cropImage(bitmap->bitmapImage(), cropRect, true); |
- else |
- m_image = cropImage(bitmap->bitmapImage(), cropRect, false); |
+ bool imageOrientationFlipYFlag; |
+ bool premultiplyAlphaEnabledFlag; |
+ parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag); |
+ m_image = cropImage(bitmap->bitmapImage(), cropRect, imageOrientationFlipYFlag, true); |
m_image->setOriginClean(bitmap->originClean()); |
} |
ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, const IntRect& cropRect, const ImageBitmapOptions& options) |
{ |
- if (options.imageOrientation() == imageOrientationFlipY) |
- m_image = cropImage(image.get(), cropRect, true); |
- else |
- m_image = cropImage(image.get(), cropRect, false); |
+ bool imageOrientationFlipYFlag; |
+ bool premultiplyAlphaEnabledFlag; |
+ parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag); |
+ m_image = cropImage(image.get(), cropRect, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag); |
m_image->setOriginClean(image->originClean()); |
} |