Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp

Issue 2522693002: Color correct ImageBitmap(HTMLImageElement*) constructor (Closed)
Patch Set: Addressing crash on memory sanitizer trybot Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2013, Google Inc. All rights reserved. 2 * Copyright (c) 2013, Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 22 matching lines...) Expand all
33 #include "SkPixelRef.h" // FIXME: qualify this skia header file. 33 #include "SkPixelRef.h" // FIXME: qualify this skia header file.
34 #include "core/dom/Document.h" 34 #include "core/dom/Document.h"
35 #include "core/fetch/ImageResourceContent.h" 35 #include "core/fetch/ImageResourceContent.h"
36 #include "core/fetch/MemoryCache.h" 36 #include "core/fetch/MemoryCache.h"
37 #include "core/html/HTMLCanvasElement.h" 37 #include "core/html/HTMLCanvasElement.h"
38 #include "core/html/HTMLImageElement.h" 38 #include "core/html/HTMLImageElement.h"
39 #include "core/html/HTMLVideoElement.h" 39 #include "core/html/HTMLVideoElement.h"
40 #include "platform/graphics/StaticBitmapImage.h" 40 #include "platform/graphics/StaticBitmapImage.h"
41 #include "platform/graphics/skia/SkiaUtils.h" 41 #include "platform/graphics/skia/SkiaUtils.h"
42 #include "platform/heap/Handle.h" 42 #include "platform/heap/Handle.h"
43 #include "platform/image-decoders/ImageDecoder.h"
43 #include "platform/network/ResourceRequest.h" 44 #include "platform/network/ResourceRequest.h"
44 #include "testing/gtest/include/gtest/gtest.h" 45 #include "testing/gtest/include/gtest/gtest.h"
45 #include "third_party/skia/include/core/SkCanvas.h" 46 #include "third_party/skia/include/core/SkCanvas.h"
47 #include "third_party/skia/include/core/SkColorSpaceXform.h"
46 #include "third_party/skia/include/core/SkImage.h" 48 #include "third_party/skia/include/core/SkImage.h"
47 #include "third_party/skia/include/core/SkSurface.h" 49 #include "third_party/skia/include/core/SkSurface.h"
48 50
49 namespace blink { 51 namespace blink {
50 52
51 class ImageBitmapTest : public ::testing::Test { 53 class ImageBitmapTest : public ::testing::Test {
52 protected: 54 protected:
53 virtual void SetUp() { 55 virtual void SetUp() {
54 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(10, 10); 56 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(10, 10);
55 surface->getCanvas()->clear(0xFFFFFFFF); 57 surface->getCanvas()->clear(0xFFFFFFFF);
56 m_image = surface->makeImageSnapshot(); 58 m_image = surface->makeImageSnapshot();
57 59
58 sk_sp<SkSurface> surface2 = SkSurface::MakeRasterN32Premul(5, 5); 60 sk_sp<SkSurface> surface2 = SkSurface::MakeRasterN32Premul(5, 5);
59 surface2->getCanvas()->clear(0xAAAAAAAA); 61 surface2->getCanvas()->clear(0xAAAAAAAA);
60 m_image2 = surface2->makeImageSnapshot(); 62 m_image2 = surface2->makeImageSnapshot();
61 63
62 // Save the global memory cache to restore it upon teardown. 64 // Save the global memory cache to restore it upon teardown.
63 m_globalMemoryCache = replaceMemoryCacheForTesting(MemoryCache::create()); 65 m_globalMemoryCache = replaceMemoryCacheForTesting(MemoryCache::create());
66
67 // Save the state of experimental canvas features and color correct
68 // rendering flags to restore them on teardown.
69 experimentalCanvasFeatures =
70 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled();
71 colorCorrectRendering =
72 RuntimeEnabledFeatures::colorCorrectRenderingEnabled();
73 colorCorrectRenderingDefaultMode =
74 RuntimeEnabledFeatures::colorCorrectRenderingDefaultModeEnabled();
64 } 75 }
65 virtual void TearDown() { 76 virtual void TearDown() {
66 // Garbage collection is required prior to switching out the 77 // Garbage collection is required prior to switching out the
67 // test's memory cache; image resources are released, evicting 78 // test's memory cache; image resources are released, evicting
68 // them from the cache. 79 // them from the cache.
69 ThreadState::current()->collectGarbage(BlinkGC::NoHeapPointersOnStack, 80 ThreadState::current()->collectGarbage(BlinkGC::NoHeapPointersOnStack,
70 BlinkGC::GCWithSweep, 81 BlinkGC::GCWithSweep,
71 BlinkGC::ForcedGC); 82 BlinkGC::ForcedGC);
72 83
73 replaceMemoryCacheForTesting(m_globalMemoryCache.release()); 84 replaceMemoryCacheForTesting(m_globalMemoryCache.release());
85 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(
86 experimentalCanvasFeatures);
87 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(
88 colorCorrectRendering);
89 RuntimeEnabledFeatures::setColorCorrectRenderingDefaultModeEnabled(
90 colorCorrectRenderingDefaultMode);
74 } 91 }
75 92
76 sk_sp<SkImage> m_image, m_image2; 93 sk_sp<SkImage> m_image, m_image2;
77 Persistent<MemoryCache> m_globalMemoryCache; 94 Persistent<MemoryCache> m_globalMemoryCache;
95 bool experimentalCanvasFeatures;
96 bool colorCorrectRendering;
97 bool colorCorrectRenderingDefaultMode;
78 }; 98 };
79 99
80 TEST_F(ImageBitmapTest, ImageResourceConsistency) { 100 TEST_F(ImageBitmapTest, ImageResourceConsistency) {
81 const ImageBitmapOptions defaultOptions; 101 const ImageBitmapOptions defaultOptions;
82 HTMLImageElement* imageElement = 102 HTMLImageElement* imageElement =
83 HTMLImageElement::create(*Document::create()); 103 HTMLImageElement::create(*Document::create());
84 ImageResourceContent* image = 104 ImageResourceContent* image =
85 ImageResourceContent::create(StaticBitmapImage::create(m_image).get()); 105 ImageResourceContent::create(StaticBitmapImage::create(m_image).get());
86 imageElement->setImageResource(image); 106 imageElement->setImageResource(image);
87 107
88 Optional<IntRect> cropRect = 108 Optional<IntRect> cropRect =
89 IntRect(0, 0, m_image->width(), m_image->height()); 109 IntRect(0, 0, m_image->width(), m_image->height());
90 ImageBitmap* imageBitmapNoCrop = ImageBitmap::create( 110 ImageBitmap* imageBitmapNoCrop = ImageBitmap::create(
91 imageElement, cropRect, &(imageElement->document()), defaultOptions); 111 imageElement, cropRect, &(imageElement->document()), defaultOptions);
92 cropRect = IntRect(m_image->width() / 2, m_image->height() / 2, 112 cropRect = IntRect(m_image->width() / 2, m_image->height() / 2,
93 m_image->width() / 2, m_image->height() / 2); 113 m_image->width() / 2, m_image->height() / 2);
94 ImageBitmap* imageBitmapInteriorCrop = ImageBitmap::create( 114 ImageBitmap* imageBitmapInteriorCrop = ImageBitmap::create(
95 imageElement, cropRect, &(imageElement->document()), defaultOptions); 115 imageElement, cropRect, &(imageElement->document()), defaultOptions);
96 cropRect = IntRect(-m_image->width() / 2, -m_image->height() / 2, 116 cropRect = IntRect(-m_image->width() / 2, -m_image->height() / 2,
97 m_image->width(), m_image->height()); 117 m_image->width(), m_image->height());
98 ImageBitmap* imageBitmapExteriorCrop = ImageBitmap::create( 118 ImageBitmap* imageBitmapExteriorCrop = ImageBitmap::create(
99 imageElement, cropRect, &(imageElement->document()), defaultOptions); 119 imageElement, cropRect, &(imageElement->document()), defaultOptions);
100 cropRect = IntRect(-m_image->width(), -m_image->height(), m_image->width(), 120 cropRect = IntRect(-m_image->width(), -m_image->height(), m_image->width(),
101 m_image->height()); 121 m_image->height());
102 ImageBitmap* imageBitmapOutsideCrop = ImageBitmap::create( 122 ImageBitmap* imageBitmapOutsideCrop = ImageBitmap::create(
103 imageElement, cropRect, &(imageElement->document()), defaultOptions); 123 imageElement, cropRect, &(imageElement->document()), defaultOptions);
104 124
105 ASSERT_EQ(imageBitmapNoCrop->bitmapImage()->imageForCurrentFrame( 125 ASSERT_NE(imageBitmapNoCrop->bitmapImage()->imageForCurrentFrame(
106 ColorBehavior::transformToTargetForTesting()), 126 ColorBehavior::transformToTargetForTesting()),
107 imageElement->cachedImage()->getImage()->imageForCurrentFrame( 127 imageElement->cachedImage()->getImage()->imageForCurrentFrame(
108 ColorBehavior::transformToTargetForTesting())); 128 ColorBehavior::transformToTargetForTesting()));
109 ASSERT_NE(imageBitmapInteriorCrop->bitmapImage()->imageForCurrentFrame( 129 ASSERT_NE(imageBitmapInteriorCrop->bitmapImage()->imageForCurrentFrame(
110 ColorBehavior::transformToTargetForTesting()), 130 ColorBehavior::transformToTargetForTesting()),
111 imageElement->cachedImage()->getImage()->imageForCurrentFrame( 131 imageElement->cachedImage()->getImage()->imageForCurrentFrame(
112 ColorBehavior::transformToTargetForTesting())); 132 ColorBehavior::transformToTargetForTesting()));
113 ASSERT_NE(imageBitmapExteriorCrop->bitmapImage()->imageForCurrentFrame( 133 ASSERT_NE(imageBitmapExteriorCrop->bitmapImage()->imageForCurrentFrame(
114 ColorBehavior::transformToTargetForTesting()), 134 ColorBehavior::transformToTargetForTesting()),
115 imageElement->cachedImage()->getImage()->imageForCurrentFrame( 135 imageElement->cachedImage()->getImage()->imageForCurrentFrame(
(...skipping 12 matching lines...) Expand all
128 HTMLImageElement* image = HTMLImageElement::create(*Document::create()); 148 HTMLImageElement* image = HTMLImageElement::create(*Document::create());
129 ImageResourceContent* originalImageResource = 149 ImageResourceContent* originalImageResource =
130 ImageResourceContent::create(StaticBitmapImage::create(m_image).get()); 150 ImageResourceContent::create(StaticBitmapImage::create(m_image).get());
131 image->setImageResource(originalImageResource); 151 image->setImageResource(originalImageResource);
132 152
133 const ImageBitmapOptions defaultOptions; 153 const ImageBitmapOptions defaultOptions;
134 Optional<IntRect> cropRect = 154 Optional<IntRect> cropRect =
135 IntRect(0, 0, m_image->width(), m_image->height()); 155 IntRect(0, 0, m_image->width(), m_image->height());
136 ImageBitmap* imageBitmap = ImageBitmap::create( 156 ImageBitmap* imageBitmap = ImageBitmap::create(
137 image, cropRect, &(image->document()), defaultOptions); 157 image, cropRect, &(image->document()), defaultOptions);
138 ASSERT_EQ(imageBitmap->bitmapImage()->imageForCurrentFrame( 158 // As we are applying color space conversion for the "default" mode,
159 // this verifies that the color corrected image is not the same as the
160 // source.
161 ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(
139 ColorBehavior::transformToTargetForTesting()), 162 ColorBehavior::transformToTargetForTesting()),
140 originalImageResource->getImage()->imageForCurrentFrame( 163 originalImageResource->getImage()->imageForCurrentFrame(
141 ColorBehavior::transformToTargetForTesting())); 164 ColorBehavior::transformToTargetForTesting()));
142 165
143 ImageResourceContent* newImageResource = 166 ImageResourceContent* newImageResource =
144 ImageResourceContent::create(StaticBitmapImage::create(m_image2).get()); 167 ImageResourceContent::create(StaticBitmapImage::create(m_image2).get());
145 image->setImageResource(newImageResource); 168 image->setImageResource(newImageResource);
146 169
147 // The ImageBitmap should contain the same data as the original cached image
148 { 170 {
149 ASSERT_EQ(imageBitmap->bitmapImage()->imageForCurrentFrame( 171 ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(
150 ColorBehavior::transformToTargetForTesting()), 172 ColorBehavior::transformToTargetForTesting()),
151 originalImageResource->getImage()->imageForCurrentFrame( 173 originalImageResource->getImage()->imageForCurrentFrame(
152 ColorBehavior::transformToTargetForTesting())); 174 ColorBehavior::transformToTargetForTesting()));
153 SkImage* image1 = 175 SkImage* image1 =
154 imageBitmap->bitmapImage() 176 imageBitmap->bitmapImage()
155 ->imageForCurrentFrame(ColorBehavior::transformToTargetForTesting()) 177 ->imageForCurrentFrame(ColorBehavior::transformToTargetForTesting())
156 .get(); 178 .get();
157 ASSERT_NE(image1, nullptr); 179 ASSERT_NE(image1, nullptr);
158 SkImage* image2 = 180 SkImage* image2 =
159 originalImageResource->getImage() 181 originalImageResource->getImage()
160 ->imageForCurrentFrame(ColorBehavior::transformToTargetForTesting()) 182 ->imageForCurrentFrame(ColorBehavior::transformToTargetForTesting())
161 .get(); 183 .get();
162 ASSERT_NE(image2, nullptr); 184 ASSERT_NE(image2, nullptr);
163 ASSERT_EQ(image1, image2); 185 ASSERT_NE(image1, image2);
164 } 186 }
165 187
166 { 188 {
167 ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame( 189 ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(
168 ColorBehavior::transformToTargetForTesting()), 190 ColorBehavior::transformToTargetForTesting()),
169 newImageResource->getImage()->imageForCurrentFrame( 191 newImageResource->getImage()->imageForCurrentFrame(
170 ColorBehavior::transformToTargetForTesting())); 192 ColorBehavior::transformToTargetForTesting()));
171 SkImage* image1 = 193 SkImage* image1 =
172 imageBitmap->bitmapImage() 194 imageBitmap->bitmapImage()
173 ->imageForCurrentFrame(ColorBehavior::transformToTargetForTesting()) 195 ->imageForCurrentFrame(ColorBehavior::transformToTargetForTesting())
174 .get(); 196 .get();
175 ASSERT_NE(image1, nullptr); 197 ASSERT_NE(image1, nullptr);
176 SkImage* image2 = 198 SkImage* image2 =
177 newImageResource->getImage() 199 newImageResource->getImage()
178 ->imageForCurrentFrame(ColorBehavior::transformToTargetForTesting()) 200 ->imageForCurrentFrame(ColorBehavior::transformToTargetForTesting())
179 .get(); 201 .get();
180 ASSERT_NE(image2, nullptr); 202 ASSERT_NE(image2, nullptr);
181 ASSERT_NE(image1, image2); 203 ASSERT_NE(image1, image2);
182 } 204 }
183 } 205 }
184 206
207 enum class ColorSpaceConversion : uint8_t {
208 NONE = 0,
209 DEFAULT_NOT_COLOR_CORRECTED = 1,
210 DEFAULT_COLOR_CORRECTED = 2,
211 SRGB = 3,
212 LINEAR_RGB = 4,
213
214 LAST = LINEAR_RGB
215 };
216
217 static ImageBitmap* createImageBitmapWithColorSpaceConversion(
218 HTMLImageElement* image,
219 Optional<IntRect>& cropRect,
220 Document* document,
221 const ColorSpaceConversion& colorSpaceConversion) {
222 // Set the color space conversion in ImageBitmapOptions
223 ImageBitmapOptions options;
224 static const Vector<String> conversions = {"none", "default", "default",
225 "srgb", "linear-rgb"};
226 options.setColorSpaceConversion(
227 conversions[static_cast<uint8_t>(colorSpaceConversion)]);
228
229 // Set the runtime flags
230 bool flag = (colorSpaceConversion !=
231 ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED);
232 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(true);
233 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(flag);
234 RuntimeEnabledFeatures::setColorCorrectRenderingDefaultModeEnabled(!flag);
235
236 // Create and return the ImageBitmap
237 return ImageBitmap::create(image, cropRect, &(image->document()), options);
238 }
239
240 TEST_F(ImageBitmapTest, ImageBitmapColorSpaceConversion) {
241 HTMLImageElement* imageElement =
242 HTMLImageElement::create(*Document::create());
243
244 SkPaint p;
245 p.setColor(SK_ColorRED);
246 sk_sp<SkColorSpace> srcRGBColorSpace =
247 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
248
249 SkImageInfo rasterImageInfo =
250 SkImageInfo::MakeN32Premul(100, 100, srcRGBColorSpace);
251 sk_sp<SkSurface> surface(SkSurface::MakeRaster(rasterImageInfo));
252 surface->getCanvas()->drawCircle(50, 50, 50, p);
253 sk_sp<SkImage> image = surface->makeImageSnapshot();
254
255 std::unique_ptr<uint8_t[]> srcPixel(
256 new uint8_t[rasterImageInfo.bytesPerPixel()]());
257 image->readPixels(rasterImageInfo.makeWH(1, 1), srcPixel.get(),
258 image->width() * rasterImageInfo.bytesPerPixel(), 50, 50);
259
260 ImageResourceContent* originalImageResource =
261 ImageResourceContent::create(StaticBitmapImage::create(image).get());
262 imageElement->setImageResource(originalImageResource);
263
264 Optional<IntRect> cropRect = IntRect(0, 0, image->width(), image->height());
265
266 // Create and test the ImageBitmap objects.
267 // We don't check "none" color space conversion as it requires the encoded
268 // data in a format readable by ImageDecoder. Furthermore, the code path for
269 // "none" color space conversion is not affected by this CL.
270
271 sk_sp<SkColorSpace> colorSpace = nullptr;
272 SkColorType colorType = SkColorType::kN32_SkColorType;
273 SkColorSpaceXform::ColorFormat colorFormat32 =
274 (colorType == kBGRA_8888_SkColorType)
275 ? SkColorSpaceXform::ColorFormat::kBGRA_8888_ColorFormat
276 : SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
277 SkColorSpaceXform::ColorFormat colorFormat = colorFormat32;
278
279 for (uint8_t i = static_cast<uint8_t>(
280 ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED);
281 i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) {
282 ColorSpaceConversion colorSpaceConversion =
283 static_cast<ColorSpaceConversion>(i);
284 ImageBitmap* imageBitmap = createImageBitmapWithColorSpaceConversion(
285 imageElement, cropRect, &(imageElement->document()),
286 colorSpaceConversion);
287 SkImage* convertedImage =
288 imageBitmap->bitmapImage()
289 ->imageForCurrentFrame(ColorBehavior::ignore())
290 .get();
291
292 switch (colorSpaceConversion) {
293 case ColorSpaceConversion::NONE:
294 NOTREACHED();
295 break;
296 case ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED:
297 // TODO(zakerinasab): Replace sRGB with a call to
298 // ImageDecoder::globalTargetColorSpace() when the crash problem on Mac
299 // is fixed. crbug.com/668546.
300 colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
301 colorFormat = colorFormat32;
302 break;
303 case ColorSpaceConversion::DEFAULT_COLOR_CORRECTED:
304 case ColorSpaceConversion::SRGB:
305 colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
306 colorFormat = colorFormat32;
307 break;
308 case ColorSpaceConversion::LINEAR_RGB:
309 colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
310 colorType = SkColorType::kRGBA_F16_SkColorType;
311 colorFormat = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
312 break;
313 default:
314 NOTREACHED();
315 }
316
317 SkImageInfo imageInfo = SkImageInfo::Make(
318 1, 1, colorType, SkAlphaType::kPremul_SkAlphaType, colorSpace);
319 std::unique_ptr<uint8_t[]> convertedPixel(
320 new uint8_t[imageInfo.bytesPerPixel()]());
321 convertedImage->readPixels(
322 imageInfo, convertedPixel.get(),
323 convertedImage->width() * imageInfo.bytesPerPixel(), 50, 50);
324
325 // Transform the source pixel and check if the image bitmap color conversion
326 // is done correctly.
327 std::unique_ptr<SkColorSpaceXform> colorSpaceXform =
328 SkColorSpaceXform::New(srcRGBColorSpace.get(), colorSpace.get());
329 std::unique_ptr<uint8_t[]> transformedPixel(
330 new uint8_t[imageInfo.bytesPerPixel()]());
331 colorSpaceXform->apply(colorFormat, transformedPixel.get(), colorFormat32,
332 srcPixel.get(), 1, SkAlphaType::kPremul_SkAlphaType);
333
334 int compare = std::memcmp(convertedPixel.get(), transformedPixel.get(),
335 imageInfo.bytesPerPixel());
336 ASSERT_EQ(compare, 0);
337 }
338 }
339
185 } // namespace blink 340 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698