Chromium Code Reviews| 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()); |
| } |