OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/html/ImageData.h" | 5 #include "core/html/ImageData.h" |
6 | 6 |
7 #include "core/dom/ExceptionCode.h" | 7 #include "core/dom/ExceptionCode.h" |
8 #include "platform/geometry/IntSize.h" | 8 #include "platform/geometry/IntSize.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
| 10 #include "third_party/skia/include/core/SkColorSpaceXform.h" |
10 | 11 |
11 namespace blink { | 12 namespace blink { |
12 namespace { | 13 namespace { |
13 | 14 |
14 class ImageDataTest : public ::testing::Test { | 15 class ImageDataTest : public ::testing::Test { |
15 protected: | 16 protected: |
16 ImageDataTest(){}; | 17 virtual void SetUp() { |
17 void TearDown(){}; | 18 // Save the state of experimental canvas features and color correct |
| 19 // rendering flags to restore them on teardown. |
| 20 experimentalCanvasFeatures = |
| 21 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled(); |
| 22 colorCorrectRendering = |
| 23 RuntimeEnabledFeatures::colorCorrectRenderingEnabled(); |
| 24 } |
| 25 |
| 26 virtual void TearDown() { |
| 27 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled( |
| 28 experimentalCanvasFeatures); |
| 29 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled( |
| 30 colorCorrectRendering); |
| 31 } |
| 32 |
| 33 bool experimentalCanvasFeatures; |
| 34 bool colorCorrectRendering; |
18 }; | 35 }; |
19 | 36 |
20 TEST_F(ImageDataTest, NegativeAndZeroIntSizeTest) { | 37 TEST_F(ImageDataTest, NegativeAndZeroIntSizeTest) { |
21 ImageData* imageData; | 38 ImageData* imageData; |
22 | 39 |
23 imageData = ImageData::create(IntSize(0, 10)); | 40 imageData = ImageData::create(IntSize(0, 10)); |
24 EXPECT_EQ(imageData, nullptr); | 41 EXPECT_EQ(imageData, nullptr); |
25 | 42 |
26 imageData = ImageData::create(IntSize(10, 0)); | 43 imageData = ImageData::create(IntSize(10, 0)); |
27 EXPECT_EQ(imageData, nullptr); | 44 EXPECT_EQ(imageData, nullptr); |
(...skipping 15 matching lines...) Expand all Loading... |
43 // allocated to the ImageData, then an exception must raise. | 60 // allocated to the ImageData, then an exception must raise. |
44 TEST_F(ImageDataTest, CreateImageDataTooBig) { | 61 TEST_F(ImageDataTest, CreateImageDataTooBig) { |
45 DummyExceptionStateForTesting exceptionState; | 62 DummyExceptionStateForTesting exceptionState; |
46 ImageData* tooBigImageData = ImageData::create(32767, 32767, exceptionState); | 63 ImageData* tooBigImageData = ImageData::create(32767, 32767, exceptionState); |
47 if (!tooBigImageData) { | 64 if (!tooBigImageData) { |
48 EXPECT_TRUE(exceptionState.hadException()); | 65 EXPECT_TRUE(exceptionState.hadException()); |
49 EXPECT_EQ(exceptionState.code(), V8RangeError); | 66 EXPECT_EQ(exceptionState.code(), V8RangeError); |
50 } | 67 } |
51 } | 68 } |
52 | 69 |
| 70 // Skia conversion does not guarantee to be exact, se we need to do |
| 71 // approximate comparisons. |
| 72 static inline bool IsNearlyTheSame(float f, float g) { |
| 73 static const float epsilonScale = 0.01f; |
| 74 return std::abs(f - g) < epsilonScale * |
| 75 std::max(std::max(std::abs(f), std::abs(g)), epsilonScale); |
| 76 } |
| 77 |
| 78 // This test verifies the correct behavior of ImageData member function used |
| 79 // to convert pixels data from canvas pixel format image data storage format. |
| 80 // This function is used in BaseRenderingContext2D::getImageData. |
| 81 TEST_F(ImageDataTest, TestConvertPixelsFromCanvasPixelFormatToImageDataStorageFo
rmat) { |
| 82 // Source pixels in RGBA32 |
| 83 unsigned char rgba32Pixels[] = {255, 0, 0, 255, // Red |
| 84 0, 0, 0, 0, // Transparent |
| 85 255, 192, 128, 64, // Decreasing values |
| 86 93, 117, 205, 11}; // Random values |
| 87 const unsigned numColorComponents = 16; |
| 88 // Source pixels in F16 |
| 89 unsigned char* f16Pixels = new unsigned char [numColorComponents * 2]; |
| 90 |
| 91 // Filling F16 source pixels |
| 92 std::unique_ptr<SkColorSpaceXform> xform = |
| 93 SkColorSpaceXform::New(SkColorSpace::MakeSRGBLinear().get(), |
| 94 SkColorSpace::MakeSRGBLinear().get()); |
| 95 xform->apply(SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat, f16Pixels, |
| 96 SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat, rgba32Pix
els, |
| 97 4, SkAlphaType::kUnpremul_SkAlphaType); |
| 98 |
| 99 // Creating ArrayBufferContents objects. We need two buffers for RGBA32 data |
| 100 // because kRGBA8CanvasPixelFormat->kUint8ClampedArrayStorageFormat consumes |
| 101 // the input data parameter. |
| 102 WTF::ArrayBufferContents contentsRGBA32(numColorComponents, 1, WTF::ArrayBuffe
rContents::NotShared, |
| 103 WTF::ArrayBufferContents::DontInitialize); |
| 104 std::memcpy(contentsRGBA32.data(), rgba32Pixels, numColorComponents); |
| 105 |
| 106 WTF::ArrayBufferContents contents2RGBA32(numColorComponents, 1, WTF::ArrayBuff
erContents::NotShared, |
| 107 WTF::ArrayBufferContents::DontInitialize); |
| 108 std::memcpy(contents2RGBA32.data(), rgba32Pixels, numColorComponents); |
| 109 |
| 110 WTF::ArrayBufferContents contentsF16(numColorComponents * 2, 1, WTF::ArrayBuff
erContents::NotShared, |
| 111 WTF::ArrayBufferContents::DontInitialize); |
| 112 std::memcpy(contentsF16.data(), f16Pixels, numColorComponents * 2); |
| 113 |
| 114 // Uint16 is not supported as the storage format for ImageData created from a |
| 115 // canvas, so this conversion is neither implemented nor tested here. |
| 116 bool testPassed = true; |
| 117 DOMArrayBufferView* data = nullptr; |
| 118 DOMUint8ClampedArray* dataU8 = nullptr; |
| 119 DOMFloat32Array* dataF32 = nullptr; |
| 120 |
| 121 // Testing kRGBA8CanvasPixelFormat -> kUint8ClampedArrayStorageFormat |
| 122 data = ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat( |
| 123 contentsRGBA32, kRGBA8CanvasPixelFormat, kUint8ClampedArrayStorageFormat); |
| 124 DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped); |
| 125 dataU8 = const_cast<DOMUint8ClampedArray*>( |
| 126 static_cast<const DOMUint8ClampedArray*>(data)); |
| 127 DCHECK(dataU8); |
| 128 for (unsigned i = 0; i < numColorComponents; i++) { |
| 129 if (dataU8->data()[i] != rgba32Pixels[i]){ |
| 130 testPassed = false; |
| 131 break; |
| 132 } |
| 133 } |
| 134 EXPECT_TRUE(testPassed); |
| 135 |
| 136 // Testing kRGBA8CanvasPixelFormat -> kFloat32ArrayStorageFormat |
| 137 data = ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat( |
| 138 contents2RGBA32, kRGBA8CanvasPixelFormat, kFloat32ArrayStorageFormat); |
| 139 DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeFloat32); |
| 140 dataF32 = const_cast<DOMFloat32Array*>( |
| 141 static_cast<const DOMFloat32Array*>(data)); |
| 142 DCHECK(dataF32); |
| 143 for (unsigned i = 0; i < numColorComponents; i++) { |
| 144 if (!IsNearlyTheSame(dataF32->data()[i], rgba32Pixels[i] / 255.0)){ |
| 145 testPassed = false; |
| 146 break; |
| 147 } |
| 148 } |
| 149 EXPECT_TRUE(testPassed); |
| 150 |
| 151 // Testing kF16CanvasPixelFormat -> kUint8ClampedArrayStorageFormat |
| 152 data = ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat( |
| 153 contentsF16, kF16CanvasPixelFormat, kUint8ClampedArrayStorageFormat); |
| 154 DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped); |
| 155 dataU8 = const_cast<DOMUint8ClampedArray*>( |
| 156 static_cast<const DOMUint8ClampedArray*>(data)); |
| 157 DCHECK(dataU8); |
| 158 for (unsigned i = 0; i < numColorComponents; i++) { |
| 159 if (!IsNearlyTheSame(dataU8->data()[i], rgba32Pixels[i])){ |
| 160 testPassed = false; |
| 161 break; |
| 162 } |
| 163 } |
| 164 EXPECT_TRUE(testPassed); |
| 165 |
| 166 // Testing kF16CanvasPixelFormat -> kFloat32ArrayStorageFormat |
| 167 data = ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat( |
| 168 contentsF16, kF16CanvasPixelFormat, kFloat32ArrayStorageFormat); |
| 169 DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeFloat32); |
| 170 dataF32 = const_cast<DOMFloat32Array*>( |
| 171 static_cast<const DOMFloat32Array*>(data)); |
| 172 DCHECK(dataF32); |
| 173 for (unsigned i = 0; i < numColorComponents; i++) { |
| 174 if (!IsNearlyTheSame(dataF32->data()[i], rgba32Pixels[i] / 255.0)){ |
| 175 testPassed = false; |
| 176 break; |
| 177 } |
| 178 } |
| 179 EXPECT_TRUE(testPassed); |
| 180 } |
| 181 |
53 } // namspace | 182 } // namspace |
54 } // namespace blink | 183 } // namespace blink |
OLD | NEW |