Chromium Code Reviews| Index: third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp |
| diff --git a/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp b/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp |
| index 964d9b8b31bf55716ef749f8c8db29d51c9310a5..465557181529097b61437716a8892af4634b25ea 100644 |
| --- a/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp |
| +++ b/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp |
| @@ -40,9 +40,11 @@ |
| #include "platform/graphics/StaticBitmapImage.h" |
| #include "platform/graphics/skia/SkiaUtils.h" |
| #include "platform/heap/Handle.h" |
| +#include "platform/image-decoders/ImageDecoder.h" |
| #include "platform/network/ResourceRequest.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkCanvas.h" |
| +#include "third_party/skia/include/core/SkColorSpaceXform.h" |
| #include "third_party/skia/include/core/SkImage.h" |
| #include "third_party/skia/include/core/SkSurface.h" |
| @@ -61,6 +63,13 @@ class ImageBitmapTest : public ::testing::Test { |
| // Save the global memory cache to restore it upon teardown. |
| m_globalMemoryCache = replaceMemoryCacheForTesting(MemoryCache::create()); |
| + |
| + // Save the state of experimental canvas features and color correct |
| + // rendering flags to restore them on teardown. |
| + experimentalCanvasFeatures = |
| + RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled(); |
| + colorCorrectRendering = |
| + RuntimeEnabledFeatures::colorCorrectRenderingEnabled(); |
| } |
| virtual void TearDown() { |
| // Garbage collection is required prior to switching out the |
| @@ -71,10 +80,16 @@ class ImageBitmapTest : public ::testing::Test { |
| BlinkGC::ForcedGC); |
| replaceMemoryCacheForTesting(m_globalMemoryCache.release()); |
| + RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled( |
| + experimentalCanvasFeatures); |
| + RuntimeEnabledFeatures::setColorCorrectRenderingEnabled( |
| + colorCorrectRendering); |
| } |
| sk_sp<SkImage> m_image, m_image2; |
| Persistent<MemoryCache> m_globalMemoryCache; |
| + bool experimentalCanvasFeatures; |
| + bool colorCorrectRendering; |
| }; |
| TEST_F(ImageBitmapTest, ImageResourceConsistency) { |
| @@ -102,7 +117,7 @@ TEST_F(ImageBitmapTest, ImageResourceConsistency) { |
| ImageBitmap* imageBitmapOutsideCrop = ImageBitmap::create( |
| imageElement, cropRect, &(imageElement->document()), defaultOptions); |
| - ASSERT_EQ(imageBitmapNoCrop->bitmapImage()->imageForCurrentFrame(), |
| + ASSERT_NE(imageBitmapNoCrop->bitmapImage()->imageForCurrentFrame(), |
| imageElement->cachedImage()->getImage()->imageForCurrentFrame()); |
| ASSERT_NE(imageBitmapInteriorCrop->bitmapImage()->imageForCurrentFrame(), |
| imageElement->cachedImage()->getImage()->imageForCurrentFrame()); |
| @@ -127,23 +142,25 @@ TEST_F(ImageBitmapTest, ImageBitmapSourceChanged) { |
| IntRect(0, 0, m_image->width(), m_image->height()); |
| ImageBitmap* imageBitmap = ImageBitmap::create( |
| image, cropRect, &(image->document()), defaultOptions); |
| - ASSERT_EQ(imageBitmap->bitmapImage()->imageForCurrentFrame(), |
| + // As we are applying color space conversion for the "default" mode, |
| + // this verifies that the color corrected image is not the same as the |
| + // source. |
| + ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(), |
| originalImageResource->getImage()->imageForCurrentFrame()); |
| ImageResource* newImageResource = |
| ImageResource::create(StaticBitmapImage::create(m_image2).get()); |
| image->setImageResource(newImageResource); |
| - // The ImageBitmap should contain the same data as the original cached image |
| { |
| - ASSERT_EQ(imageBitmap->bitmapImage()->imageForCurrentFrame(), |
| + ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(), |
| originalImageResource->getImage()->imageForCurrentFrame()); |
| SkImage* image1 = imageBitmap->bitmapImage()->imageForCurrentFrame().get(); |
| ASSERT_NE(image1, nullptr); |
| SkImage* image2 = |
| originalImageResource->getImage()->imageForCurrentFrame().get(); |
| ASSERT_NE(image2, nullptr); |
| - ASSERT_EQ(image1, image2); |
| + ASSERT_NE(image1, image2); |
| } |
| { |
| @@ -158,4 +175,129 @@ TEST_F(ImageBitmapTest, ImageBitmapSourceChanged) { |
| } |
| } |
| +enum class ColorSpaceConversion : uint8_t { |
| + NONE = 0, |
| + DEFAULT_NOT_COLOR_CORRECTED = 1, |
| + DEFAULT_COLOR_CORRECTED = 2, |
| + SRGB = 3, |
| + LINEAR_RGB = 4, |
| + |
| + LAST = LINEAR_RGB |
| +}; |
| + |
| +static ImageBitmap* createImageBitmapWithColorSpaceConversion( |
| + HTMLImageElement* image, |
| + Optional<IntRect>& cropRect, |
| + Document* document, |
| + const ColorSpaceConversion& colorSpaceConversion) { |
| + // Set the color space conversion in ImageBitmapOptions |
| + ImageBitmapOptions options; |
| + static const Vector<String> conversions = {"none", "default", "default", |
| + "srgb", "linear-rgb"}; |
|
xidachen
2016/11/24 20:27:31
Why are we having two "default"?
zakerinasab
2016/11/24 20:51:12
We have two "default"s because there are two defau
|
| + options.setColorSpaceConversion( |
| + conversions[static_cast<uint8_t>(colorSpaceConversion)]); |
| + |
| + // Set the runtime flags |
| + bool runtimeFlag = (colorSpaceConversion != |
| + ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED); |
| + RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(runtimeFlag); |
| + RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(runtimeFlag); |
| + |
| + // Create and return the ImageBitmap |
| + return ImageBitmap::create(image, cropRect, &(image->document()), options); |
| +} |
| + |
| +TEST_F(ImageBitmapTest, ImageBitmapColorSpaceConversion) { |
| + HTMLImageElement* imageElement = |
| + HTMLImageElement::create(*Document::create()); |
| + |
| + SkPaint p; |
| + p.setColor(SK_ColorRED); |
| + sk_sp<SkColorSpace> srcRGBColorSpace = |
| + SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); |
| + |
| + SkImageInfo rasterImageInfo = |
| + SkImageInfo::MakeN32Premul(100, 100, srcRGBColorSpace); |
| + sk_sp<SkSurface> surface(SkSurface::MakeRaster(rasterImageInfo)); |
| + surface->getCanvas()->drawCircle(50, 50, 50, p); |
| + sk_sp<SkImage> image = surface->makeImageSnapshot(); |
| + |
| + uint8_t* srcPixel = new uint8_t[rasterImageInfo.bytesPerPixel()]; |
|
xidachen
2016/11/24 20:27:31
Please use makeUnique.
zakerinasab
2016/11/24 20:51:12
Done.
|
| + image->readPixels(rasterImageInfo.makeWH(1, 1), (void*)(srcPixel), |
| + image->width() * rasterImageInfo.bytesPerPixel(), 50, 50); |
| + |
| + ImageResource* originalImageResource = |
| + ImageResource::create(StaticBitmapImage::create(image).get()); |
| + imageElement->setImageResource(originalImageResource); |
| + |
| + Optional<IntRect> cropRect = IntRect(0, 0, image->width(), image->height()); |
| + |
| + // Create and test the ImageBitmap objects. |
| + // We don't check "none" color space conversion as it requires the encoded |
| + // data in a format readable by ImageDecoder. Furthermore, the code path for |
| + // "none" color space conversion is not affected by this CL. |
| + |
| + sk_sp<SkColorSpace> colorSpace = nullptr; |
| + SkColorType colorType = SkColorType::kN32_SkColorType; |
| + SkColorSpaceXform::ColorFormat colorFormat32 = |
| + (colorType == kBGRA_8888_SkColorType) |
| + ? SkColorSpaceXform::ColorFormat::kBGRA_8888_ColorFormat |
| + : SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat; |
| + SkColorSpaceXform::ColorFormat colorFormat = colorFormat32; |
| + |
| + for (uint8_t i = (uint8_t)(ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED); |
| + i <= (uint8_t)(ColorSpaceConversion::LAST); i++) { |
| + ColorSpaceConversion colorSpaceConversion = |
| + static_cast<ColorSpaceConversion>(i); |
| + ImageBitmap* imageBitmap = createImageBitmapWithColorSpaceConversion( |
| + imageElement, cropRect, &(imageElement->document()), |
| + colorSpaceConversion); |
| + SkImage* convertedImage = |
| + imageBitmap->bitmapImage()->imageForCurrentFrame().get(); |
| + |
| + switch (colorSpaceConversion) { |
| + case ColorSpaceConversion::NONE: |
| + NOTREACHED(); |
| + break; |
| + case ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED: |
| + //colorSpace = ImageDecoder::globalTargetColorSpace(); |
| + colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); |
| + colorFormat = colorFormat32; |
| + break; |
| + case ColorSpaceConversion::DEFAULT_COLOR_CORRECTED: |
| + case ColorSpaceConversion::SRGB: |
| + colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); |
| + colorFormat = colorFormat32; |
| + break; |
| + case ColorSpaceConversion::LINEAR_RGB: |
| + colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named); |
| + colorType = SkColorType::kRGBA_F16_SkColorType; |
| + colorFormat = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| + |
| + SkImageInfo imageInfo = SkImageInfo::Make( |
| + 1, 1, colorType, SkAlphaType::kPremul_SkAlphaType, colorSpace); |
| + auto convertedPixel = makeUnique<uint8_t>(imageInfo.bytesPerPixel()); |
| + convertedImage->readPixels( |
| + imageInfo, (void*)(convertedPixel.get()), |
| + convertedImage->width() * imageInfo.bytesPerPixel(), 50, 50); |
| + |
| + // Transform the source pixel and check if the image bitmap color conversion |
| + // is done correctly. |
| + std::unique_ptr<SkColorSpaceXform> colorSpaceXform = |
| + SkColorSpaceXform::New(srcRGBColorSpace.get(), colorSpace.get()); |
| + uint8_t* transformedPixel = new uint8_t[imageInfo.bytesPerPixel()]; |
|
xidachen
2016/11/24 20:27:31
Please use makeUnique.
zakerinasab
2016/11/24 20:51:12
Done.
|
| + colorSpaceXform->apply(colorFormat, (void*)(transformedPixel), |
| + colorFormat32, (void*)(srcPixel), 1, |
| + SkAlphaType::kPremul_SkAlphaType); |
| + |
| + int compare = std::memcmp(convertedPixel.get(), transformedPixel, |
| + imageInfo.bytesPerPixel()); |
| + ASSERT_EQ(compare, 0); |
| + } |
| +} |
| + |
| } // namespace blink |