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

Side by Side Diff: third_party/WebKit/Source/core/frame/ImageBitmap.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 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/frame/ImageBitmap.h" 5 #include "core/frame/ImageBitmap.h"
6 6
7 #include "core/html/HTMLCanvasElement.h" 7 #include "core/html/HTMLCanvasElement.h"
8 #include "core/html/HTMLVideoElement.h" 8 #include "core/html/HTMLVideoElement.h"
9 #include "core/html/ImageData.h" 9 #include "core/html/ImageData.h"
10 #include "platform/graphics/skia/SkiaUtils.h" 10 #include "platform/graphics/skia/SkiaUtils.h"
11 #include "platform/image-decoders/ImageDecoder.h" 11 #include "platform/image-decoders/ImageDecoder.h"
12 #include "third_party/skia/include/core/SkCanvas.h" 12 #include "third_party/skia/include/core/SkCanvas.h"
13 #include "third_party/skia/include/core/SkImageInfo.h"
13 #include "third_party/skia/include/core/SkSurface.h" 14 #include "third_party/skia/include/core/SkSurface.h"
14 #include "wtf/CheckedNumeric.h" 15 #include "wtf/CheckedNumeric.h"
15 #include "wtf/PtrUtil.h" 16 #include "wtf/PtrUtil.h"
16 #include "wtf/RefPtr.h" 17 #include "wtf/RefPtr.h"
17 #include <memory> 18 #include <memory>
18 19
19 namespace blink { 20 namespace blink {
20 21
21 static const char* imageOrientationFlipY = "flipY"; 22 static const char* imageOrientationFlipY = "flipY";
22 static const char* imageBitmapOptionNone = "none"; 23 static const char* imageBitmapOptionNone = "none";
23 24
24 namespace { 25 namespace {
25 26
26 struct ParsedOptions { 27 struct ParsedOptions {
27 bool flipY = false; 28 bool flipY = false;
28 bool premultiplyAlpha = true; 29 bool premultiplyAlpha = true;
29 bool shouldScaleInput = false; 30 bool shouldScaleInput = false;
30 unsigned resizeWidth = 0; 31 unsigned resizeWidth = 0;
31 unsigned resizeHeight = 0; 32 unsigned resizeHeight = 0;
32 IntRect cropRect; 33 IntRect cropRect;
33 SkFilterQuality resizeQuality = kLow_SkFilterQuality; 34 SkFilterQuality resizeQuality = kLow_SkFilterQuality;
34 // This value should be changed in the future when we support 35 sk_sp<SkColorSpace> dstColorSpace = nullptr;
35 // createImageBitmap with higher bit depth, in the parseOptions() function. 36 sk_sp<SkColorSpace> latestColorSpace = nullptr;
36 // For now, it is always 4. 37 SkColorType dstColorType = kN32_SkColorType;
37 int bytesPerPixel = 4; 38 SkColorType latestColorType = kN32_SkColorType;
38 }; 39 };
39 40
41 ParsedOptions defaultOptions() {
42 return ParsedOptions();
43 }
44
40 // The following two functions are helpers used in cropImage 45 // The following two functions are helpers used in cropImage
41 static inline IntRect normalizeRect(const IntRect& rect) { 46 static inline IntRect normalizeRect(const IntRect& rect) {
42 return IntRect(std::min(rect.x(), rect.maxX()), 47 return IntRect(std::min(rect.x(), rect.maxX()),
43 std::min(rect.y(), rect.maxY()), 48 std::min(rect.y(), rect.maxY()),
44 std::max(rect.width(), -rect.width()), 49 std::max(rect.width(), -rect.width()),
45 std::max(rect.height(), -rect.height())); 50 std::max(rect.height(), -rect.height()));
46 } 51 }
47 52
48 ParsedOptions parseOptions(const ImageBitmapOptions& options, 53 ParsedOptions parseOptions(const ImageBitmapOptions& options,
49 Optional<IntRect> cropRect, 54 Optional<IntRect> cropRect,
50 IntSize sourceSize) { 55 IntSize sourceSize) {
51 ParsedOptions parsedOptions; 56 ParsedOptions parsedOptions;
52 if (options.imageOrientation() == imageOrientationFlipY) { 57 if (options.imageOrientation() == imageOrientationFlipY) {
53 parsedOptions.flipY = true; 58 parsedOptions.flipY = true;
54 } else { 59 } else {
55 parsedOptions.flipY = false; 60 parsedOptions.flipY = false;
56 DCHECK(options.imageOrientation() == imageBitmapOptionNone); 61 DCHECK(options.imageOrientation() == imageBitmapOptionNone);
57 } 62 }
58 if (options.premultiplyAlpha() == imageBitmapOptionNone) { 63 if (options.premultiplyAlpha() == imageBitmapOptionNone) {
59 parsedOptions.premultiplyAlpha = false; 64 parsedOptions.premultiplyAlpha = false;
60 } else { 65 } else {
61 parsedOptions.premultiplyAlpha = true; 66 parsedOptions.premultiplyAlpha = true;
62 DCHECK(options.premultiplyAlpha() == "default" || 67 DCHECK(options.premultiplyAlpha() == "default" ||
63 options.premultiplyAlpha() == "premultiply"); 68 options.premultiplyAlpha() == "premultiply");
64 } 69 }
65 70
71 if (options.colorSpaceConversion() != "none") {
72 if (!RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() ||
73 !RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) {
74 DCHECK_EQ(options.colorSpaceConversion(), "default");
75 // TODO(zakerinasab): Replace sRGB with a call to
76 // ImageDecoder::globalTargetColorSpace() when the crash problem on Mac
77 // is fixed. crbug.com/668546.
78 if (RuntimeEnabledFeatures::colorCorrectRenderingDefaultModeEnabled()) {
79 parsedOptions.dstColorSpace =
80 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
81 parsedOptions.dstColorType = SkColorType::kN32_SkColorType;
82 }
83 } else {
84 if (options.colorSpaceConversion() == "default" ||
85 options.colorSpaceConversion() == "srgb") {
86 parsedOptions.dstColorSpace =
87 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
88 parsedOptions.dstColorType = SkColorType::kN32_SkColorType;
89 } else if (options.colorSpaceConversion() == "linear-rgb") {
90 parsedOptions.dstColorSpace =
91 SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
92 parsedOptions.dstColorType = SkColorType::kRGBA_F16_SkColorType;
93 } else {
94 NOTREACHED()
95 << "Invalid ImageBitmap creation attribute colorSpaceConversion: "
96 << options.colorSpaceConversion();
97 }
98 }
99 }
100
66 int sourceWidth = sourceSize.width(); 101 int sourceWidth = sourceSize.width();
67 int sourceHeight = sourceSize.height(); 102 int sourceHeight = sourceSize.height();
68 if (!cropRect) { 103 if (!cropRect) {
69 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight); 104 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight);
70 } else { 105 } else {
71 parsedOptions.cropRect = normalizeRect(*cropRect); 106 parsedOptions.cropRect = normalizeRect(*cropRect);
72 } 107 }
73 if (!options.hasResizeWidth() && !options.hasResizeHeight()) { 108 if (!options.hasResizeWidth() && !options.hasResizeHeight()) {
74 parsedOptions.resizeWidth = parsedOptions.cropRect.width(); 109 parsedOptions.resizeWidth = parsedOptions.cropRect.width();
75 parsedOptions.resizeHeight = parsedOptions.cropRect.height(); 110 parsedOptions.resizeHeight = parsedOptions.cropRect.height();
(...skipping 24 matching lines...) Expand all
100 parsedOptions.resizeQuality = kHigh_SkFilterQuality; 135 parsedOptions.resizeQuality = kHigh_SkFilterQuality;
101 else if (options.resizeQuality() == "medium") 136 else if (options.resizeQuality() == "medium")
102 parsedOptions.resizeQuality = kMedium_SkFilterQuality; 137 parsedOptions.resizeQuality = kMedium_SkFilterQuality;
103 else if (options.resizeQuality() == "pixelated") 138 else if (options.resizeQuality() == "pixelated")
104 parsedOptions.resizeQuality = kNone_SkFilterQuality; 139 parsedOptions.resizeQuality = kNone_SkFilterQuality;
105 else 140 else
106 parsedOptions.resizeQuality = kLow_SkFilterQuality; 141 parsedOptions.resizeQuality = kLow_SkFilterQuality;
107 return parsedOptions; 142 return parsedOptions;
108 } 143 }
109 144
110 bool dstBufferSizeHasOverflow(ParsedOptions options) { 145 bool dstBufferSizeHasOverflow(const ParsedOptions& options) {
111 CheckedNumeric<unsigned> totalBytes = options.cropRect.width(); 146 CheckedNumeric<unsigned> totalBytes = options.cropRect.width();
112 totalBytes *= options.cropRect.height(); 147 totalBytes *= options.cropRect.height();
113 totalBytes *= options.bytesPerPixel; 148 totalBytes *= SkColorTypeBytesPerPixel(options.latestColorType);
114 if (!totalBytes.IsValid()) 149 if (!totalBytes.IsValid())
115 return true; 150 return true;
116 151
117 if (!options.shouldScaleInput) 152 if (!options.shouldScaleInput)
118 return false; 153 return false;
119 totalBytes = options.resizeWidth; 154 totalBytes = options.resizeWidth;
120 totalBytes *= options.resizeHeight; 155 totalBytes *= options.resizeHeight;
121 totalBytes *= options.bytesPerPixel; 156 totalBytes *= SkColorTypeBytesPerPixel(options.latestColorType);
122 if (!totalBytes.IsValid()) 157 if (!totalBytes.IsValid())
123 return true; 158 return true;
124 159
125 return false; 160 return false;
126 } 161 }
127 162
128 } // namespace 163 } // namespace
129 164
130 static PassRefPtr<Uint8Array> copySkImageData(SkImage* input, 165 static PassRefPtr<Uint8Array> copySkImageData(SkImage* input,
131 const SkImageInfo& info) { 166 const SkImageInfo& info) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 srcAddr + bottomRowStartPosition); 215 srcAddr + bottomRowStartPosition);
181 } 216 }
182 } 217 }
183 } else { 218 } else {
184 if (kN32_SkColorType == kBGRA_8888_SkColorType) // needs to swizzle 219 if (kN32_SkColorType == kBGRA_8888_SkColorType) // needs to swizzle
185 for (unsigned i = 0; i < height * bytesPerRow; i += 4) 220 for (unsigned i = 0; i < height * bytesPerRow; i += 4)
186 std::swap(srcAddr[i], srcAddr[i + 2]); 221 std::swap(srcAddr[i], srcAddr[i + 2]);
187 } 222 }
188 } 223 }
189 224
190 static sk_sp<SkImage> flipSkImageVertically(SkImage* input, 225 enum AlphaPremultiplyEnforcement {
191 AlphaDisposition alphaOp) { 226 EnforceAlphaPremultiply,
227 DontEnforceAlphaPremultiply,
228 };
229
230 static sk_sp<SkImage> flipSkImageVertically(
231 SkImage* input,
232 AlphaPremultiplyEnforcement premultiplyEnforcement =
233 DontEnforceAlphaPremultiply,
234 const ParsedOptions& options = defaultOptions()) {
192 unsigned width = static_cast<unsigned>(input->width()); 235 unsigned width = static_cast<unsigned>(input->width());
193 unsigned height = static_cast<unsigned>(input->height()); 236 unsigned height = static_cast<unsigned>(input->height());
194 SkImageInfo info = SkImageInfo::MakeN32(input->width(), input->height(), 237 SkAlphaType alphaType =
195 (alphaOp == PremultiplyAlpha) 238 ((premultiplyEnforcement == EnforceAlphaPremultiply) ||
196 ? kPremul_SkAlphaType 239 options.premultiplyAlpha)
197 : kUnpremul_SkAlphaType); 240 ? kPremul_SkAlphaType
241 : kUnpremul_SkAlphaType;
242 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(),
243 options.latestColorType, alphaType,
244 options.latestColorSpace);
245
198 unsigned imageRowBytes = width * info.bytesPerPixel(); 246 unsigned imageRowBytes = width * info.bytesPerPixel();
199 RefPtr<Uint8Array> imagePixels = copySkImageData(input, info); 247 RefPtr<Uint8Array> imagePixels = copySkImageData(input, info);
200 if (!imagePixels) 248 if (!imagePixels)
201 return nullptr; 249 return nullptr;
202 for (unsigned i = 0; i < height / 2; i++) { 250 for (unsigned i = 0; i < height / 2; i++) {
203 unsigned topFirstElement = i * imageRowBytes; 251 unsigned topFirstElement = i * imageRowBytes;
204 unsigned topLastElement = (i + 1) * imageRowBytes; 252 unsigned topLastElement = (i + 1) * imageRowBytes;
205 unsigned bottomFirstElement = (height - 1 - i) * imageRowBytes; 253 unsigned bottomFirstElement = (height - 1 - i) * imageRowBytes;
206 std::swap_ranges(imagePixels->data() + topFirstElement, 254 std::swap_ranges(imagePixels->data() + topFirstElement,
207 imagePixels->data() + topLastElement, 255 imagePixels->data() + topLastElement,
208 imagePixels->data() + bottomFirstElement); 256 imagePixels->data() + bottomFirstElement);
209 } 257 }
210 return newSkImageFromRaster(info, std::move(imagePixels), imageRowBytes); 258 return newSkImageFromRaster(info, std::move(imagePixels), imageRowBytes);
211 } 259 }
212 260
213 static sk_sp<SkImage> premulSkImageToUnPremul(SkImage* input) { 261 static sk_sp<SkImage> premulSkImageToUnPremul(
214 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), 262 SkImage* input,
215 kN32_SkColorType, kUnpremul_SkAlphaType); 263 const ParsedOptions& options = defaultOptions()) {
264 SkImageInfo info = SkImageInfo::Make(
265 input->width(), input->height(), options.latestColorType,
266 kUnpremul_SkAlphaType, options.latestColorSpace);
267
216 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); 268 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info);
217 if (!dstPixels) 269 if (!dstPixels)
218 return nullptr; 270 return nullptr;
219 return newSkImageFromRaster( 271 return newSkImageFromRaster(
220 info, std::move(dstPixels), 272 info, std::move(dstPixels),
221 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); 273 static_cast<unsigned>(input->width()) * info.bytesPerPixel());
222 } 274 }
223 275
224 static sk_sp<SkImage> unPremulSkImageToPremul(SkImage* input) { 276 static sk_sp<SkImage> unPremulSkImageToPremul(
225 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), 277 SkImage* input,
226 kN32_SkColorType, kPremul_SkAlphaType); 278 const ParsedOptions& options = defaultOptions()) {
279 SkImageInfo info = SkImageInfo::Make(
280 input->width(), input->height(), options.latestColorType,
281 kPremul_SkAlphaType, options.latestColorSpace);
282
227 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); 283 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info);
228 if (!dstPixels) 284 if (!dstPixels)
229 return nullptr; 285 return nullptr;
230 return newSkImageFromRaster( 286 return newSkImageFromRaster(
231 info, std::move(dstPixels), 287 info, std::move(dstPixels),
232 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); 288 static_cast<unsigned>(input->width()) * info.bytesPerPixel());
233 } 289 }
234 290
291 // This code is borrowed from third_party/skia/src/codec/SkCodecPriv.h
292 // If you need to change this, please check SkColorSpaceXform::ColorFormat
293 // and SkColorType for proper coverage.
294 static inline SkColorSpaceXform::ColorFormat getXformFormat(
295 SkColorType colorType) {
296 switch (colorType) {
297 case kRGBA_8888_SkColorType:
298 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
299 case kBGRA_8888_SkColorType:
300 return SkColorSpaceXform::kBGRA_8888_ColorFormat;
301 case kRGBA_F16_SkColorType:
302 return SkColorSpaceXform::kRGBA_F16_ColorFormat;
303 default:
304 NOTREACHED();
305 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
306 }
307 }
308
309 static inline void updateLatestColorInformation(ParsedOptions& options) {
310 options.latestColorType = options.dstColorType;
311 options.latestColorSpace = options.dstColorSpace;
312 }
313
314 // TODO (zakrinasab). Rewrite this when SkImage::readPixels() respectes the
315 // color space of the passed SkImageInfo (crbug.com/skia/6021) and SkImage
316 // exposes SkColorSpace and SkColorType (crbug.com/skia/6022).
317
318 static void applyColorSpaceConversion(sk_sp<SkImage>& image,
319 ParsedOptions& options) {
320 if (!options.dstColorSpace)
321 return;
322 if (SkColorSpace::Equals(options.latestColorSpace.get(),
323 options.dstColorSpace.get()))
324 return;
325
326 // If we have the color space information of the source image, we can use
327 // SkColorSpaceXform. Otherwise, we need to draw the image on a canvas and
328 // take a snapshot.
329 if (options.latestColorSpace) {
330 SkImageInfo info = SkImageInfo::Make(
331 image->width(), image->height(), options.latestColorType,
332 image->alphaType(), options.latestColorSpace);
333 size_t size = image->width() * image->height() * info.bytesPerPixel();
334 std::unique_ptr<uint8_t[]> srcPixels(new uint8_t[size]());
335 if (!image->readPixels(info, &srcPixels,
336 image->width() * info.bytesPerPixel(), 0, 0)) {
337 return;
338 }
339
340 // For in-place color correction, bytes per pixel must be equal for source
341 // and destination color spaces.
342 std::unique_ptr<uint8_t[]> dstPixels = nullptr;
343 if (SkColorTypeBytesPerPixel(options.dstColorType) !=
344 SkColorTypeBytesPerPixel(options.latestColorType)) {
345 size = image->width() * image->height() *
346 SkColorTypeBytesPerPixel(options.latestColorType);
347 dstPixels = std::unique_ptr<uint8_t[]>(new uint8_t[size]());
348 }
349
350 std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(
351 options.latestColorSpace.get(), options.dstColorSpace.get());
352 xform->apply(getXformFormat(options.dstColorType),
353 dstPixels ? &dstPixels : &srcPixels,
354 getXformFormat(options.latestColorType), &srcPixels,
355 image->width() * image->height(), kUnpremul_SkAlphaType);
356
357 SkImageInfo dstInfo =
358 SkImageInfo::Make(image->width(), image->height(), options.dstColorType,
359 image->alphaType(), options.dstColorSpace);
360 sk_sp<SkData> data(SkData::MakeWithoutCopy(&dstPixels, size));
361 sk_sp<SkImage> coloredImage = SkImage::MakeRasterData(
362 dstInfo, data, image->width() * dstInfo.bytesPerPixel());
363 if (coloredImage) {
364 updateLatestColorInformation(options);
365 image = coloredImage;
366 return;
367 }
368 return;
369 }
370
371 // Skia does not support drawing to unpremul surfaces/canvases.
372 sk_sp<SkImage> unPremulImage = nullptr;
373 if (image->alphaType() == kUnpremul_SkAlphaType)
374 unPremulImage = unPremulSkImageToPremul(image.get(), options);
375
376 // If the color space of the source SkImage is null, the following code
377 // does not do any color conversion even thought the new SkImage will be
378 // tagged by the new color space. If this is the case, the following code
379 // will tag a wrong color space to the SkImage. However, this cannot be
380 // addressed here and the code that creates the SkImage must tag the
381 // SkImage with proper color space.
382 SkImageInfo imageInfo = SkImageInfo::Make(
383 image->width(), image->height(), options.dstColorType,
384 unPremulImage ? unPremulImage->alphaType() : image->alphaType(),
385 options.dstColorSpace);
386 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo);
387 surface->getCanvas()->drawImage(
388 unPremulImage ? unPremulImage : sk_sp<SkImage>(image), 0, 0);
389 sk_sp<SkImage> coloredImage = surface->makeImageSnapshot();
390 updateLatestColorInformation(options);
391 image = coloredImage;
392 return;
393 }
394
235 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( 395 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder(
236 std::unique_ptr<ImageDecoder> decoder) { 396 std::unique_ptr<ImageDecoder> decoder,
397 SkColorType* decodedColorType,
398 sk_sp<SkColorSpace>* decodedColorSpace,
399 ColorSpaceInfoUpdate colorSpaceInfoUpdate) {
237 if (!decoder->frameCount()) 400 if (!decoder->frameCount())
238 return nullptr; 401 return nullptr;
239 ImageFrame* frame = decoder->frameBufferAtIndex(0); 402 ImageFrame* frame = decoder->frameBufferAtIndex(0);
240 if (!frame || frame->getStatus() != ImageFrame::FrameComplete) 403 if (!frame || frame->getStatus() != ImageFrame::FrameComplete)
241 return nullptr; 404 return nullptr;
242 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty()); 405 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty());
243 return frame->finalizePixelsAndGetImage(); 406 sk_sp<SkImage> image = frame->finalizePixelsAndGetImage();
407 if (colorSpaceInfoUpdate == UpdateColorSpaceInformation) {
408 *decodedColorType = frame->bitmap().colorType();
409 *decodedColorSpace = sk_sp<SkColorSpace>(frame->bitmap().colorSpace());
410 }
411 return image;
244 } 412 }
245 413
246 bool ImageBitmap::isResizeOptionValid(const ImageBitmapOptions& options, 414 bool ImageBitmap::isResizeOptionValid(const ImageBitmapOptions& options,
247 ExceptionState& exceptionState) { 415 ExceptionState& exceptionState) {
248 if ((options.hasResizeWidth() && options.resizeWidth() == 0) || 416 if ((options.hasResizeWidth() && options.resizeWidth() == 0) ||
249 (options.hasResizeHeight() && options.resizeHeight() == 0)) { 417 (options.hasResizeHeight() && options.resizeHeight() == 0)) {
250 exceptionState.throwDOMException( 418 exceptionState.throwDOMException(
251 InvalidStateError, 419 InvalidStateError,
252 "The resizeWidth or/and resizeHeight is equal to 0."); 420 "The resizeWidth or/and resizeHeight is equal to 0.");
253 return false; 421 return false;
(...skipping 11 matching lines...) Expand all
265 return false; 433 return false;
266 } 434 }
267 return true; 435 return true;
268 } 436 }
269 437
270 // The parameter imageFormat indicates whether the first parameter "image" is 438 // The parameter imageFormat indicates whether the first parameter "image" is
271 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in 439 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in
272 // premuliplied format For example, if the image is already in unpremultiplied 440 // premuliplied format For example, if the image is already in unpremultiplied
273 // format and we want the created ImageBitmap in the same format, then we don't 441 // format and we want the created ImageBitmap in the same format, then we don't
274 // need to use the ImageDecoder to decode the image. 442 // need to use the ImageDecoder to decode the image.
275 static PassRefPtr<StaticBitmapImage> cropImage( 443 static PassRefPtr<StaticBitmapImage> cropImageAndApplyColorSpaceConversion(
276 Image* image, 444 Image* image,
277 const ParsedOptions& parsedOptions, 445 ParsedOptions& parsedOptions,
278 AlphaDisposition imageFormat, 446 AlphaDisposition imageFormat,
279 ColorBehavior colorBehavior) { 447 ColorBehavior colorBehavior) {
280 ASSERT(image); 448 ASSERT(image);
281 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); 449 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height()));
282 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); 450 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect);
283 451
284 // In the case when cropRect doesn't intersect the source image and it 452 // In the case when cropRect doesn't intersect the source image and it
285 // requires a umpremul image We immediately return a transparent black image 453 // requires a umpremul image We immediately return a transparent black image
286 // with cropRect.size() 454 // with cropRect.size()
287 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) { 455 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) {
(...skipping 22 matching lines...) Expand all
310 !skiaImage) && 478 !skiaImage) &&
311 image->data() && imageFormat == PremultiplyAlpha) || 479 image->data() && imageFormat == PremultiplyAlpha) ||
312 colorBehavior.isIgnore()) { 480 colorBehavior.isIgnore()) {
313 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create( 481 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create(
314 image->data(), true, 482 image->data(), true,
315 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied 483 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied
316 : ImageDecoder::AlphaNotPremultiplied, 484 : ImageDecoder::AlphaNotPremultiplied,
317 colorBehavior)); 485 colorBehavior));
318 if (!decoder) 486 if (!decoder)
319 return nullptr; 487 return nullptr;
320 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder)); 488 skiaImage = ImageBitmap::getSkImageFromDecoder(
489 std::move(decoder), &parsedOptions.latestColorType,
490 &parsedOptions.latestColorSpace, UpdateColorSpaceInformation);
321 if (!skiaImage) 491 if (!skiaImage)
322 return nullptr; 492 return nullptr;
323 } 493 }
324 494
325 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { 495 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) {
326 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); 496 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect);
327 if (parsedOptions.flipY) 497 if (parsedOptions.dstColorSpace)
498 applyColorSpaceConversion(croppedSkImage, parsedOptions);
499 if (parsedOptions.flipY) {
328 return StaticBitmapImage::create(flipSkImageVertically( 500 return StaticBitmapImage::create(flipSkImageVertically(
329 croppedSkImage.get(), parsedOptions.premultiplyAlpha 501 croppedSkImage.get(), DontEnforceAlphaPremultiply, parsedOptions));
330 ? PremultiplyAlpha 502 }
331 : DontPremultiplyAlpha));
332 // Special case: The first parameter image is unpremul but we need to turn 503 // Special case: The first parameter image is unpremul but we need to turn
333 // it into premul. 504 // it into premul.
334 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) 505 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha)
335 return StaticBitmapImage::create( 506 return StaticBitmapImage::create(
336 unPremulSkImageToPremul(croppedSkImage.get())); 507 unPremulSkImageToPremul(croppedSkImage.get()));
337 // Call preroll to trigger image decoding. 508 // Call preroll to trigger image decoding.
338 croppedSkImage->preroll(); 509 croppedSkImage->preroll();
339 return StaticBitmapImage::create(std::move(croppedSkImage)); 510 return StaticBitmapImage::create(std::move(croppedSkImage));
340 } 511 }
341 512
(...skipping 21 matching lines...) Expand all
363 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth, 534 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth,
364 parsedOptions.resizeHeight); 535 parsedOptions.resizeHeight);
365 SkPaint paint; 536 SkPaint paint;
366 paint.setFilterQuality(parsedOptions.resizeQuality); 537 paint.setFilterQuality(parsedOptions.resizeQuality);
367 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, 538 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect,
368 &paint); 539 &paint);
369 } else { 540 } else {
370 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); 541 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop);
371 } 542 }
372 skiaImage = surface->makeImageSnapshot(); 543 skiaImage = surface->makeImageSnapshot();
544 if (parsedOptions.dstColorSpace)
545 applyColorSpaceConversion(skiaImage, parsedOptions);
373 546
374 if (parsedOptions.premultiplyAlpha) { 547 if (parsedOptions.premultiplyAlpha) {
375 if (imageFormat == DontPremultiplyAlpha) 548 if (imageFormat == DontPremultiplyAlpha)
376 return StaticBitmapImage::create( 549 return StaticBitmapImage::create(
377 unPremulSkImageToPremul(skiaImage.get())); 550 unPremulSkImageToPremul(skiaImage.get()));
378 return StaticBitmapImage::create(std::move(skiaImage)); 551 return StaticBitmapImage::create(std::move(skiaImage));
379 } 552 }
380 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); 553 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get()));
381 } 554 }
382 555
383 ImageBitmap::ImageBitmap(HTMLImageElement* image, 556 ImageBitmap::ImageBitmap(HTMLImageElement* image,
384 Optional<IntRect> cropRect, 557 Optional<IntRect> cropRect,
385 Document* document, 558 Document* document,
386 const ImageBitmapOptions& options) { 559 const ImageBitmapOptions& options) {
387 RefPtr<Image> input = image->cachedImage()->getImage(); 560 RefPtr<Image> input = image->cachedImage()->getImage();
388 ParsedOptions parsedOptions = 561 ParsedOptions parsedOptions =
389 parseOptions(options, cropRect, image->bitmapSourceSize()); 562 parseOptions(options, cropRect, image->bitmapSourceSize());
390 if (dstBufferSizeHasOverflow(parsedOptions)) 563 if (dstBufferSizeHasOverflow(parsedOptions))
391 return; 564 return;
392 565
393 if (options.colorSpaceConversion() == "none") { 566 if (options.colorSpaceConversion() == "none") {
394 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 567 m_image = cropImageAndApplyColorSpaceConversion(
395 ColorBehavior::ignore()); 568 input.get(), parsedOptions, PremultiplyAlpha, ColorBehavior::ignore());
396 } else { 569 } else {
397 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 570 m_image = cropImageAndApplyColorSpaceConversion(
398 ColorBehavior::transformToGlobalTarget()); 571 input.get(), parsedOptions, PremultiplyAlpha,
572 ColorBehavior::transformToGlobalTarget());
399 } 573 }
574
400 if (!m_image) 575 if (!m_image)
401 return; 576 return;
402 // In the case where the source image is lazy-decoded, m_image may not be in 577 // In the case where the source image is lazy-decoded, m_image may not be in
403 // a decoded state, we trigger it here. 578 // a decoded state, we trigger it here.
404 // TODO(ccameron): Canvas should operate in sRGB and not display space. 579 // TODO(ccameron): Canvas should operate in sRGB and not display space.
405 // https://crbug.com/667431 580 // https://crbug.com/667431
406 sk_sp<SkImage> skImage = 581 sk_sp<SkImage> skImage =
407 m_image->imageForCurrentFrame(ColorBehavior::transformToGlobalTarget()); 582 m_image->imageForCurrentFrame(ColorBehavior::transformToGlobalTarget());
408 SkPixmap pixmap; 583 SkPixmap pixmap;
409 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { 584 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) {
410 sk_sp<SkSurface> surface = 585 SkImageInfo imageInfo = SkImageInfo::Make(
411 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); 586 skImage->width(), skImage->height(), parsedOptions.dstColorType,
587 kPremul_SkAlphaType, parsedOptions.dstColorSpace);
588 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo);
412 surface->getCanvas()->drawImage(skImage, 0, 0); 589 surface->getCanvas()->drawImage(skImage, 0, 0);
413 m_image = StaticBitmapImage::create(surface->makeImageSnapshot()); 590 m_image = StaticBitmapImage::create(surface->makeImageSnapshot());
414 } 591 }
415 if (!m_image) 592 if (!m_image)
416 return; 593 return;
417 m_image->setOriginClean( 594 m_image->setOriginClean(
418 !image->wouldTaintOrigin(document->getSecurityOrigin())); 595 !image->wouldTaintOrigin(document->getSecurityOrigin()));
419 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 596 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
420 } 597 }
421 598
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 ParsedOptions parsedOptions = 661 ParsedOptions parsedOptions =
485 parseOptions(options, cropRect, IntSize(input->width(), input->height())); 662 parseOptions(options, cropRect, IntSize(input->width(), input->height()));
486 if (dstBufferSizeHasOverflow(parsedOptions)) 663 if (dstBufferSizeHasOverflow(parsedOptions))
487 return; 664 return;
488 665
489 bool isPremultiplyAlphaReverted = false; 666 bool isPremultiplyAlphaReverted = false;
490 if (!parsedOptions.premultiplyAlpha) { 667 if (!parsedOptions.premultiplyAlpha) {
491 parsedOptions.premultiplyAlpha = true; 668 parsedOptions.premultiplyAlpha = true;
492 isPremultiplyAlphaReverted = true; 669 isPremultiplyAlphaReverted = true;
493 } 670 }
494 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 671 m_image = cropImageAndApplyColorSpaceConversion(
495 ColorBehavior::transformToGlobalTarget()); 672 input.get(), parsedOptions, PremultiplyAlpha,
673 ColorBehavior::transformToGlobalTarget());
496 if (!m_image) 674 if (!m_image)
497 return; 675 return;
498 if (isPremultiplyAlphaReverted) { 676 if (isPremultiplyAlphaReverted) {
499 parsedOptions.premultiplyAlpha = false; 677 parsedOptions.premultiplyAlpha = false;
500 // TODO(ccameron): Canvas should operate in sRGB and not display space. 678 // TODO(ccameron): Canvas should operate in sRGB and not display space.
501 // https://crbug.com/667431 679 // https://crbug.com/667431
502 m_image = StaticBitmapImage::create(premulSkImageToUnPremul( 680 m_image = StaticBitmapImage::create(premulSkImageToUnPremul(
503 m_image->imageForCurrentFrame(ColorBehavior::transformToGlobalTarget()) 681 m_image->imageForCurrentFrame(ColorBehavior::transformToGlobalTarget())
504 .get())); 682 .get()));
505 } 683 }
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 std::min(0, -parsedOptions.cropRect.y())); 849 std::min(0, -parsedOptions.cropRect.y()));
672 if (parsedOptions.cropRect.x() < 0) 850 if (parsedOptions.cropRect.x() < 0)
673 dstPoint.setX(-parsedOptions.cropRect.x()); 851 dstPoint.setX(-parsedOptions.cropRect.x());
674 if (parsedOptions.cropRect.y() < 0) 852 if (parsedOptions.cropRect.y() < 0)
675 dstPoint.setY(-parsedOptions.cropRect.y()); 853 dstPoint.setY(-parsedOptions.cropRect.y());
676 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(), 854 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(),
677 srcRect, dstPoint); 855 srcRect, dstPoint);
678 sk_sp<SkImage> skImage = 856 sk_sp<SkImage> skImage =
679 buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown); 857 buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown);
680 if (parsedOptions.flipY) 858 if (parsedOptions.flipY)
681 skImage = flipSkImageVertically(skImage.get(), PremultiplyAlpha); 859 skImage = flipSkImageVertically(skImage.get(), EnforceAlphaPremultiply);
682 if (!skImage) 860 if (!skImage)
683 return; 861 return;
684 if (parsedOptions.shouldScaleInput) { 862 if (parsedOptions.shouldScaleInput) {
685 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( 863 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(
686 parsedOptions.resizeWidth, parsedOptions.resizeHeight); 864 parsedOptions.resizeWidth, parsedOptions.resizeHeight);
687 if (!surface) 865 if (!surface)
688 return; 866 return;
689 SkPaint paint; 867 SkPaint paint;
690 paint.setFilterQuality(parsedOptions.resizeQuality); 868 paint.setFilterQuality(parsedOptions.resizeQuality);
691 SkRect dstDrawRect = 869 SkRect dstDrawRect =
692 SkRect::MakeWH(parsedOptions.resizeWidth, parsedOptions.resizeHeight); 870 SkRect::MakeWH(parsedOptions.resizeWidth, parsedOptions.resizeHeight);
693 surface->getCanvas()->drawImageRect(skImage, dstDrawRect, &paint); 871 surface->getCanvas()->drawImageRect(skImage, dstDrawRect, &paint);
694 skImage = surface->makeImageSnapshot(); 872 skImage = surface->makeImageSnapshot();
695 } 873 }
696 m_image = StaticBitmapImage::create(std::move(skImage)); 874 m_image = StaticBitmapImage::create(std::move(skImage));
697 } 875 }
698 876
699 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, 877 ImageBitmap::ImageBitmap(ImageBitmap* bitmap,
700 Optional<IntRect> cropRect, 878 Optional<IntRect> cropRect,
701 const ImageBitmapOptions& options) { 879 const ImageBitmapOptions& options) {
702 RefPtr<Image> input = bitmap->bitmapImage(); 880 RefPtr<Image> input = bitmap->bitmapImage();
703 if (!input) 881 if (!input)
704 return; 882 return;
705 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()); 883 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size());
706 if (dstBufferSizeHasOverflow(parsedOptions)) 884 if (dstBufferSizeHasOverflow(parsedOptions))
707 return; 885 return;
708 886
709 m_image = cropImage( 887 m_image = cropImageAndApplyColorSpaceConversion(
710 input.get(), parsedOptions, 888 input.get(), parsedOptions,
711 bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha, 889 bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha,
712 ColorBehavior::transformToGlobalTarget()); 890 ColorBehavior::transformToGlobalTarget());
713 if (!m_image) 891 if (!m_image)
714 return; 892 return;
715 m_image->setOriginClean(bitmap->originClean()); 893 m_image->setOriginClean(bitmap->originClean());
716 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 894 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
717 } 895 }
718 896
719 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, 897 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image,
720 Optional<IntRect> cropRect, 898 Optional<IntRect> cropRect,
721 const ImageBitmapOptions& options) { 899 const ImageBitmapOptions& options) {
722 bool originClean = image->originClean(); 900 bool originClean = image->originClean();
723 RefPtr<Image> input = image; 901 RefPtr<Image> input = image;
724 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()); 902 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size());
725 if (dstBufferSizeHasOverflow(parsedOptions)) 903 if (dstBufferSizeHasOverflow(parsedOptions))
726 return; 904 return;
727 905
728 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 906 m_image = cropImageAndApplyColorSpaceConversion(
729 ColorBehavior::transformToGlobalTarget()); 907 input.get(), parsedOptions, PremultiplyAlpha,
908 ColorBehavior::transformToGlobalTarget());
730 if (!m_image) 909 if (!m_image)
731 return; 910 return;
732 911
733 m_image->setOriginClean(originClean); 912 m_image->setOriginClean(originClean);
734 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 913 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
735 } 914 }
736 915
737 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) { 916 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) {
738 m_image = image; 917 m_image = image;
739 } 918 }
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
879 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, 1058 void ImageBitmap::adjustDrawRects(FloatRect* srcRect,
880 FloatRect* dstRect) const {} 1059 FloatRect* dstRect) const {}
881 1060
882 FloatSize ImageBitmap::elementSize(const FloatSize&) const { 1061 FloatSize ImageBitmap::elementSize(const FloatSize&) const {
883 return FloatSize(width(), height()); 1062 return FloatSize(width(), height());
884 } 1063 }
885 1064
886 DEFINE_TRACE(ImageBitmap) {} 1065 DEFINE_TRACE(ImageBitmap) {}
887 1066
888 } // namespace blink 1067 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/frame/ImageBitmap.h ('k') | third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698