| Index: third_party/WebKit/Source/core/html/ImageDataTest.cpp | 
| diff --git a/third_party/WebKit/Source/core/html/ImageDataTest.cpp b/third_party/WebKit/Source/core/html/ImageDataTest.cpp | 
| index daa0d9af1063391c41fb3d93ed69c4188ff8f252..716b0a67ceebdd083dac2e34c0ed651174f6189b 100644 | 
| --- a/third_party/WebKit/Source/core/html/ImageDataTest.cpp | 
| +++ b/third_party/WebKit/Source/core/html/ImageDataTest.cpp | 
| @@ -7,14 +7,31 @@ | 
| #include "core/dom/ExceptionCode.h" | 
| #include "platform/geometry/IntSize.h" | 
| #include "testing/gtest/include/gtest/gtest.h" | 
| +#include "third_party/skia/include/core/SkColorSpaceXform.h" | 
|  | 
| namespace blink { | 
| namespace { | 
|  | 
| class ImageDataTest : public ::testing::Test { | 
| protected: | 
| -  ImageDataTest(){}; | 
| -  void TearDown(){}; | 
| +  virtual void SetUp() { | 
| +    // 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() { | 
| +    RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled( | 
| +        experimentalCanvasFeatures); | 
| +    RuntimeEnabledFeatures::setColorCorrectRenderingEnabled( | 
| +        colorCorrectRendering); | 
| +  } | 
| + | 
| +  bool experimentalCanvasFeatures; | 
| +  bool colorCorrectRendering; | 
| }; | 
|  | 
| TEST_F(ImageDataTest, NegativeAndZeroIntSizeTest) { | 
| @@ -50,5 +67,117 @@ TEST_F(ImageDataTest, CreateImageDataTooBig) { | 
| } | 
| } | 
|  | 
| +// Skia conversion does not guarantee to be exact, se we need to do | 
| +// approximate comparisons. | 
| +static inline bool IsNearlyTheSame(float f, float g) { | 
| +  static const float epsilonScale = 0.01f; | 
| +  return std::abs(f - g) < epsilonScale * | 
| +             std::max(std::max(std::abs(f), std::abs(g)), epsilonScale); | 
| +} | 
| + | 
| +// This test verifies the correct behavior of ImageData member function used | 
| +// to convert pixels data from canvas pixel format image data storage format. | 
| +// This function is used in BaseRenderingContext2D::getImageData. | 
| +TEST_F(ImageDataTest, TestConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat) { | 
| +  // Source pixels in RGBA32 | 
| +  unsigned char rgba32Pixels[] = {255, 0, 0, 255,       // Red | 
| +                                  0, 0, 0, 0,           // Transparent | 
| +                                  255, 192, 128, 64,    // Decreasing values | 
| +                                  93, 117, 205, 11};    // Random values | 
| +  const unsigned numColorComponents = 16; | 
| +  // Source pixels in F16 | 
| +  unsigned char* f16Pixels = new unsigned char [numColorComponents * 2]; | 
| + | 
| +  // Filling F16 source pixels | 
| +  std::unique_ptr<SkColorSpaceXform> xform = | 
| +      SkColorSpaceXform::New(SkColorSpace::MakeSRGBLinear().get(), | 
| +                             SkColorSpace::MakeSRGBLinear().get()); | 
| +  xform->apply(SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat, f16Pixels, | 
| +               SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat, rgba32Pixels, | 
| +               4, SkAlphaType::kUnpremul_SkAlphaType); | 
| + | 
| +  // Creating ArrayBufferContents objects. We need two buffers for RGBA32 data | 
| +  // because kRGBA8CanvasPixelFormat->kUint8ClampedArrayStorageFormat consumes | 
| +  // the input data parameter. | 
| +  WTF::ArrayBufferContents contentsRGBA32(numColorComponents, 1, WTF::ArrayBufferContents::NotShared, | 
| +    WTF::ArrayBufferContents::DontInitialize); | 
| +  std::memcpy(contentsRGBA32.data(), rgba32Pixels, numColorComponents); | 
| + | 
| +  WTF::ArrayBufferContents contents2RGBA32(numColorComponents, 1, WTF::ArrayBufferContents::NotShared, | 
| +    WTF::ArrayBufferContents::DontInitialize); | 
| +  std::memcpy(contents2RGBA32.data(), rgba32Pixels, numColorComponents); | 
| + | 
| +  WTF::ArrayBufferContents contentsF16(numColorComponents * 2, 1, WTF::ArrayBufferContents::NotShared, | 
| +    WTF::ArrayBufferContents::DontInitialize); | 
| +  std::memcpy(contentsF16.data(), f16Pixels, numColorComponents * 2); | 
| + | 
| +  // Uint16 is not supported as the storage format for ImageData created from a | 
| +  // canvas, so this conversion is neither implemented nor tested here. | 
| +  bool testPassed = true; | 
| +  DOMArrayBufferView* data = nullptr; | 
| +  DOMUint8ClampedArray* dataU8 = nullptr; | 
| +  DOMFloat32Array* dataF32 = nullptr; | 
| + | 
| +  // Testing kRGBA8CanvasPixelFormat -> kUint8ClampedArrayStorageFormat | 
| +  data = ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat( | 
| +      contentsRGBA32, kRGBA8CanvasPixelFormat, kUint8ClampedArrayStorageFormat); | 
| +  DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped); | 
| +  dataU8 = const_cast<DOMUint8ClampedArray*>( | 
| +          static_cast<const DOMUint8ClampedArray*>(data)); | 
| +  DCHECK(dataU8); | 
| +  for (unsigned i = 0; i < numColorComponents; i++) { | 
| +    if (dataU8->data()[i] != rgba32Pixels[i]){ | 
| +      testPassed = false; | 
| +      break; | 
| +    } | 
| +  } | 
| +  EXPECT_TRUE(testPassed); | 
| + | 
| +  // Testing kRGBA8CanvasPixelFormat -> kFloat32ArrayStorageFormat | 
| +  data = ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat( | 
| +      contents2RGBA32, kRGBA8CanvasPixelFormat, kFloat32ArrayStorageFormat); | 
| +  DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeFloat32); | 
| +  dataF32 = const_cast<DOMFloat32Array*>( | 
| +          static_cast<const DOMFloat32Array*>(data)); | 
| +  DCHECK(dataF32); | 
| +  for (unsigned i = 0; i < numColorComponents; i++) { | 
| +    if (!IsNearlyTheSame(dataF32->data()[i], rgba32Pixels[i] / 255.0)){ | 
| +      testPassed = false; | 
| +      break; | 
| +    } | 
| +  } | 
| +  EXPECT_TRUE(testPassed); | 
| + | 
| +  // Testing kF16CanvasPixelFormat -> kUint8ClampedArrayStorageFormat | 
| +  data = ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat( | 
| +      contentsF16, kF16CanvasPixelFormat, kUint8ClampedArrayStorageFormat); | 
| +  DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped); | 
| +  dataU8 = const_cast<DOMUint8ClampedArray*>( | 
| +          static_cast<const DOMUint8ClampedArray*>(data)); | 
| +  DCHECK(dataU8); | 
| +  for (unsigned i = 0; i < numColorComponents; i++) { | 
| +    if (!IsNearlyTheSame(dataU8->data()[i], rgba32Pixels[i])){ | 
| +      testPassed = false; | 
| +      break; | 
| +    } | 
| +  } | 
| +  EXPECT_TRUE(testPassed); | 
| + | 
| +  // Testing kF16CanvasPixelFormat -> kFloat32ArrayStorageFormat | 
| +  data = ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat( | 
| +      contentsF16, kF16CanvasPixelFormat, kFloat32ArrayStorageFormat); | 
| +  DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeFloat32); | 
| +  dataF32 = const_cast<DOMFloat32Array*>( | 
| +          static_cast<const DOMFloat32Array*>(data)); | 
| +  DCHECK(dataF32); | 
| +  for (unsigned i = 0; i < numColorComponents; i++) { | 
| +    if (!IsNearlyTheSame(dataF32->data()[i], rgba32Pixels[i] / 255.0)){ | 
| +      testPassed = false; | 
| +      break; | 
| +    } | 
| +  } | 
| +  EXPECT_TRUE(testPassed); | 
| +} | 
| + | 
| }  // namspace | 
| }  // namespace blink | 
|  |