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

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

Issue 2522693002: Color correct ImageBitmap(HTMLImageElement*) constructor (Closed)
Patch Set: Removing ImageDecoder::globalTargetColorSpace() calls for now 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/ImageResource.h" 35 #include "core/fetch/ImageResource.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();
64 } 73 }
65 virtual void TearDown() { 74 virtual void TearDown() {
66 // Garbage collection is required prior to switching out the 75 // Garbage collection is required prior to switching out the
67 // test's memory cache; image resources are released, evicting 76 // test's memory cache; image resources are released, evicting
68 // them from the cache. 77 // them from the cache.
69 ThreadState::current()->collectGarbage(BlinkGC::NoHeapPointersOnStack, 78 ThreadState::current()->collectGarbage(BlinkGC::NoHeapPointersOnStack,
70 BlinkGC::GCWithSweep, 79 BlinkGC::GCWithSweep,
71 BlinkGC::ForcedGC); 80 BlinkGC::ForcedGC);
72 81
73 replaceMemoryCacheForTesting(m_globalMemoryCache.release()); 82 replaceMemoryCacheForTesting(m_globalMemoryCache.release());
83 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(
84 experimentalCanvasFeatures);
85 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(
86 colorCorrectRendering);
74 } 87 }
75 88
76 sk_sp<SkImage> m_image, m_image2; 89 sk_sp<SkImage> m_image, m_image2;
77 Persistent<MemoryCache> m_globalMemoryCache; 90 Persistent<MemoryCache> m_globalMemoryCache;
91 bool experimentalCanvasFeatures;
92 bool colorCorrectRendering;
78 }; 93 };
79 94
80 TEST_F(ImageBitmapTest, ImageResourceConsistency) { 95 TEST_F(ImageBitmapTest, ImageResourceConsistency) {
81 const ImageBitmapOptions defaultOptions; 96 const ImageBitmapOptions defaultOptions;
82 HTMLImageElement* imageElement = 97 HTMLImageElement* imageElement =
83 HTMLImageElement::create(*Document::create()); 98 HTMLImageElement::create(*Document::create());
84 ImageResource* image = 99 ImageResource* image =
85 ImageResource::create(StaticBitmapImage::create(m_image).get()); 100 ImageResource::create(StaticBitmapImage::create(m_image).get());
86 imageElement->setImageResource(image); 101 imageElement->setImageResource(image);
87 102
88 Optional<IntRect> cropRect = 103 Optional<IntRect> cropRect =
89 IntRect(0, 0, m_image->width(), m_image->height()); 104 IntRect(0, 0, m_image->width(), m_image->height());
90 ImageBitmap* imageBitmapNoCrop = ImageBitmap::create( 105 ImageBitmap* imageBitmapNoCrop = ImageBitmap::create(
91 imageElement, cropRect, &(imageElement->document()), defaultOptions); 106 imageElement, cropRect, &(imageElement->document()), defaultOptions);
92 cropRect = IntRect(m_image->width() / 2, m_image->height() / 2, 107 cropRect = IntRect(m_image->width() / 2, m_image->height() / 2,
93 m_image->width() / 2, m_image->height() / 2); 108 m_image->width() / 2, m_image->height() / 2);
94 ImageBitmap* imageBitmapInteriorCrop = ImageBitmap::create( 109 ImageBitmap* imageBitmapInteriorCrop = ImageBitmap::create(
95 imageElement, cropRect, &(imageElement->document()), defaultOptions); 110 imageElement, cropRect, &(imageElement->document()), defaultOptions);
96 cropRect = IntRect(-m_image->width() / 2, -m_image->height() / 2, 111 cropRect = IntRect(-m_image->width() / 2, -m_image->height() / 2,
97 m_image->width(), m_image->height()); 112 m_image->width(), m_image->height());
98 ImageBitmap* imageBitmapExteriorCrop = ImageBitmap::create( 113 ImageBitmap* imageBitmapExteriorCrop = ImageBitmap::create(
99 imageElement, cropRect, &(imageElement->document()), defaultOptions); 114 imageElement, cropRect, &(imageElement->document()), defaultOptions);
100 cropRect = IntRect(-m_image->width(), -m_image->height(), m_image->width(), 115 cropRect = IntRect(-m_image->width(), -m_image->height(), m_image->width(),
101 m_image->height()); 116 m_image->height());
102 ImageBitmap* imageBitmapOutsideCrop = ImageBitmap::create( 117 ImageBitmap* imageBitmapOutsideCrop = ImageBitmap::create(
103 imageElement, cropRect, &(imageElement->document()), defaultOptions); 118 imageElement, cropRect, &(imageElement->document()), defaultOptions);
104 119
105 ASSERT_EQ(imageBitmapNoCrop->bitmapImage()->imageForCurrentFrame(), 120 ASSERT_NE(imageBitmapNoCrop->bitmapImage()->imageForCurrentFrame(),
106 imageElement->cachedImage()->getImage()->imageForCurrentFrame()); 121 imageElement->cachedImage()->getImage()->imageForCurrentFrame());
107 ASSERT_NE(imageBitmapInteriorCrop->bitmapImage()->imageForCurrentFrame(), 122 ASSERT_NE(imageBitmapInteriorCrop->bitmapImage()->imageForCurrentFrame(),
108 imageElement->cachedImage()->getImage()->imageForCurrentFrame()); 123 imageElement->cachedImage()->getImage()->imageForCurrentFrame());
109 ASSERT_NE(imageBitmapExteriorCrop->bitmapImage()->imageForCurrentFrame(), 124 ASSERT_NE(imageBitmapExteriorCrop->bitmapImage()->imageForCurrentFrame(),
110 imageElement->cachedImage()->getImage()->imageForCurrentFrame()); 125 imageElement->cachedImage()->getImage()->imageForCurrentFrame());
111 126
112 StaticBitmapImage* emptyImage = imageBitmapOutsideCrop->bitmapImage(); 127 StaticBitmapImage* emptyImage = imageBitmapOutsideCrop->bitmapImage();
113 ASSERT_NE(emptyImage->imageForCurrentFrame(), 128 ASSERT_NE(emptyImage->imageForCurrentFrame(),
114 imageElement->cachedImage()->getImage()->imageForCurrentFrame()); 129 imageElement->cachedImage()->getImage()->imageForCurrentFrame());
115 } 130 }
116 131
117 // Verifies that ImageBitmaps constructed from HTMLImageElements hold a 132 // Verifies that ImageBitmaps constructed from HTMLImageElements hold a
118 // reference to the original Image if the HTMLImageElement src is changed. 133 // reference to the original Image if the HTMLImageElement src is changed.
119 TEST_F(ImageBitmapTest, ImageBitmapSourceChanged) { 134 TEST_F(ImageBitmapTest, ImageBitmapSourceChanged) {
120 HTMLImageElement* image = HTMLImageElement::create(*Document::create()); 135 HTMLImageElement* image = HTMLImageElement::create(*Document::create());
121 ImageResource* originalImageResource = 136 ImageResource* originalImageResource =
122 ImageResource::create(StaticBitmapImage::create(m_image).get()); 137 ImageResource::create(StaticBitmapImage::create(m_image).get());
123 image->setImageResource(originalImageResource); 138 image->setImageResource(originalImageResource);
124 139
125 const ImageBitmapOptions defaultOptions; 140 const ImageBitmapOptions defaultOptions;
126 Optional<IntRect> cropRect = 141 Optional<IntRect> cropRect =
127 IntRect(0, 0, m_image->width(), m_image->height()); 142 IntRect(0, 0, m_image->width(), m_image->height());
128 ImageBitmap* imageBitmap = ImageBitmap::create( 143 ImageBitmap* imageBitmap = ImageBitmap::create(
129 image, cropRect, &(image->document()), defaultOptions); 144 image, cropRect, &(image->document()), defaultOptions);
130 ASSERT_EQ(imageBitmap->bitmapImage()->imageForCurrentFrame(), 145 // As we are applying color space conversion for the "default" mode,
146 // this verifies that the color corrected image is not the same as the
147 // source.
148 ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(),
131 originalImageResource->getImage()->imageForCurrentFrame()); 149 originalImageResource->getImage()->imageForCurrentFrame());
132 150
133 ImageResource* newImageResource = 151 ImageResource* newImageResource =
134 ImageResource::create(StaticBitmapImage::create(m_image2).get()); 152 ImageResource::create(StaticBitmapImage::create(m_image2).get());
135 image->setImageResource(newImageResource); 153 image->setImageResource(newImageResource);
136 154
137 // The ImageBitmap should contain the same data as the original cached image
138 { 155 {
139 ASSERT_EQ(imageBitmap->bitmapImage()->imageForCurrentFrame(), 156 ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(),
140 originalImageResource->getImage()->imageForCurrentFrame()); 157 originalImageResource->getImage()->imageForCurrentFrame());
141 SkImage* image1 = imageBitmap->bitmapImage()->imageForCurrentFrame().get(); 158 SkImage* image1 = imageBitmap->bitmapImage()->imageForCurrentFrame().get();
142 ASSERT_NE(image1, nullptr); 159 ASSERT_NE(image1, nullptr);
143 SkImage* image2 = 160 SkImage* image2 =
144 originalImageResource->getImage()->imageForCurrentFrame().get(); 161 originalImageResource->getImage()->imageForCurrentFrame().get();
145 ASSERT_NE(image2, nullptr); 162 ASSERT_NE(image2, nullptr);
146 ASSERT_EQ(image1, image2); 163 ASSERT_NE(image1, image2);
147 } 164 }
148 165
149 { 166 {
150 ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(), 167 ASSERT_NE(imageBitmap->bitmapImage()->imageForCurrentFrame(),
151 newImageResource->getImage()->imageForCurrentFrame()); 168 newImageResource->getImage()->imageForCurrentFrame());
152 SkImage* image1 = imageBitmap->bitmapImage()->imageForCurrentFrame().get(); 169 SkImage* image1 = imageBitmap->bitmapImage()->imageForCurrentFrame().get();
153 ASSERT_NE(image1, nullptr); 170 ASSERT_NE(image1, nullptr);
154 SkImage* image2 = 171 SkImage* image2 =
155 newImageResource->getImage()->imageForCurrentFrame().get(); 172 newImageResource->getImage()->imageForCurrentFrame().get();
156 ASSERT_NE(image2, nullptr); 173 ASSERT_NE(image2, nullptr);
157 ASSERT_NE(image1, image2); 174 ASSERT_NE(image1, image2);
158 } 175 }
159 } 176 }
160 177
178 enum class ColorSpaceConversion : uint8_t {
179 NONE = 0,
180 DEFAULT_NOT_COLOR_CORRECTED = 1,
181 DEFAULT_COLOR_CORRECTED = 2,
182 SRGB = 3,
183 LINEAR_RGB = 4,
184
185 LAST = LINEAR_RGB
186 };
187
188 static ImageBitmap* createImageBitmapWithColorSpaceConversion(
189 HTMLImageElement* image,
190 Optional<IntRect>& cropRect,
191 Document* document,
192 const ColorSpaceConversion& colorSpaceConversion) {
193 // Set the color space conversion in ImageBitmapOptions
194 ImageBitmapOptions options;
195 static const Vector<String> conversions = {"none", "default", "default",
196 "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
197 options.setColorSpaceConversion(
198 conversions[static_cast<uint8_t>(colorSpaceConversion)]);
199
200 // Set the runtime flags
201 bool runtimeFlag = (colorSpaceConversion !=
202 ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED);
203 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(runtimeFlag);
204 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(runtimeFlag);
205
206 // Create and return the ImageBitmap
207 return ImageBitmap::create(image, cropRect, &(image->document()), options);
208 }
209
210 TEST_F(ImageBitmapTest, ImageBitmapColorSpaceConversion) {
211 HTMLImageElement* imageElement =
212 HTMLImageElement::create(*Document::create());
213
214 SkPaint p;
215 p.setColor(SK_ColorRED);
216 sk_sp<SkColorSpace> srcRGBColorSpace =
217 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
218
219 SkImageInfo rasterImageInfo =
220 SkImageInfo::MakeN32Premul(100, 100, srcRGBColorSpace);
221 sk_sp<SkSurface> surface(SkSurface::MakeRaster(rasterImageInfo));
222 surface->getCanvas()->drawCircle(50, 50, 50, p);
223 sk_sp<SkImage> image = surface->makeImageSnapshot();
224
225 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.
226 image->readPixels(rasterImageInfo.makeWH(1, 1), (void*)(srcPixel),
227 image->width() * rasterImageInfo.bytesPerPixel(), 50, 50);
228
229 ImageResource* originalImageResource =
230 ImageResource::create(StaticBitmapImage::create(image).get());
231 imageElement->setImageResource(originalImageResource);
232
233 Optional<IntRect> cropRect = IntRect(0, 0, image->width(), image->height());
234
235 // Create and test the ImageBitmap objects.
236 // We don't check "none" color space conversion as it requires the encoded
237 // data in a format readable by ImageDecoder. Furthermore, the code path for
238 // "none" color space conversion is not affected by this CL.
239
240 sk_sp<SkColorSpace> colorSpace = nullptr;
241 SkColorType colorType = SkColorType::kN32_SkColorType;
242 SkColorSpaceXform::ColorFormat colorFormat32 =
243 (colorType == kBGRA_8888_SkColorType)
244 ? SkColorSpaceXform::ColorFormat::kBGRA_8888_ColorFormat
245 : SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
246 SkColorSpaceXform::ColorFormat colorFormat = colorFormat32;
247
248 for (uint8_t i = (uint8_t)(ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED);
249 i <= (uint8_t)(ColorSpaceConversion::LAST); i++) {
250 ColorSpaceConversion colorSpaceConversion =
251 static_cast<ColorSpaceConversion>(i);
252 ImageBitmap* imageBitmap = createImageBitmapWithColorSpaceConversion(
253 imageElement, cropRect, &(imageElement->document()),
254 colorSpaceConversion);
255 SkImage* convertedImage =
256 imageBitmap->bitmapImage()->imageForCurrentFrame().get();
257
258 switch (colorSpaceConversion) {
259 case ColorSpaceConversion::NONE:
260 NOTREACHED();
261 break;
262 case ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED:
263 //colorSpace = ImageDecoder::globalTargetColorSpace();
264 colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
265 colorFormat = colorFormat32;
266 break;
267 case ColorSpaceConversion::DEFAULT_COLOR_CORRECTED:
268 case ColorSpaceConversion::SRGB:
269 colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
270 colorFormat = colorFormat32;
271 break;
272 case ColorSpaceConversion::LINEAR_RGB:
273 colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
274 colorType = SkColorType::kRGBA_F16_SkColorType;
275 colorFormat = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
276 break;
277 default:
278 NOTREACHED();
279 }
280
281 SkImageInfo imageInfo = SkImageInfo::Make(
282 1, 1, colorType, SkAlphaType::kPremul_SkAlphaType, colorSpace);
283 auto convertedPixel = makeUnique<uint8_t>(imageInfo.bytesPerPixel());
284 convertedImage->readPixels(
285 imageInfo, (void*)(convertedPixel.get()),
286 convertedImage->width() * imageInfo.bytesPerPixel(), 50, 50);
287
288 // Transform the source pixel and check if the image bitmap color conversion
289 // is done correctly.
290 std::unique_ptr<SkColorSpaceXform> colorSpaceXform =
291 SkColorSpaceXform::New(srcRGBColorSpace.get(), colorSpace.get());
292 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.
293 colorSpaceXform->apply(colorFormat, (void*)(transformedPixel),
294 colorFormat32, (void*)(srcPixel), 1,
295 SkAlphaType::kPremul_SkAlphaType);
296
297 int compare = std::memcmp(convertedPixel.get(), transformedPixel,
298 imageInfo.bytesPerPixel());
299 ASSERT_EQ(compare, 0);
300 }
301 }
302
161 } // namespace blink 303 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698