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..a17d0fd4f834e9026f5f33a9afb5930b56af5c8d 100644 |
--- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
+++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
@@ -7,13 +7,28 @@ |
#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; |
Justin Novosad
2016/02/05 14:46:41
ASSERT(options.imageOrientation() == imageBitmapOp
xidachen
2016/02/05 16:47:36
Acknowledged.
|
+ if (options.premultiplyAlpha() == imageBitmapOptionNone) |
+ premultiplyAlphaEnabledFlag = false; |
+ else |
+ premultiplyAlphaEnabledFlag = true; |
Justin Novosad
2016/02/05 14:46:41
ASSERT(options.premultiplyAlpha() == premultiplyAl
xidachen
2016/02/05 16:47:36
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 +37,14 @@ 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) |
+{ |
+ return !frameBitmap.isNull() |
+ && !frameBitmap.empty() |
+ && frameBitmap.isImmutable() |
+ && frameBitmap.colorType() == kN32_SkColorType; |
Justin Novosad
2016/02/05 14:46:41
Should some of these conditions be ASSERTs (i.e. t
xidachen
2016/02/05 16:47:36
Acknowledged.
|
+} |
+ |
static SkImage* flipSkImageVertically(SkImage* input) |
{ |
int width = input->width(); |
@@ -41,21 +63,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 +123,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 +167,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 +201,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()); |
} |