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 c1cb64a471998ea3f1508f3306a180c6237de77a..87ee6f51f9d6b6496b3bff13891db67346fbffe4 100644 |
| --- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
| +++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp |
| @@ -11,6 +11,8 @@ |
| #include "platform/image-decoders/ImageDecoder.h" |
| #include "third_party/skia/include/core/SkCanvas.h" |
| #include "third_party/skia/include/core/SkSurface.h" |
| +#include "ui/gfx/icc_profile.h" |
| +#include "ui/gfx/color_space.h" |
| #include "wtf/CheckedNumeric.h" |
| #include "wtf/PtrUtil.h" |
| #include "wtf/RefPtr.h" |
| @@ -232,6 +234,73 @@ static sk_sp<SkImage> unPremulSkImageToPremul(SkImage* input) { |
| static_cast<unsigned>(input->width()) * info.bytesPerPixel()); |
| } |
| +static sk_sp<SkImage> applyColorSpaceConversion( |
| + sk_sp<SkImage> image, |
| + bool premultiplyAlpha, |
| + const ImageBitmapOptions* options) { |
| + // Valid values for colorSpaceConversion are "default", "srgb" and |
| + // "linear-rgb" here. |
| + if (options->colorSpaceConversion() != "default" && |
| + options->colorSpaceConversion() != "srgb" && |
| + options->colorSpaceConversion() != "linear-rgb") { |
| + NOTREACHED() << "Invalid ImageBitmap creation attribute colorConversionSpace: " |
| + << options->colorSpaceConversion(); |
| + return image; |
| + } |
| + |
| + bool colorCorrectRendering = |
| + RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() && |
| + RuntimeEnabledFeatures::colorCorrectRenderingEnabled(); |
| + |
| + // If color correct rendering is not set, only "default" is accepted here. |
| + if (options->colorSpaceConversion() != "default" && |
| + !colorCorrectRendering) { |
| + NOTREACHED() << "Invalid ImageBitmap creation attribute colorConversionSpace in\ |
| + not-color-corrected mode: " |
| + << options->colorSpaceConversion(); |
| + return image; |
| + } |
| + |
| + SkImageInfo imageInfo; |
| + // If color space conversion is default and color correct rendering is |
| + // not set, color correct the image to display color space. |
| + // For now we assume 8 bit per channel for display. This must be fixed |
| + // to properly support color space conversion on HDR displays. |
| + if (options->colorSpaceConversion() == "default" && |
| + !colorCorrectRendering) { |
|
ccameron
2016/11/21 22:11:36
Ah -- as soon as https://codereview.chromium.org/2
|
| + gfx::ICCProfile iccProfile = gfx::ICCProfile::FromBestMonitor(); |
| + gfx::ColorSpace gfxColorSpace = iccProfile.GetColorSpace(); |
| + sk_sp<SkColorSpace> colorSpace = |
| + (gfxColorSpace != gfx::ColorSpace()) ? |
| + gfxColorSpace.ToSkColorSpace() : |
| + SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); |
| + imageInfo = SkImageInfo::Make( |
| + image->width(), image->height(), |
| + SkColorType::kN32_SkColorType, |
| + SkAlphaType::kPremul_SkAlphaType, |
| + colorSpace); |
| + |
| + // If color space conversion is default and color correct rendering is |
| + // set, color correct the image to sRGB. |
| + } else if (options->colorSpaceConversion() == "default" || |
| + options->colorSpaceConversion() == "srgb") { |
| + imageInfo = SkImageInfo::MakeS32( |
| + image->width(), image->height(), |
| + SkAlphaType::kPremul_SkAlphaType); |
| + |
| + } else if (options->colorSpaceConversion() == "linear-rgb") { |
| + imageInfo = SkImageInfo::Make( |
| + image->width(), image->height(), |
| + SkColorType::kRGBA_F16_SkColorType, |
| + SkAlphaType::kPremul_SkAlphaType, |
| + SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named)); |
| + } |
| + |
| + sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo); |
| + surface->getCanvas()->drawImage(image, 0, 0); |
| + return surface->makeImageSnapshot(); |
| +} |
| + |
| sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( |
| std::unique_ptr<ImageDecoder> decoder) { |
| if (!decoder->frameCount()) |
| @@ -277,7 +346,9 @@ static PassRefPtr<StaticBitmapImage> cropImage( |
| const ParsedOptions& parsedOptions, |
| AlphaDisposition imageFormat = PremultiplyAlpha, |
| ImageDecoder::ColorSpaceOption colorSpaceOp = |
| - ImageDecoder::ColorSpaceApplied) { |
| + ImageDecoder::ColorSpaceApplied, |
| + const ImageBitmapOptions* imageBitmapOptions = nullptr) { |
| + |
| ASSERT(image); |
| IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); |
| const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); |
| @@ -296,9 +367,10 @@ static PassRefPtr<StaticBitmapImage> cropImage( |
| return nullptr; |
| RefPtr<Uint8Array> dstPixels = |
| Uint8Array::create(dstBuffer, 0, dstBuffer->byteLength()); |
| - return StaticBitmapImage::create(newSkImageFromRaster( |
| - info, std::move(dstPixels), |
| - static_cast<unsigned>(info.width()) * info.bytesPerPixel())); |
| + sk_sp<SkImage> croppedImage = newSkImageFromRaster( |
| + info, std::move(dstPixels), |
| + static_cast<size_t>(info.width()) * info.bytesPerPixel()); |
| + return StaticBitmapImage::create(croppedImage); |
| } |
| sk_sp<SkImage> skiaImage = image->imageForCurrentFrame(); |
| @@ -322,6 +394,11 @@ static PassRefPtr<StaticBitmapImage> cropImage( |
| if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { |
| sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); |
| + if (colorSpaceOp == ImageDecoder::ColorSpaceApplied) |
| + croppedSkImage = applyColorSpaceConversion( |
| + croppedSkImage, |
| + parsedOptions.premultiplyAlpha, |
| + imageBitmapOptions); |
| if (parsedOptions.flipY) |
| return StaticBitmapImage::create(flipSkImageVertically( |
| croppedSkImage.get(), parsedOptions.premultiplyAlpha |
| @@ -337,6 +414,9 @@ static PassRefPtr<StaticBitmapImage> cropImage( |
| return StaticBitmapImage::create(std::move(croppedSkImage)); |
| } |
| + // Currently ImageDecoder assumes at most 8 bits per channel for the decoded |
| + // image. When this is fixed, we should change this code to create the |
| + // surface according to the color depth of the decoded image. |
| sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( |
| parsedOptions.resizeWidth, parsedOptions.resizeHeight); |
| if (!surface) |
| @@ -369,6 +449,11 @@ static PassRefPtr<StaticBitmapImage> cropImage( |
| } |
| skiaImage = surface->makeImageSnapshot(); |
| + if (colorSpaceOp == ImageDecoder::ColorSpaceApplied) |
| + skiaImage = applyColorSpaceConversion(skiaImage, |
| + parsedOptions.premultiplyAlpha, |
| + imageBitmapOptions); |
| + |
| if (parsedOptions.premultiplyAlpha) { |
| if (imageFormat == DontPremultiplyAlpha) |
| return StaticBitmapImage::create( |
| @@ -393,7 +478,7 @@ ImageBitmap::ImageBitmap(HTMLImageElement* image, |
| ImageDecoder::ColorSpaceIgnored); |
| } else { |
| m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, |
| - ImageDecoder::ColorSpaceApplied); |
| + ImageDecoder::ColorSpaceApplied, &options); |
| } |
| if (!m_image) |
| return; |