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

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

Issue 2522693002: Color correct ImageBitmap(HTMLImageElement*) constructor (Closed)
Patch Set: Rebaseline 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(ParsedOptions options) {
dcheng 2016/12/11 20:11:58 Nit: not introduced by this CL, but this should be
zakerinasab1 2016/12/12 18:35:21 Done.
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 static sk_sp<SkImage> flipSkImageVertically(
191 AlphaDisposition alphaOp) { 226 SkImage* input,
227 bool enforceAlphaPremultiply = false,
dcheng 2016/12/11 20:11:58 Ditto about preferring enums over bools here as we
zakerinasab1 2016/12/12 18:35:21 Done.
228 const ParsedOptions& options = defaultOptions()) {
192 unsigned width = static_cast<unsigned>(input->width()); 229 unsigned width = static_cast<unsigned>(input->width());
193 unsigned height = static_cast<unsigned>(input->height()); 230 unsigned height = static_cast<unsigned>(input->height());
194 SkImageInfo info = SkImageInfo::MakeN32(input->width(), input->height(), 231 SkAlphaType alphaType = (enforceAlphaPremultiply || options.premultiplyAlpha)
195 (alphaOp == PremultiplyAlpha) 232 ? kPremul_SkAlphaType
196 ? kPremul_SkAlphaType 233 : kUnpremul_SkAlphaType;
197 : kUnpremul_SkAlphaType); 234 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(),
235 options.latestColorType, alphaType,
236 options.latestColorSpace);
237
198 unsigned imageRowBytes = width * info.bytesPerPixel(); 238 unsigned imageRowBytes = width * info.bytesPerPixel();
199 RefPtr<Uint8Array> imagePixels = copySkImageData(input, info); 239 RefPtr<Uint8Array> imagePixels = copySkImageData(input, info);
200 if (!imagePixels) 240 if (!imagePixels)
201 return nullptr; 241 return nullptr;
202 for (unsigned i = 0; i < height / 2; i++) { 242 for (unsigned i = 0; i < height / 2; i++) {
203 unsigned topFirstElement = i * imageRowBytes; 243 unsigned topFirstElement = i * imageRowBytes;
204 unsigned topLastElement = (i + 1) * imageRowBytes; 244 unsigned topLastElement = (i + 1) * imageRowBytes;
205 unsigned bottomFirstElement = (height - 1 - i) * imageRowBytes; 245 unsigned bottomFirstElement = (height - 1 - i) * imageRowBytes;
206 std::swap_ranges(imagePixels->data() + topFirstElement, 246 std::swap_ranges(imagePixels->data() + topFirstElement,
207 imagePixels->data() + topLastElement, 247 imagePixels->data() + topLastElement,
208 imagePixels->data() + bottomFirstElement); 248 imagePixels->data() + bottomFirstElement);
209 } 249 }
210 return newSkImageFromRaster(info, std::move(imagePixels), imageRowBytes); 250 return newSkImageFromRaster(info, std::move(imagePixels), imageRowBytes);
211 } 251 }
212 252
213 static sk_sp<SkImage> premulSkImageToUnPremul(SkImage* input) { 253 static sk_sp<SkImage> premulSkImageToUnPremul(
214 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), 254 SkImage* input,
215 kN32_SkColorType, kUnpremul_SkAlphaType); 255 const ParsedOptions& options = defaultOptions()) {
256 SkImageInfo info = SkImageInfo::Make(
257 input->width(), input->height(), options.latestColorType,
258 kUnpremul_SkAlphaType, options.latestColorSpace);
259
216 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); 260 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info);
217 if (!dstPixels) 261 if (!dstPixels)
218 return nullptr; 262 return nullptr;
219 return newSkImageFromRaster( 263 return newSkImageFromRaster(
220 info, std::move(dstPixels), 264 info, std::move(dstPixels),
221 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); 265 static_cast<unsigned>(input->width()) * info.bytesPerPixel());
222 } 266 }
223 267
224 static sk_sp<SkImage> unPremulSkImageToPremul(SkImage* input) { 268 static sk_sp<SkImage> unPremulSkImageToPremul(
225 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), 269 SkImage* input,
226 kN32_SkColorType, kPremul_SkAlphaType); 270 const ParsedOptions& options = defaultOptions()) {
271 SkImageInfo info = SkImageInfo::Make(
272 input->width(), input->height(), options.latestColorType,
273 kPremul_SkAlphaType, options.latestColorSpace);
274
227 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); 275 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info);
228 if (!dstPixels) 276 if (!dstPixels)
229 return nullptr; 277 return nullptr;
230 return newSkImageFromRaster( 278 return newSkImageFromRaster(
231 info, std::move(dstPixels), 279 info, std::move(dstPixels),
232 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); 280 static_cast<unsigned>(input->width()) * info.bytesPerPixel());
233 } 281 }
234 282
283 // This code is borrowed from third_party/skia/src/codec/SkCodecPriv.h
284 // If you need to change this, please check SkColorSpaceXform::ColorFormat
285 // and SkColorType for proper coverage.
286 static inline SkColorSpaceXform::ColorFormat getXformFormat(
287 SkColorType colorType) {
288 switch (colorType) {
289 case kRGBA_8888_SkColorType:
290 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
291 case kBGRA_8888_SkColorType:
292 return SkColorSpaceXform::kBGRA_8888_ColorFormat;
293 case kRGBA_F16_SkColorType:
294 return SkColorSpaceXform::kRGBA_F16_ColorFormat;
295 default:
296 SkASSERT(false);
dcheng 2016/12/11 20:11:58 I think we should be writing NOTREACHED in Blink c
zakerinasab1 2016/12/12 18:35:21 Done.
297 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
298 }
299 }
300
301 static inline void updateLatestColorInformation(ParsedOptions& options) {
302 options.latestColorType = options.dstColorType;
303 options.latestColorSpace = options.dstColorSpace;
304 }
305
306 // TODO (zakrinasab). Rewrite this when SkImage::readPixels() respectes the
307 // color space of the passed SkImageInfo (crbug.com/skia/6021) and SkImage
308 // exposes SkColorSpace and SkColorType (crbug.com/skia/6022).
309
310 static sk_sp<SkImage> applyColorSpaceConversion(const sk_sp<SkImage> image,
dcheng 2016/12/11 20:11:58 This refs the SkImage unnecessarily, as this metho
zakerinasab1 2016/12/12 18:35:21 I changed the function signature. PTAL. Passing Sk
dcheng 2016/12/12 21:13:57 Ah... another option is to pass by value (instead
311 ParsedOptions& options) {
312 if (!options.dstColorSpace)
313 return image;
314 if (SkColorSpace::Equals(options.latestColorSpace.get(),
315 options.dstColorSpace.get()))
316 return image;
317
318 // If we have the color space information of the source image, we can use
319 // SkColorSpaceXform. Otherwise, we need to draw the image on a canvas and
320 // take a snapshot.
321 if (options.latestColorSpace) {
322 SkImageInfo info = SkImageInfo::Make(
323 image->width(), image->height(), options.latestColorType,
324 image->alphaType(), options.latestColorSpace);
325 size_t size = image->width() * image->height() * info.bytesPerPixel();
326 auto srcPixels = WTF::makeUnique<uint8_t>(size);
327 if (!image->readPixels(info, &srcPixels,
328 image->width() * info.bytesPerPixel(), 0, 0)) {
329 return image;
330 }
331
332 // For in-place color correction, bytes per pixel must be equal for source
333 // and destination color spaces.
334 std::unique_ptr<uint8_t> dstPixels = nullptr;
335 if (SkColorTypeBytesPerPixel(options.dstColorType) !=
336 SkColorTypeBytesPerPixel(options.latestColorType)) {
337 size = image->width() * image->height() *
338 SkColorTypeBytesPerPixel(options.latestColorType);
339 dstPixels = WTF::makeUnique<uint8_t>(size);
340 }
341
342 std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(
343 options.latestColorSpace.get(), options.dstColorSpace.get());
344 xform->apply(getXformFormat(options.dstColorType),
345 dstPixels ? &dstPixels : &srcPixels,
346 getXformFormat(options.latestColorType), &srcPixels,
347 image->width() * image->height(), kUnpremul_SkAlphaType);
348
349 SkImageInfo dstInfo =
350 SkImageInfo::Make(image->width(), image->height(), options.dstColorType,
351 image->alphaType(), options.dstColorSpace);
352 sk_sp<SkData> data(SkData::MakeWithoutCopy(&dstPixels, size));
353 sk_sp<SkImage> coloredImage = SkImage::MakeRasterData(
354 dstInfo, data, image->width() * dstInfo.bytesPerPixel());
355 if (coloredImage) {
356 updateLatestColorInformation(options);
357 return coloredImage;
358 }
359 return image;
360 }
361
362 // Skia does not support drawing to unpremul surfaces/canvases.
363 sk_sp<SkImage> unPremulImage = nullptr;
364 if (image->alphaType() == kUnpremul_SkAlphaType)
365 unPremulImage = unPremulSkImageToPremul(image.get(), options);
366
367 // If the color space of the source SkImage is null, the following code
368 // does not do any color conversion even thought the new SkImage will be
369 // tagged by the new color space. If this is the case, the following code
370 // will tag a wrong color space to the SkImage. However, this cannot be
371 // addressed here and the code that creates the SkImage must tag the
372 // SkImage with proper color space.
373 SkImageInfo imageInfo = SkImageInfo::Make(
374 image->width(), image->height(), options.dstColorType,
375 unPremulImage ? unPremulImage->alphaType() : image->alphaType(),
376 options.dstColorSpace);
377 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo);
378 surface->getCanvas()->drawImage(unPremulImage ? unPremulImage : image, 0, 0);
379 sk_sp<SkImage> coloredImage = surface->makeImageSnapshot();
380 updateLatestColorInformation(options);
381 return coloredImage;
382 }
383
235 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( 384 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder(
236 std::unique_ptr<ImageDecoder> decoder) { 385 std::unique_ptr<ImageDecoder> decoder,
386 SkColorType* decodedColorType,
387 sk_sp<SkColorSpace> decodedColorSpace,
388 bool returnColorSpaceInformation) {
237 if (!decoder->frameCount()) 389 if (!decoder->frameCount())
238 return nullptr; 390 return nullptr;
239 ImageFrame* frame = decoder->frameBufferAtIndex(0); 391 ImageFrame* frame = decoder->frameBufferAtIndex(0);
240 if (!frame || frame->getStatus() != ImageFrame::FrameComplete) 392 if (!frame || frame->getStatus() != ImageFrame::FrameComplete)
241 return nullptr; 393 return nullptr;
242 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty()); 394 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty());
243 return frame->finalizePixelsAndGetImage(); 395 sk_sp<SkImage> image = frame->finalizePixelsAndGetImage();
396 if (returnColorSpaceInformation) {
397 *decodedColorType = frame->bitmap().colorType();
398 decodedColorSpace = sk_sp<SkColorSpace>(frame->bitmap().colorSpace());
dcheng 2016/12/11 20:11:58 This parameter is passed by value, so the caller w
zakerinasab1 2016/12/12 18:35:21 The parameter is fixed. The flag is needed as the
399 }
400 return image;
244 } 401 }
245 402
246 bool ImageBitmap::isResizeOptionValid(const ImageBitmapOptions& options, 403 bool ImageBitmap::isResizeOptionValid(const ImageBitmapOptions& options,
247 ExceptionState& exceptionState) { 404 ExceptionState& exceptionState) {
248 if ((options.hasResizeWidth() && options.resizeWidth() == 0) || 405 if ((options.hasResizeWidth() && options.resizeWidth() == 0) ||
249 (options.hasResizeHeight() && options.resizeHeight() == 0)) { 406 (options.hasResizeHeight() && options.resizeHeight() == 0)) {
250 exceptionState.throwDOMException( 407 exceptionState.throwDOMException(
251 InvalidStateError, 408 InvalidStateError,
252 "The resizeWidth or/and resizeHeight is equal to 0."); 409 "The resizeWidth or/and resizeHeight is equal to 0.");
253 return false; 410 return false;
(...skipping 11 matching lines...) Expand all
265 return false; 422 return false;
266 } 423 }
267 return true; 424 return true;
268 } 425 }
269 426
270 // The parameter imageFormat indicates whether the first parameter "image" is 427 // The parameter imageFormat indicates whether the first parameter "image" is
271 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in 428 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in
272 // premuliplied format For example, if the image is already in unpremultiplied 429 // 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 430 // 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. 431 // need to use the ImageDecoder to decode the image.
275 static PassRefPtr<StaticBitmapImage> cropImage( 432 static PassRefPtr<StaticBitmapImage> cropImageAndApplyColorSpaceConversion(
276 Image* image, 433 Image* image,
277 const ParsedOptions& parsedOptions, 434 ParsedOptions& parsedOptions,
278 AlphaDisposition imageFormat, 435 AlphaDisposition imageFormat,
279 ColorBehavior colorBehavior) { 436 ColorBehavior colorBehavior) {
280 ASSERT(image); 437 ASSERT(image);
281 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); 438 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height()));
282 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); 439 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect);
283 440
284 // In the case when cropRect doesn't intersect the source image and it 441 // 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 442 // requires a umpremul image We immediately return a transparent black image
286 // with cropRect.size() 443 // with cropRect.size()
287 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) { 444 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) {
(...skipping 19 matching lines...) Expand all
307 !skiaImage) && 464 !skiaImage) &&
308 image->data() && imageFormat == PremultiplyAlpha) || 465 image->data() && imageFormat == PremultiplyAlpha) ||
309 colorBehavior.isIgnore()) { 466 colorBehavior.isIgnore()) {
310 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create( 467 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create(
311 image->data(), true, 468 image->data(), true,
312 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied 469 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied
313 : ImageDecoder::AlphaNotPremultiplied, 470 : ImageDecoder::AlphaNotPremultiplied,
314 colorBehavior)); 471 colorBehavior));
315 if (!decoder) 472 if (!decoder)
316 return nullptr; 473 return nullptr;
317 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder)); 474 skiaImage = ImageBitmap::getSkImageFromDecoder(
475 std::move(decoder), &parsedOptions.latestColorType,
476 parsedOptions.latestColorSpace, true);
318 if (!skiaImage) 477 if (!skiaImage)
319 return nullptr; 478 return nullptr;
320 } 479 }
321 480
322 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { 481 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) {
323 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); 482 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect);
324 if (parsedOptions.flipY) 483 if (parsedOptions.dstColorSpace) {
325 return StaticBitmapImage::create(flipSkImageVertically( 484 croppedSkImage = applyColorSpaceConversion(croppedSkImage, parsedOptions);
326 croppedSkImage.get(), parsedOptions.premultiplyAlpha 485 }
327 ? PremultiplyAlpha 486 if (parsedOptions.flipY) {
328 : DontPremultiplyAlpha)); 487 return StaticBitmapImage::create(
488 flipSkImageVertically(croppedSkImage.get(), false, parsedOptions));
489 }
329 // Special case: The first parameter image is unpremul but we need to turn 490 // Special case: The first parameter image is unpremul but we need to turn
330 // it into premul. 491 // it into premul.
331 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) 492 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha)
332 return StaticBitmapImage::create( 493 return StaticBitmapImage::create(
333 unPremulSkImageToPremul(croppedSkImage.get())); 494 unPremulSkImageToPremul(croppedSkImage.get()));
334 // Call preroll to trigger image decoding. 495 // Call preroll to trigger image decoding.
335 croppedSkImage->preroll(); 496 croppedSkImage->preroll();
336 return StaticBitmapImage::create(std::move(croppedSkImage)); 497 return StaticBitmapImage::create(std::move(croppedSkImage));
337 } 498 }
338 499
(...skipping 21 matching lines...) Expand all
360 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth, 521 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth,
361 parsedOptions.resizeHeight); 522 parsedOptions.resizeHeight);
362 SkPaint paint; 523 SkPaint paint;
363 paint.setFilterQuality(parsedOptions.resizeQuality); 524 paint.setFilterQuality(parsedOptions.resizeQuality);
364 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, 525 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect,
365 &paint); 526 &paint);
366 } else { 527 } else {
367 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); 528 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop);
368 } 529 }
369 skiaImage = surface->makeImageSnapshot(); 530 skiaImage = surface->makeImageSnapshot();
531 if (parsedOptions.dstColorSpace)
532 skiaImage = applyColorSpaceConversion(skiaImage, parsedOptions);
370 533
371 if (parsedOptions.premultiplyAlpha) { 534 if (parsedOptions.premultiplyAlpha) {
372 if (imageFormat == DontPremultiplyAlpha) 535 if (imageFormat == DontPremultiplyAlpha)
373 return StaticBitmapImage::create( 536 return StaticBitmapImage::create(
374 unPremulSkImageToPremul(skiaImage.get())); 537 unPremulSkImageToPremul(skiaImage.get()));
375 return StaticBitmapImage::create(std::move(skiaImage)); 538 return StaticBitmapImage::create(std::move(skiaImage));
376 } 539 }
377 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); 540 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get()));
378 } 541 }
379 542
380 ImageBitmap::ImageBitmap(HTMLImageElement* image, 543 ImageBitmap::ImageBitmap(HTMLImageElement* image,
381 Optional<IntRect> cropRect, 544 Optional<IntRect> cropRect,
382 Document* document, 545 Document* document,
383 const ImageBitmapOptions& options) { 546 const ImageBitmapOptions& options) {
384 RefPtr<Image> input = image->cachedImage()->getImage(); 547 RefPtr<Image> input = image->cachedImage()->getImage();
385 ParsedOptions parsedOptions = 548 ParsedOptions parsedOptions =
386 parseOptions(options, cropRect, image->bitmapSourceSize()); 549 parseOptions(options, cropRect, image->bitmapSourceSize());
387 if (dstBufferSizeHasOverflow(parsedOptions)) 550 if (dstBufferSizeHasOverflow(parsedOptions))
388 return; 551 return;
389 552
390 if (options.colorSpaceConversion() == "none") { 553 if (options.colorSpaceConversion() == "none") {
391 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 554 m_image = cropImageAndApplyColorSpaceConversion(
392 ColorBehavior::ignore()); 555 input.get(), parsedOptions, PremultiplyAlpha, ColorBehavior::ignore());
393 } else { 556 } else {
394 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 557 m_image = cropImageAndApplyColorSpaceConversion(
395 ColorBehavior::transformToGlobalTarget()); 558 input.get(), parsedOptions, PremultiplyAlpha,
559 ColorBehavior::transformToGlobalTarget());
396 } 560 }
561
397 if (!m_image) 562 if (!m_image)
398 return; 563 return;
399 // In the case where the source image is lazy-decoded, m_image may not be in 564 // In the case where the source image is lazy-decoded, m_image may not be in
400 // a decoded state, we trigger it here. 565 // a decoded state, we trigger it here.
401 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame(); 566 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame();
402 SkPixmap pixmap; 567 SkPixmap pixmap;
403 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { 568 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) {
404 sk_sp<SkSurface> surface = 569 SkImageInfo imageInfo = SkImageInfo::Make(
405 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); 570 skImage->width(), skImage->height(), parsedOptions.dstColorType,
571 kPremul_SkAlphaType, parsedOptions.dstColorSpace);
572 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo);
406 surface->getCanvas()->drawImage(skImage, 0, 0); 573 surface->getCanvas()->drawImage(skImage, 0, 0);
407 m_image = StaticBitmapImage::create(surface->makeImageSnapshot()); 574 m_image = StaticBitmapImage::create(surface->makeImageSnapshot());
408 } 575 }
409 if (!m_image) 576 if (!m_image)
410 return; 577 return;
411 m_image->setOriginClean( 578 m_image->setOriginClean(
412 !image->wouldTaintOrigin(document->getSecurityOrigin())); 579 !image->wouldTaintOrigin(document->getSecurityOrigin()));
413 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 580 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
414 } 581 }
415 582
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 ParsedOptions parsedOptions = 643 ParsedOptions parsedOptions =
477 parseOptions(options, cropRect, IntSize(input->width(), input->height())); 644 parseOptions(options, cropRect, IntSize(input->width(), input->height()));
478 if (dstBufferSizeHasOverflow(parsedOptions)) 645 if (dstBufferSizeHasOverflow(parsedOptions))
479 return; 646 return;
480 647
481 bool isPremultiplyAlphaReverted = false; 648 bool isPremultiplyAlphaReverted = false;
482 if (!parsedOptions.premultiplyAlpha) { 649 if (!parsedOptions.premultiplyAlpha) {
483 parsedOptions.premultiplyAlpha = true; 650 parsedOptions.premultiplyAlpha = true;
484 isPremultiplyAlphaReverted = true; 651 isPremultiplyAlphaReverted = true;
485 } 652 }
486 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 653 m_image = cropImageAndApplyColorSpaceConversion(
487 ColorBehavior::transformToGlobalTarget()); 654 input.get(), parsedOptions, PremultiplyAlpha,
655 ColorBehavior::transformToGlobalTarget());
488 if (!m_image) 656 if (!m_image)
489 return; 657 return;
490 if (isPremultiplyAlphaReverted) { 658 if (isPremultiplyAlphaReverted) {
491 parsedOptions.premultiplyAlpha = false; 659 parsedOptions.premultiplyAlpha = false;
492 m_image = StaticBitmapImage::create( 660 m_image = StaticBitmapImage::create(
493 premulSkImageToUnPremul(m_image->imageForCurrentFrame().get())); 661 premulSkImageToUnPremul(m_image->imageForCurrentFrame().get()));
494 } 662 }
495 if (!m_image) 663 if (!m_image)
496 return; 664 return;
497 m_image->setOriginClean(canvas->originClean()); 665 m_image->setOriginClean(canvas->originClean());
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 std::min(0, -parsedOptions.cropRect.y())); 828 std::min(0, -parsedOptions.cropRect.y()));
661 if (parsedOptions.cropRect.x() < 0) 829 if (parsedOptions.cropRect.x() < 0)
662 dstPoint.setX(-parsedOptions.cropRect.x()); 830 dstPoint.setX(-parsedOptions.cropRect.x());
663 if (parsedOptions.cropRect.y() < 0) 831 if (parsedOptions.cropRect.y() < 0)
664 dstPoint.setY(-parsedOptions.cropRect.y()); 832 dstPoint.setY(-parsedOptions.cropRect.y());
665 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(), 833 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(),
666 srcRect, dstPoint); 834 srcRect, dstPoint);
667 sk_sp<SkImage> skImage = 835 sk_sp<SkImage> skImage =
668 buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown); 836 buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown);
669 if (parsedOptions.flipY) 837 if (parsedOptions.flipY)
670 skImage = flipSkImageVertically(skImage.get(), PremultiplyAlpha); 838 skImage = flipSkImageVertically(skImage.get(), true);
671 if (!skImage) 839 if (!skImage)
672 return; 840 return;
673 if (parsedOptions.shouldScaleInput) { 841 if (parsedOptions.shouldScaleInput) {
674 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( 842 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(
675 parsedOptions.resizeWidth, parsedOptions.resizeHeight); 843 parsedOptions.resizeWidth, parsedOptions.resizeHeight);
676 if (!surface) 844 if (!surface)
677 return; 845 return;
678 SkPaint paint; 846 SkPaint paint;
679 paint.setFilterQuality(parsedOptions.resizeQuality); 847 paint.setFilterQuality(parsedOptions.resizeQuality);
680 SkRect dstDrawRect = 848 SkRect dstDrawRect =
681 SkRect::MakeWH(parsedOptions.resizeWidth, parsedOptions.resizeHeight); 849 SkRect::MakeWH(parsedOptions.resizeWidth, parsedOptions.resizeHeight);
682 surface->getCanvas()->drawImageRect(skImage, dstDrawRect, &paint); 850 surface->getCanvas()->drawImageRect(skImage, dstDrawRect, &paint);
683 skImage = surface->makeImageSnapshot(); 851 skImage = surface->makeImageSnapshot();
684 } 852 }
685 m_image = StaticBitmapImage::create(std::move(skImage)); 853 m_image = StaticBitmapImage::create(std::move(skImage));
686 } 854 }
687 855
688 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, 856 ImageBitmap::ImageBitmap(ImageBitmap* bitmap,
689 Optional<IntRect> cropRect, 857 Optional<IntRect> cropRect,
690 const ImageBitmapOptions& options) { 858 const ImageBitmapOptions& options) {
691 RefPtr<Image> input = bitmap->bitmapImage(); 859 RefPtr<Image> input = bitmap->bitmapImage();
692 if (!input) 860 if (!input)
693 return; 861 return;
694 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()); 862 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size());
695 if (dstBufferSizeHasOverflow(parsedOptions)) 863 if (dstBufferSizeHasOverflow(parsedOptions))
696 return; 864 return;
697 865
698 m_image = cropImage( 866 m_image = cropImageAndApplyColorSpaceConversion(
699 input.get(), parsedOptions, 867 input.get(), parsedOptions,
700 bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha, 868 bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha,
701 ColorBehavior::transformToGlobalTarget()); 869 ColorBehavior::transformToGlobalTarget());
702 if (!m_image) 870 if (!m_image)
703 return; 871 return;
704 m_image->setOriginClean(bitmap->originClean()); 872 m_image->setOriginClean(bitmap->originClean());
705 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 873 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
706 } 874 }
707 875
708 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, 876 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image,
709 Optional<IntRect> cropRect, 877 Optional<IntRect> cropRect,
710 const ImageBitmapOptions& options) { 878 const ImageBitmapOptions& options) {
711 bool originClean = image->originClean(); 879 bool originClean = image->originClean();
712 RefPtr<Image> input = image; 880 RefPtr<Image> input = image;
713 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()); 881 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size());
714 if (dstBufferSizeHasOverflow(parsedOptions)) 882 if (dstBufferSizeHasOverflow(parsedOptions))
715 return; 883 return;
716 884
717 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 885 m_image = cropImageAndApplyColorSpaceConversion(
718 ColorBehavior::transformToGlobalTarget()); 886 input.get(), parsedOptions, PremultiplyAlpha,
887 ColorBehavior::transformToGlobalTarget());
719 if (!m_image) 888 if (!m_image)
720 return; 889 return;
721 890
722 m_image->setOriginClean(originClean); 891 m_image->setOriginClean(originClean);
723 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 892 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
724 } 893 }
725 894
726 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) { 895 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) {
727 m_image = image; 896 m_image = image;
728 } 897 }
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
864 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, 1033 void ImageBitmap::adjustDrawRects(FloatRect* srcRect,
865 FloatRect* dstRect) const {} 1034 FloatRect* dstRect) const {}
866 1035
867 FloatSize ImageBitmap::elementSize(const FloatSize&) const { 1036 FloatSize ImageBitmap::elementSize(const FloatSize&) const {
868 return FloatSize(width(), height()); 1037 return FloatSize(width(), height());
869 } 1038 }
870 1039
871 DEFINE_TRACE(ImageBitmap) {} 1040 DEFINE_TRACE(ImageBitmap) {}
872 1041
873 } // namespace blink 1042 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698