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 7c0de1e9e10b593f496e058d70579b981bd201f8..af6167cc5bfd5b45de81747bd093d5e499bb481c 100644 |
| --- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
| +++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
| @@ -117,7 +117,7 @@ PassRefPtr<SkImage> ImageBitmap::getSkImageFromDecoder(std::unique_ptr<ImageDeco |
| // imageFormat = PremultiplyAlpha means the image is in premuliplied format |
| // For example, if the image is already in unpremultiplied format and we want the created ImageBitmap |
| // in the same format, then we don't need to use the ImageDecoder to decode the image. |
| -static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& cropRect, bool flipY, bool premultiplyAlpha, AlphaDisposition imageFormat = PremultiplyAlpha, ImageDecoder::GammaAndColorProfileOption colorSpaceOp = ImageDecoder::GammaAndColorProfileApplied) |
| +static PassRefPtr<StaticBitmapImage> cropImage(Image* image, IntRect& cropRect, bool flipY, bool premultiplyAlpha, AlphaDisposition imageFormat = PremultiplyAlpha, ImageDecoder::GammaAndColorProfileOption colorSpaceOp = ImageDecoder::GammaAndColorProfileApplied) |
| { |
| ASSERT(image); |
| @@ -183,16 +183,34 @@ static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& crop |
| return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); |
| } |
| -ImageBitmap::ImageBitmap(HTMLImageElement* image, const IntRect& cropRect, Document* document, const ImageBitmapOptions& options) |
| +static PassRefPtr<Image> scaleInputAndCropRect(Image* input, IntRect& cropRect, unsigned resizeWidth, unsigned resizeHeight, SkFilterQuality resizeQuality) |
| { |
| - bool flipY; |
| - bool premultiplyAlpha; |
| - parseOptions(options, flipY, premultiplyAlpha); |
| + if (cropRect.x() == 0 && cropRect.y() == 0 && cropRect.width() == input->width() && cropRect.height() == input->height()) { |
| + cropRect.setWidth(resizeWidth); |
|
jbroman
2016/06/30 18:52:34
Hmm. It seems you're setting parameters to use for
xidachen
2016/07/07 13:48:47
Done. The scale && crop are in cropImage(), and it
|
| + cropRect.setHeight(resizeHeight); |
| + } |
| + |
| + RefPtr<SkImage> skiaImage = input->imageForCurrentFrame(); |
| + sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(resizeWidth, resizeHeight); |
| + SkRect srcRect = SkRect::MakeIWH(input->width(), input->height()); |
| + SkRect dstRect = SkRect::MakeIWH(resizeWidth, resizeHeight); |
| + SkPaint paint; |
| + paint.setFilterQuality(resizeQuality); |
| + surface->getCanvas()->drawImageRect(skiaImage.get(), srcRect, dstRect, &paint); |
|
jbroman
2016/06/30 18:52:34
You should also clear the canvas to transparent be
xidachen
2016/07/07 13:48:47
This is not needed as SkSurface::MakeRaster() does
|
| + return StaticBitmapImage::create(fromSkSp(surface->makeImageSnapshot())); |
| +} |
| + |
| +ImageBitmap::ImageBitmap(HTMLImageElement* image, IntRect& cropRect, Document* document, const ImageBitmapOptions& options) |
| +{ |
| + RefPtr<Image> input = image->cachedImage()->getImage(); |
| + ParsedOptions parsedOptions = parseOptions(options, input->width(), input->height()); |
| + if (parsedOptions.shouldScaleInput) |
| + input = scaleInputAndCropRect(input.get(), cropRect, parsedOptions.resizeWidth, parsedOptions.resizeHeight, parsedOptions.resizeQuality); |
| if (options.colorSpaceConversion() == "none") |
| - m_image = cropImage(image->cachedImage()->getImage(), cropRect, flipY, premultiplyAlpha, PremultiplyAlpha, ImageDecoder::GammaAndColorProfileIgnored); |
| + m_image = cropImage(input.get(), cropRect, parsedOptions.flipY, parsedOptions.premultiplyAlpha, PremultiplyAlpha, ImageDecoder::GammaAndColorProfileIgnored); |
| else |
| - m_image = cropImage(image->cachedImage()->getImage(), cropRect, flipY, premultiplyAlpha, PremultiplyAlpha, ImageDecoder::GammaAndColorProfileApplied); |
| + m_image = cropImage(input.get(), cropRect, parsedOptions.flipY, parsedOptions.premultiplyAlpha, PremultiplyAlpha, ImageDecoder::GammaAndColorProfileApplied); |
| if (!m_image) |
| return; |
| // In the case where the source image is lazy-decoded, m_image may not be in |
| @@ -205,10 +223,10 @@ ImageBitmap::ImageBitmap(HTMLImageElement* image, const IntRect& cropRect, Docum |
| m_image = StaticBitmapImage::create(fromSkSp(surface->makeImageSnapshot())); |
| } |
| m_image->setOriginClean(!image->wouldTaintOrigin(document->getSecurityOrigin())); |
| - m_image->setPremultiplied(premultiplyAlpha); |
| + m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| } |
| -ImageBitmap::ImageBitmap(HTMLVideoElement* video, const IntRect& cropRect, Document* document, const ImageBitmapOptions& options) |
| +ImageBitmap::ImageBitmap(HTMLVideoElement* video, IntRect& cropRect, Document* document, const ImageBitmapOptions& options) |
| { |
| IntSize playerSize; |
| if (video->webMediaPlayer()) |
| @@ -223,51 +241,50 @@ ImageBitmap::ImageBitmap(HTMLVideoElement* video, const IntRect& cropRect, Docum |
| IntPoint dstPoint = IntPoint(std::max(0, -cropRect.x()), std::max(0, -cropRect.y())); |
| video->paintCurrentFrame(buffer->canvas(), IntRect(dstPoint, srcRect.size()), nullptr); |
| - bool flipY; |
| - bool premultiplyAlpha; |
| - parseOptions(options, flipY, premultiplyAlpha); |
| + // TODO(xidachen); implement the resize option. |
| + ParsedOptions parsedOptions = parseOptions(options, playerSize.width(), playerSize.height()); |
| - if (flipY || !premultiplyAlpha) { |
| + if (parsedOptions.flipY || !parsedOptions.premultiplyAlpha) { |
| RefPtr<SkImage> skiaImage = buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown); |
| - if (flipY) |
| + if (parsedOptions.flipY) |
| skiaImage = flipSkImageVertically(skiaImage.get(), PremultiplyAlpha); |
| - if (!premultiplyAlpha) |
| + if (!parsedOptions.premultiplyAlpha) |
| skiaImage = premulSkImageToUnPremul(skiaImage.get()); |
| m_image = StaticBitmapImage::create(skiaImage.release()); |
| } else { |
| m_image = StaticBitmapImage::create(buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown)); |
| } |
| m_image->setOriginClean(!video->wouldTaintOrigin(document->getSecurityOrigin())); |
| - m_image->setPremultiplied(premultiplyAlpha); |
| + m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| } |
| -ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, const IntRect& cropRect, const ImageBitmapOptions& options) |
| +ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, IntRect& cropRect, const ImageBitmapOptions& options) |
| { |
| ASSERT(canvas->isPaintable()); |
| - bool flipY; |
| - bool premultiplyAlpha; |
| - parseOptions(options, flipY, premultiplyAlpha); |
| + RefPtr<Image> input = canvas->copiedImage(BackBuffer, PreferAcceleration); |
| + ParsedOptions parsedOptions = parseOptions(options, input->width(), input->height()); |
| + if (parsedOptions.shouldScaleInput) |
| + input = scaleInputAndCropRect(input.get(), cropRect, parsedOptions.resizeWidth, parsedOptions.resizeHeight, parsedOptions.resizeQuality); |
| // canvas is always premultiplied, so set the last parameter to true and convert to un-premul later |
| - m_image = cropImage(canvas->copiedImage(BackBuffer, PreferAcceleration).get(), cropRect, flipY, true); |
| + m_image = cropImage(input.get(), cropRect, parsedOptions.flipY, true); |
| if (!m_image) |
| return; |
| - if (!premultiplyAlpha) |
| + if (!parsedOptions.premultiplyAlpha) |
| m_image = StaticBitmapImage::create(premulSkImageToUnPremul(m_image->imageForCurrentFrame().get())); |
| m_image->setOriginClean(canvas->originClean()); |
| - m_image->setPremultiplied(premultiplyAlpha); |
| + m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| } |
| // The last two parameters are used for structure-cloning. |
| -ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBitmapOptions& options, const bool& isImageDataPremultiplied, const bool& isImageDataOriginClean) |
| +ImageBitmap::ImageBitmap(ImageData* data, IntRect& cropRect, const ImageBitmapOptions& options, const bool& isImageDataPremultiplied, const bool& isImageDataOriginClean) |
| { |
| - bool flipY; |
| - bool premultiplyAlpha; |
| - parseOptions(options, flipY, premultiplyAlpha); |
| + // TODO(xidachen): implement the resize option |
| + ParsedOptions parsedOptions = parseOptions(options, data->width(), data->height()); |
| IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), data->size())); |
| // treat non-premultiplyAlpha as a special case |
| - if (!premultiplyAlpha) { |
| + if (!parsedOptions.premultiplyAlpha) { |
| unsigned char* srcAddr = data->data()->data(); |
| int srcHeight = data->size().height(); |
| int dstHeight = cropRect.height(); |
| @@ -281,10 +298,10 @@ ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBi |
| int srcPixelBytesPerRow = info.bytesPerPixel() * data->size().width(); |
| int dstPixelBytesPerRow = info.bytesPerPixel() * cropRect.width(); |
| if (cropRect == IntRect(IntPoint(), data->size())) { |
| - swizzleImageData(srcAddr, srcHeight, srcPixelBytesPerRow, flipY); |
| + swizzleImageData(srcAddr, srcHeight, srcPixelBytesPerRow, parsedOptions.flipY); |
| m_image = StaticBitmapImage::create(fromSkSp(SkImage::MakeRasterCopy(SkPixmap(info, srcAddr, dstPixelBytesPerRow)))); |
| // restore the original ImageData |
| - swizzleImageData(srcAddr, srcHeight, srcPixelBytesPerRow, flipY); |
| + swizzleImageData(srcAddr, srcHeight, srcPixelBytesPerRow, parsedOptions.flipY); |
| } else { |
| std::unique_ptr<uint8_t[]> copiedDataBuffer = wrapArrayUnique(new uint8_t[dstHeight * dstPixelBytesPerRow]()); |
| if (!srcRect.isEmpty()) { |
| @@ -300,7 +317,7 @@ ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBi |
| int srcStartCopyPosition = (i + srcPoint.y()) * srcPixelBytesPerRow + srcPoint.x() * info.bytesPerPixel(); |
| int srcEndCopyPosition = srcStartCopyPosition + copyWidth * info.bytesPerPixel(); |
| int dstStartCopyPosition; |
| - if (flipY) |
| + if (parsedOptions.flipY) |
| dstStartCopyPosition = (dstHeight -1 - dstPoint.y() - i) * dstPixelBytesPerRow + dstPoint.x() * info.bytesPerPixel(); |
| else |
| dstStartCopyPosition = (dstPoint.y() + i) * dstPixelBytesPerRow + dstPoint.x() * info.bytesPerPixel(); |
| @@ -316,7 +333,7 @@ ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBi |
| } |
| m_image = StaticBitmapImage::create(newSkImageFromRaster(info, std::move(copiedDataBuffer), dstPixelBytesPerRow)); |
| } |
| - m_image->setPremultiplied(premultiplyAlpha); |
| + m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| m_image->setOriginClean(isImageDataOriginClean); |
| return; |
| } |
| @@ -336,34 +353,39 @@ ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBi |
| if (cropRect.y() < 0) |
| dstPoint.setY(-cropRect.y()); |
| buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(), srcRect, dstPoint); |
| - if (flipY) |
| + if (parsedOptions.flipY) |
| m_image = StaticBitmapImage::create(flipSkImageVertically(buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown).get(), PremultiplyAlpha)); |
| else |
| m_image = StaticBitmapImage::create(buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown)); |
| } |
| -ImageBitmap::ImageBitmap(ImageBitmap* bitmap, const IntRect& cropRect, const ImageBitmapOptions& options) |
| +ImageBitmap::ImageBitmap(ImageBitmap* bitmap, IntRect& cropRect, const ImageBitmapOptions& options) |
| { |
| - bool flipY; |
| - bool premultiplyAlpha; |
| - parseOptions(options, flipY, premultiplyAlpha); |
| - m_image = cropImage(bitmap->bitmapImage(), cropRect, flipY, premultiplyAlpha, bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha); |
| + RefPtr<Image> input = bitmap->bitmapImage(); |
| + ParsedOptions parsedOptions = parseOptions(options, input->width(), input->height()); |
| + if (parsedOptions.shouldScaleInput) |
|
jbroman
2016/06/30 18:52:34
Could the next few lines be bundles into function
xidachen
2016/07/07 13:48:47
Done.
|
| + input = scaleInputAndCropRect(input.get(), cropRect, parsedOptions.resizeWidth, parsedOptions.resizeHeight, parsedOptions.resizeQuality); |
| + |
| + m_image = cropImage(input.get(), cropRect, parsedOptions.flipY, parsedOptions.premultiplyAlpha, bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha); |
| if (!m_image) |
| return; |
| m_image->setOriginClean(bitmap->originClean()); |
| - m_image->setPremultiplied(premultiplyAlpha); |
| + m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| } |
| -ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, const IntRect& cropRect, const ImageBitmapOptions& options) |
| +ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, IntRect& cropRect, const ImageBitmapOptions& options) |
| { |
| - bool flipY; |
| - bool premultiplyAlpha; |
| - parseOptions(options, flipY, premultiplyAlpha); |
| - m_image = cropImage(image.get(), cropRect, flipY, premultiplyAlpha, DontPremultiplyAlpha); |
| + bool originClean = image->originClean(); |
| + RefPtr<Image> input = image; |
| + ParsedOptions parsedOptions = parseOptions(options, input->width(), input->height()); |
| + if (parsedOptions.shouldScaleInput) |
| + input = scaleInputAndCropRect(input.get(), cropRect, parsedOptions.resizeWidth, parsedOptions.resizeHeight, parsedOptions.resizeQuality); |
| + |
| + m_image = cropImage(input.get(), cropRect, parsedOptions.flipY, parsedOptions.premultiplyAlpha, DontPremultiplyAlpha); |
| if (!m_image) |
| return; |
| - m_image->setOriginClean(image->originClean()); |
| - m_image->setPremultiplied(premultiplyAlpha); |
| + m_image->setOriginClean(originClean); |
| + m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| } |
| ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) |
| @@ -492,20 +514,49 @@ ScriptPromise ImageBitmap::createImageBitmap(ScriptState* scriptState, EventTarg |
| return ImageBitmapSource::fulfillImageBitmap(scriptState, create(this, IntRect(sx, sy, sw, sh), options)); |
| } |
| -void ImageBitmap::parseOptions(const ImageBitmapOptions& options, bool& flipY, bool& premultiplyAlpha) |
| +ParsedOptions ImageBitmap::parseOptions(const ImageBitmapOptions& options, const int width, const int height) |
| { |
| + ParsedOptions parsedOptions; |
| if (options.imageOrientation() == imageOrientationFlipY) { |
| - flipY = true; |
| + parsedOptions.flipY = true; |
| } else { |
| - flipY = false; |
| + parsedOptions.flipY = false; |
| ASSERT(options.imageOrientation() == imageBitmapOptionNone); |
| } |
| if (options.premultiplyAlpha() == imageBitmapOptionNone) { |
| - premultiplyAlpha = false; |
| + parsedOptions.premultiplyAlpha = false; |
| } else { |
| - premultiplyAlpha = true; |
| + parsedOptions.premultiplyAlpha = true; |
| ASSERT(options.premultiplyAlpha() == "default" || options.premultiplyAlpha() == "premultiply"); |
| } |
| + |
| + parsedOptions.shouldScaleInput = false; |
| + if (!options.hasResizeWidth() && !options.hasResizeHeight()) |
| + return parsedOptions; |
| + if (options.hasResizeWidth() && options.hasResizeHeight()) { |
| + parsedOptions.resizeWidth = options.resizeWidth(); |
|
jbroman
2016/06/30 18:52:34
What happens if one or both of these is specified,
xidachen
2016/07/07 13:48:47
Spec has been changed, now an exception is thrown
|
| + parsedOptions.resizeHeight = options.resizeHeight(); |
| + } else if (options.hasResizeWidth() && !options.hasResizeHeight()) { |
| + parsedOptions.resizeWidth = options.resizeWidth(); |
| + parsedOptions.resizeHeight = static_cast<unsigned>(static_cast<float>(options.resizeWidth()) / width * height); |
|
jbroman
2016/06/30 18:52:34
What should be happening when the computed size ba
xidachen
2016/07/07 13:48:47
Spec has been changed, so we round up to its neare
|
| + } else { |
| + parsedOptions.resizeHeight = options.resizeHeight(); |
| + parsedOptions.resizeWidth = static_cast<unsigned>(static_cast<float>(options.resizeHeight()) / height * width); |
| + } |
| + if (static_cast<int>(parsedOptions.resizeWidth) != width || static_cast<int>(parsedOptions.resizeHeight) != height) |
| + parsedOptions.shouldScaleInput = true; |
| + else |
| + return parsedOptions; |
| + |
| + if (options.resizeQuality() == "high") |
| + parsedOptions.resizeQuality = kHigh_SkFilterQuality; |
| + else if (options.resizeQuality() == "medium") |
| + parsedOptions.resizeQuality = kMedium_SkFilterQuality; |
| + else if (options.resizeQuality() == "pixelated") |
| + parsedOptions.resizeQuality = kNone_SkFilterQuality; |
| + else |
| + parsedOptions.resizeQuality = kLow_SkFilterQuality; |
| + return parsedOptions; |
| } |
| PassRefPtr<Image> ImageBitmap::getSourceImageForCanvas(SourceImageStatus* status, AccelerationHint, SnapshotReason, const FloatSize&) const |