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 bbfdb51187538d9e1064c0f78539065dd981ee6c..46e302449acbafa9e1d678bca504d5aec78578ba 100644 |
| --- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
| +++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
| @@ -117,16 +117,22 @@ 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, const ParsedOptions& parsedOptions, AlphaDisposition imageFormat = PremultiplyAlpha, ImageDecoder::GammaAndColorProfileOption colorSpaceOp = ImageDecoder::GammaAndColorProfileApplied) |
|
jbroman
2016/07/07 19:18:00
Can you point me at why cropRect is now an in-out
xidachen
2016/07/07 20:43:29
Changed to pass by value.
|
| { |
| ASSERT(image); |
| + // Adjust the cropRect first: in the case where cropRect is not specified in the API call, |
| + // the cropRect is assumed to be the same as the size of the (scaled) image. |
| + if (parsedOptions.shouldScaleInput && cropRect.x() == 0 && cropRect.y() == 0 && cropRect.width() == image->width() && cropRect.height() == image->height()) { |
|
jbroman
2016/07/07 19:18:00
What if the cropRect _is_ specified in the API cal
xidachen
2016/07/07 20:43:29
This cannot happen. If that is the case, then in t
jbroman
2016/07/07 21:21:45
I don't mean if sw or sh is zero, but if they matc
|
| + cropRect.setWidth(parsedOptions.resizeWidth); |
| + cropRect.setHeight(parsedOptions.resizeHeight); |
| + } |
| IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); |
| const IntRect srcRect = intersection(imgRect, cropRect); |
| // In the case when cropRect doesn't intersect the source image and it requires a umpremul image |
| // We immediately return a transparent black image with cropRect.size() |
| - if (srcRect.isEmpty() && !premultiplyAlpha) { |
| + if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) { |
| SkImageInfo info = SkImageInfo::Make(cropRect.width(), cropRect.height(), kN32_SkColorType, kUnpremul_SkAlphaType); |
| std::unique_ptr<uint8_t[]> dstPixels = wrapArrayUnique(new uint8_t[cropRect.width() * cropRect.height() * info.bytesPerPixel()]()); |
| return StaticBitmapImage::create(newSkImageFromRaster(info, std::move(dstPixels), cropRect.width() * info.bytesPerPixel())); |
| @@ -134,9 +140,9 @@ static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& crop |
| RefPtr<SkImage> skiaImage = image->imageForCurrentFrame(); |
| // Attempt to get raw unpremultiplied image data, executed only when skiaImage is premultiplied. |
| - if ((((!premultiplyAlpha && !skiaImage->isOpaque()) || !skiaImage) && image->data() && imageFormat == PremultiplyAlpha) || colorSpaceOp == ImageDecoder::GammaAndColorProfileIgnored) { |
| + if ((((!parsedOptions.premultiplyAlpha && !skiaImage->isOpaque()) || !skiaImage) && image->data() && imageFormat == PremultiplyAlpha) || colorSpaceOp == ImageDecoder::GammaAndColorProfileIgnored) { |
| std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create(*(image->data()), |
| - premultiplyAlpha ? ImageDecoder::AlphaPremultiplied : ImageDecoder::AlphaNotPremultiplied, |
| + parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied : ImageDecoder::AlphaNotPremultiplied, |
| colorSpaceOp)); |
| if (!decoder) |
| return nullptr; |
| @@ -148,10 +154,10 @@ static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& crop |
| if (cropRect == srcRect) { |
| RefPtr<SkImage> croppedSkImage = fromSkSp(skiaImage->makeSubset(srcRect)); |
| - if (flipY) |
| - return StaticBitmapImage::create(flipSkImageVertically(croppedSkImage.get(), premultiplyAlpha ? PremultiplyAlpha : DontPremultiplyAlpha)); |
| + if (parsedOptions.flipY) |
| + return StaticBitmapImage::create(flipSkImageVertically(croppedSkImage.get(), parsedOptions.premultiplyAlpha ? PremultiplyAlpha : DontPremultiplyAlpha)); |
| // Special case: The first parameter image is unpremul but we need to turn it into premul. |
| - if (premultiplyAlpha && imageFormat == DontPremultiplyAlpha) |
| + if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) |
| return StaticBitmapImage::create(unPremulSkImageToPremul(croppedSkImage.get())); |
| // Call preroll to trigger image decoding. |
| croppedSkImage->preroll(); |
| @@ -170,12 +176,19 @@ static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& crop |
| dstLeft = -cropRect.x(); |
| if (cropRect.y() < 0) |
| dstTop = -cropRect.y(); |
| - surface->getCanvas()->drawImage(skiaImage.get(), dstLeft, dstTop); |
| + if (parsedOptions.shouldScaleInput) { |
| + SkRect drawDstRect = SkRect::MakeXYWH(dstLeft, dstTop, parsedOptions.resizeWidth, parsedOptions.resizeHeight); |
| + SkPaint paint; |
| + paint.setFilterQuality(parsedOptions.resizeQuality); |
| + surface->getCanvas()->drawImageRect(skiaImage.get(), drawDstRect, &paint); |
| + } else { |
| + surface->getCanvas()->drawImage(skiaImage.get(), dstLeft, dstTop); |
| + } |
| skiaImage = fromSkSp(surface->makeImageSnapshot()); |
| - if (flipY) |
| + if (parsedOptions.flipY) |
| skiaImage = flipSkImageVertically(skiaImage.get(), PremultiplyAlpha); |
| - if (premultiplyAlpha) { |
| + if (parsedOptions.premultiplyAlpha) { |
| if (imageFormat == PremultiplyAlpha) |
| return StaticBitmapImage::create(unPremulSkImageToPremul(skiaImage.get())); |
| return StaticBitmapImage::create(skiaImage.release()); |
| @@ -183,16 +196,15 @@ 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) |
| +ImageBitmap::ImageBitmap(HTMLImageElement* image, IntRect& cropRect, Document* document, const ImageBitmapOptions& options) |
| { |
| - bool flipY; |
| - bool premultiplyAlpha; |
| - parseOptions(options, flipY, premultiplyAlpha); |
| + RefPtr<Image> input = image->cachedImage()->getImage(); |
| + ParsedOptions parsedOptions = parseOptions(options, input->width(), input->height()); |
| if (options.colorSpaceConversion() == "none") |
| - m_image = cropImage(image->cachedImage()->getImage(), cropRect, flipY, premultiplyAlpha, PremultiplyAlpha, ImageDecoder::GammaAndColorProfileIgnored); |
| + m_image = cropImage(input.get(), cropRect, parsedOptions, PremultiplyAlpha, ImageDecoder::GammaAndColorProfileIgnored); |
| else |
| - m_image = cropImage(image->cachedImage()->getImage(), cropRect, flipY, premultiplyAlpha, PremultiplyAlpha, ImageDecoder::GammaAndColorProfileApplied); |
| + m_image = cropImage(input.get(), cropRect, parsedOptions, 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 +217,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,39 +235,43 @@ 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()); |
| - // 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); |
| + bool isPremultiplyAlphaReverted = false; |
| + if (!parsedOptions.premultiplyAlpha) { |
| + parsedOptions.premultiplyAlpha = true; |
| + isPremultiplyAlphaReverted = true; |
| + } |
| + m_image = cropImage(input.get(), cropRect, parsedOptions); |
| if (!m_image) |
| return; |
| - if (!premultiplyAlpha) |
| + if (isPremultiplyAlphaReverted) { |
| + parsedOptions.premultiplyAlpha = false; |
| m_image = StaticBitmapImage::create(premulSkImageToUnPremul(m_image->imageForCurrentFrame().get())); |
| + } |
| m_image->setOriginClean(canvas->originClean()); |
| - m_image->setPremultiplied(premultiplyAlpha); |
| + m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| } |
| ImageBitmap::ImageBitmap(std::unique_ptr<uint8_t[]> data, uint32_t width, uint32_t height, bool isImageBitmapPremultiplied, bool isImageBitmapOriginClean) |
| @@ -266,15 +282,14 @@ ImageBitmap::ImageBitmap(std::unique_ptr<uint8_t[]> data, uint32_t width, uint32 |
| m_image->setOriginClean(isImageBitmapOriginClean); |
| } |
| -ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBitmapOptions& options) |
| +ImageBitmap::ImageBitmap(ImageData* data, IntRect& cropRect, const ImageBitmapOptions& options) |
| { |
| - 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(); |
| @@ -284,10 +299,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()) { |
| @@ -303,7 +318,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(); |
| @@ -319,7 +334,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); |
| return; |
| } |
| @@ -338,34 +353,35 @@ 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()); |
| + |
| + m_image = cropImage(input.get(), cropRect, parsedOptions, 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()); |
| + |
| + m_image = cropImage(input.get(), cropRect, parsedOptions, 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) |
| @@ -496,23 +512,56 @@ ScriptPromise ImageBitmap::createImageBitmap(ScriptState* scriptState, EventTarg |
| exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); |
| return ScriptPromise(); |
| } |
| + if ((options.hasResizeWidth() && options.resizeWidth() <= 0) || (options.hasResizeHeight() && options.resizeHeight() <= 0)) { |
| + exceptionState.throwDOMException(InvalidStateError, "The resizeWidth or/and resizeHeight is less than or equals to 0."); |
| + return ScriptPromise(); |
| + } |
| 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) |
|
jbroman
2016/07/07 19:18:00
width and height of what?
Suggest something like
xidachen
2016/07/07 20:43:29
Done.
|
| { |
| + 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(); |
| + parsedOptions.resizeHeight = options.resizeHeight(); |
| + } else if (options.hasResizeWidth() && !options.hasResizeHeight()) { |
| + parsedOptions.resizeWidth = options.resizeWidth(); |
| + parsedOptions.resizeHeight = ceil(static_cast<float>(options.resizeWidth()) / width * height); |
| + } else { |
| + parsedOptions.resizeHeight = options.resizeHeight(); |
| + parsedOptions.resizeWidth = ceil(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 |