Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 = SkColorType::kN32_SkColorType; |
|
msarett1
2016/11/30 21:32:39
FWIW, I don't think the SkColorType:: is necessary
zakerinasab
2016/12/01 19:49:46
Removed.
| |
| 37 int bytesPerPixel = 4; | 38 SkColorType latestColorType = SkColorType::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 parsedOptions.dstColorSpace = | |
| 79 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); | |
| 80 parsedOptions.dstColorType = SkColorType::kN32_SkColorType; | |
| 81 } else { | |
| 82 if (options.colorSpaceConversion() == "default" || | |
| 83 options.colorSpaceConversion() == "srgb") { | |
| 84 parsedOptions.dstColorSpace = | |
| 85 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); | |
| 86 parsedOptions.dstColorType = SkColorType::kN32_SkColorType; | |
| 87 } else if (options.colorSpaceConversion() == "linear-rgb") { | |
| 88 parsedOptions.dstColorSpace = | |
| 89 SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named); | |
| 90 parsedOptions.dstColorType = SkColorType::kRGBA_F16_SkColorType; | |
| 91 } else { | |
| 92 NOTREACHED() | |
| 93 << "Invalid ImageBitmap creation attribute colorSpaceConversion: " | |
| 94 << options.colorSpaceConversion(); | |
| 95 } | |
| 96 } | |
| 97 } | |
| 98 | |
| 66 int sourceWidth = sourceSize.width(); | 99 int sourceWidth = sourceSize.width(); |
| 67 int sourceHeight = sourceSize.height(); | 100 int sourceHeight = sourceSize.height(); |
| 68 if (!cropRect) { | 101 if (!cropRect) { |
| 69 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight); | 102 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight); |
| 70 } else { | 103 } else { |
| 71 parsedOptions.cropRect = normalizeRect(*cropRect); | 104 parsedOptions.cropRect = normalizeRect(*cropRect); |
| 72 } | 105 } |
| 73 if (!options.hasResizeWidth() && !options.hasResizeHeight()) { | 106 if (!options.hasResizeWidth() && !options.hasResizeHeight()) { |
| 74 parsedOptions.resizeWidth = parsedOptions.cropRect.width(); | 107 parsedOptions.resizeWidth = parsedOptions.cropRect.width(); |
| 75 parsedOptions.resizeHeight = parsedOptions.cropRect.height(); | 108 parsedOptions.resizeHeight = parsedOptions.cropRect.height(); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 103 else if (options.resizeQuality() == "pixelated") | 136 else if (options.resizeQuality() == "pixelated") |
| 104 parsedOptions.resizeQuality = kNone_SkFilterQuality; | 137 parsedOptions.resizeQuality = kNone_SkFilterQuality; |
| 105 else | 138 else |
| 106 parsedOptions.resizeQuality = kLow_SkFilterQuality; | 139 parsedOptions.resizeQuality = kLow_SkFilterQuality; |
| 107 return parsedOptions; | 140 return parsedOptions; |
| 108 } | 141 } |
| 109 | 142 |
| 110 bool dstBufferSizeHasOverflow(ParsedOptions options) { | 143 bool dstBufferSizeHasOverflow(ParsedOptions options) { |
| 111 CheckedNumeric<unsigned> totalBytes = options.cropRect.width(); | 144 CheckedNumeric<unsigned> totalBytes = options.cropRect.width(); |
| 112 totalBytes *= options.cropRect.height(); | 145 totalBytes *= options.cropRect.height(); |
| 113 totalBytes *= options.bytesPerPixel; | 146 totalBytes *= SkColorTypeBytesPerPixel(options.latestColorType); |
| 114 if (!totalBytes.IsValid()) | 147 if (!totalBytes.IsValid()) |
| 115 return true; | 148 return true; |
| 116 | 149 |
| 117 if (!options.shouldScaleInput) | 150 if (!options.shouldScaleInput) |
| 118 return false; | 151 return false; |
| 119 totalBytes = options.resizeWidth; | 152 totalBytes = options.resizeWidth; |
| 120 totalBytes *= options.resizeHeight; | 153 totalBytes *= options.resizeHeight; |
| 121 totalBytes *= options.bytesPerPixel; | 154 totalBytes *= SkColorTypeBytesPerPixel(options.latestColorType); |
| 122 if (!totalBytes.IsValid()) | 155 if (!totalBytes.IsValid()) |
| 123 return true; | 156 return true; |
| 124 | 157 |
| 125 return false; | 158 return false; |
| 126 } | 159 } |
| 127 | 160 |
| 128 } // namespace | 161 } // namespace |
| 129 | 162 |
| 130 static PassRefPtr<Uint8Array> copySkImageData(SkImage* input, | 163 static PassRefPtr<Uint8Array> copySkImageData(SkImage* input, |
| 131 const SkImageInfo& info) { | 164 const SkImageInfo& info) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 srcAddr + bottomRowStartPosition); | 213 srcAddr + bottomRowStartPosition); |
| 181 } | 214 } |
| 182 } | 215 } |
| 183 } else { | 216 } else { |
| 184 if (kN32_SkColorType == kBGRA_8888_SkColorType) // needs to swizzle | 217 if (kN32_SkColorType == kBGRA_8888_SkColorType) // needs to swizzle |
| 185 for (unsigned i = 0; i < height * bytesPerRow; i += 4) | 218 for (unsigned i = 0; i < height * bytesPerRow; i += 4) |
| 186 std::swap(srcAddr[i], srcAddr[i + 2]); | 219 std::swap(srcAddr[i], srcAddr[i + 2]); |
| 187 } | 220 } |
| 188 } | 221 } |
| 189 | 222 |
| 190 static sk_sp<SkImage> flipSkImageVertically(SkImage* input, | 223 static sk_sp<SkImage> flipSkImageVertically( |
| 191 AlphaDisposition alphaOp) { | 224 SkImage* input, |
| 225 bool enforceAlphaPremultiply = false, | |
| 226 const ParsedOptions& options = defaultOptions()) { | |
| 192 unsigned width = static_cast<unsigned>(input->width()); | 227 unsigned width = static_cast<unsigned>(input->width()); |
| 193 unsigned height = static_cast<unsigned>(input->height()); | 228 unsigned height = static_cast<unsigned>(input->height()); |
| 194 SkImageInfo info = SkImageInfo::MakeN32(input->width(), input->height(), | 229 SkAlphaType alphaType = (enforceAlphaPremultiply || options.premultiplyAlpha) |
| 195 (alphaOp == PremultiplyAlpha) | 230 ? kPremul_SkAlphaType |
| 196 ? kPremul_SkAlphaType | 231 : kUnpremul_SkAlphaType; |
| 197 : kUnpremul_SkAlphaType); | 232 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), |
| 233 options.latestColorType, alphaType, | |
| 234 options.latestColorSpace); | |
| 235 | |
| 198 unsigned imageRowBytes = width * info.bytesPerPixel(); | 236 unsigned imageRowBytes = width * info.bytesPerPixel(); |
| 199 RefPtr<Uint8Array> imagePixels = copySkImageData(input, info); | 237 RefPtr<Uint8Array> imagePixels = copySkImageData(input, info); |
| 200 if (!imagePixels) | 238 if (!imagePixels) |
| 201 return nullptr; | 239 return nullptr; |
| 202 for (unsigned i = 0; i < height / 2; i++) { | 240 for (unsigned i = 0; i < height / 2; i++) { |
| 203 unsigned topFirstElement = i * imageRowBytes; | 241 unsigned topFirstElement = i * imageRowBytes; |
| 204 unsigned topLastElement = (i + 1) * imageRowBytes; | 242 unsigned topLastElement = (i + 1) * imageRowBytes; |
| 205 unsigned bottomFirstElement = (height - 1 - i) * imageRowBytes; | 243 unsigned bottomFirstElement = (height - 1 - i) * imageRowBytes; |
| 206 std::swap_ranges(imagePixels->data() + topFirstElement, | 244 std::swap_ranges(imagePixels->data() + topFirstElement, |
| 207 imagePixels->data() + topLastElement, | 245 imagePixels->data() + topLastElement, |
| 208 imagePixels->data() + bottomFirstElement); | 246 imagePixels->data() + bottomFirstElement); |
| 209 } | 247 } |
| 210 return newSkImageFromRaster(info, std::move(imagePixels), imageRowBytes); | 248 return newSkImageFromRaster(info, std::move(imagePixels), imageRowBytes); |
| 211 } | 249 } |
| 212 | 250 |
| 213 static sk_sp<SkImage> premulSkImageToUnPremul(SkImage* input) { | 251 static sk_sp<SkImage> premulSkImageToUnPremul( |
| 214 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), | 252 SkImage* input, |
| 215 kN32_SkColorType, kUnpremul_SkAlphaType); | 253 const ParsedOptions& options = defaultOptions()) { |
| 254 SkImageInfo info = SkImageInfo::Make( | |
| 255 input->width(), input->height(), options.latestColorType, | |
| 256 kUnpremul_SkAlphaType, options.latestColorSpace); | |
| 257 | |
| 216 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); | 258 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); |
| 217 if (!dstPixels) | 259 if (!dstPixels) |
| 218 return nullptr; | 260 return nullptr; |
| 219 return newSkImageFromRaster( | 261 return newSkImageFromRaster( |
| 220 info, std::move(dstPixels), | 262 info, std::move(dstPixels), |
| 221 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); | 263 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); |
| 222 } | 264 } |
| 223 | 265 |
| 224 static sk_sp<SkImage> unPremulSkImageToPremul(SkImage* input) { | 266 static sk_sp<SkImage> unPremulSkImageToPremul( |
| 225 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), | 267 SkImage* input, |
| 226 kN32_SkColorType, kPremul_SkAlphaType); | 268 const ParsedOptions& options = defaultOptions()) { |
| 269 SkImageInfo info = SkImageInfo::Make( | |
| 270 input->width(), input->height(), options.latestColorType, | |
| 271 kPremul_SkAlphaType, options.latestColorSpace); | |
| 272 | |
| 227 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); | 273 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); |
| 228 if (!dstPixels) | 274 if (!dstPixels) |
| 229 return nullptr; | 275 return nullptr; |
| 230 return newSkImageFromRaster( | 276 return newSkImageFromRaster( |
| 231 info, std::move(dstPixels), | 277 info, std::move(dstPixels), |
| 232 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); | 278 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); |
| 233 } | 279 } |
| 234 | 280 |
| 281 // This code is borrowed from third_party/skia/src/codec/SkCodecPriv.h | |
| 282 // If you need to change this, please check SkColorSpaceXform::ColorFormat | |
| 283 // and SkColorType for proper coverage. | |
| 284 static inline SkColorSpaceXform::ColorFormat getXformFormat( | |
| 285 SkColorType colorType) { | |
| 286 switch (colorType) { | |
| 287 case kRGBA_8888_SkColorType: | |
| 288 return SkColorSpaceXform::kRGBA_8888_ColorFormat; | |
| 289 case kBGRA_8888_SkColorType: | |
| 290 return SkColorSpaceXform::kBGRA_8888_ColorFormat; | |
| 291 case kRGBA_F16_SkColorType: | |
| 292 return SkColorSpaceXform::kRGBA_F16_ColorFormat; | |
| 293 case kIndex_8_SkColorType: | |
|
msarett1
2016/11/30 21:32:39
I'm guessing that this case isn't necessary for no
zakerinasab
2016/12/01 19:49:45
Removed.
| |
| 294 #ifdef SK_PMCOLOR_IS_RGBA | |
| 295 return SkColorSpaceXform::kRGBA_8888_ColorFormat; | |
| 296 #else | |
| 297 return SkColorSpaceXform::kBGRA_8888_ColorFormat; | |
| 298 #endif | |
| 299 default: | |
| 300 SkASSERT(false); | |
| 301 return SkColorSpaceXform::kRGBA_8888_ColorFormat; | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 static inline void updateLatestColorInformation(ParsedOptions& options) { | |
| 306 options.latestColorType = options.dstColorType; | |
| 307 options.latestColorSpace = options.dstColorSpace; | |
| 308 } | |
| 309 | |
| 310 static sk_sp<SkImage> applyColorSpaceConversion(const sk_sp<SkImage> image, | |
|
msarett1
2016/11/30 21:32:39
Unless I'm missing something, I think that this fu
zakerinasab
2016/12/01 19:49:46
Proper TODO added.
| |
| 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 = 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 = 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 supports color conversion for unpremultiplied images. | |
|
msarett1
2016/11/30 21:32:39
Not sure what this comment means...
I would say t
zakerinasab
2016/12/01 19:49:45
Done.
| |
| 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()); | |
| 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 13 matching lines...) Expand all Loading... | |
| 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> cropImage( |
| 276 Image* image, | 433 Image* image, |
| 277 const ParsedOptions& parsedOptions, | 434 ParsedOptions& parsedOptions, |
| 278 AlphaDisposition imageFormat = PremultiplyAlpha, | 435 AlphaDisposition imageFormat = PremultiplyAlpha, |
| 279 ImageDecoder::ColorSpaceOption colorSpaceOp = | 436 ImageDecoder::ColorSpaceOption colorSpaceOp = |
| 280 ImageDecoder::ColorSpaceApplied) { | 437 ImageDecoder::ColorSpaceApplied) { |
| 281 ASSERT(image); | 438 ASSERT(image); |
| 282 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); | 439 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); |
| 283 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); | 440 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); |
| 284 | 441 |
| 285 // In the case when cropRect doesn't intersect the source image and it | 442 // In the case when cropRect doesn't intersect the source image and it |
| 286 // requires a umpremul image We immediately return a transparent black image | 443 // requires a umpremul image We immediately return a transparent black image |
| 287 // with cropRect.size() | 444 // with cropRect.size() |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 308 !skiaImage) && | 465 !skiaImage) && |
| 309 image->data() && imageFormat == PremultiplyAlpha) || | 466 image->data() && imageFormat == PremultiplyAlpha) || |
| 310 colorSpaceOp == ImageDecoder::ColorSpaceIgnored) { | 467 colorSpaceOp == ImageDecoder::ColorSpaceIgnored) { |
| 311 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create( | 468 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create( |
| 312 image->data(), true, | 469 image->data(), true, |
| 313 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied | 470 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied |
| 314 : ImageDecoder::AlphaNotPremultiplied, | 471 : ImageDecoder::AlphaNotPremultiplied, |
| 315 colorSpaceOp)); | 472 colorSpaceOp)); |
| 316 if (!decoder) | 473 if (!decoder) |
| 317 return nullptr; | 474 return nullptr; |
| 318 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder)); | 475 skiaImage = ImageBitmap::getSkImageFromDecoder( |
| 476 std::move(decoder), &parsedOptions.latestColorType, | |
| 477 parsedOptions.latestColorSpace, true); | |
| 319 if (!skiaImage) | 478 if (!skiaImage) |
| 320 return nullptr; | 479 return nullptr; |
| 321 } | 480 } |
| 322 | 481 |
| 323 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { | 482 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { |
| 324 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); | 483 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); |
| 325 if (parsedOptions.flipY) | 484 if (parsedOptions.dstColorSpace) { |
| 326 return StaticBitmapImage::create(flipSkImageVertically( | 485 croppedSkImage = applyColorSpaceConversion(croppedSkImage, parsedOptions); |
| 327 croppedSkImage.get(), parsedOptions.premultiplyAlpha | 486 } |
| 328 ? PremultiplyAlpha | 487 if (parsedOptions.flipY) { |
| 329 : DontPremultiplyAlpha)); | 488 return StaticBitmapImage::create( |
| 489 flipSkImageVertically(croppedSkImage.get(), false, parsedOptions)); | |
| 490 } | |
| 330 // Special case: The first parameter image is unpremul but we need to turn | 491 // Special case: The first parameter image is unpremul but we need to turn |
| 331 // it into premul. | 492 // it into premul. |
| 332 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) | 493 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) |
| 333 return StaticBitmapImage::create( | 494 return StaticBitmapImage::create( |
| 334 unPremulSkImageToPremul(croppedSkImage.get())); | 495 unPremulSkImageToPremul(croppedSkImage.get())); |
| 335 // Call preroll to trigger image decoding. | 496 // Call preroll to trigger image decoding. |
| 336 croppedSkImage->preroll(); | 497 croppedSkImage->preroll(); |
| 337 return StaticBitmapImage::create(std::move(croppedSkImage)); | 498 return StaticBitmapImage::create(std::move(croppedSkImage)); |
| 338 } | 499 } |
| 339 | 500 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 361 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth, | 522 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth, |
| 362 parsedOptions.resizeHeight); | 523 parsedOptions.resizeHeight); |
| 363 SkPaint paint; | 524 SkPaint paint; |
| 364 paint.setFilterQuality(parsedOptions.resizeQuality); | 525 paint.setFilterQuality(parsedOptions.resizeQuality); |
| 365 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, | 526 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, |
| 366 &paint); | 527 &paint); |
| 367 } else { | 528 } else { |
| 368 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); | 529 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); |
| 369 } | 530 } |
| 370 skiaImage = surface->makeImageSnapshot(); | 531 skiaImage = surface->makeImageSnapshot(); |
| 532 if (parsedOptions.dstColorSpace) | |
| 533 skiaImage = applyColorSpaceConversion(skiaImage, parsedOptions); | |
| 371 | 534 |
| 372 if (parsedOptions.premultiplyAlpha) { | 535 if (parsedOptions.premultiplyAlpha) { |
| 373 if (imageFormat == DontPremultiplyAlpha) | 536 if (imageFormat == DontPremultiplyAlpha) |
| 374 return StaticBitmapImage::create( | 537 return StaticBitmapImage::create( |
| 375 unPremulSkImageToPremul(skiaImage.get())); | 538 unPremulSkImageToPremul(skiaImage.get())); |
| 376 return StaticBitmapImage::create(std::move(skiaImage)); | 539 return StaticBitmapImage::create(std::move(skiaImage)); |
| 377 } | 540 } |
| 378 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); | 541 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); |
| 379 } | 542 } |
| 380 | 543 |
| 381 ImageBitmap::ImageBitmap(HTMLImageElement* image, | 544 ImageBitmap::ImageBitmap(HTMLImageElement* image, |
| 382 Optional<IntRect> cropRect, | 545 Optional<IntRect> cropRect, |
| 383 Document* document, | 546 Document* document, |
| 384 const ImageBitmapOptions& options) { | 547 const ImageBitmapOptions& options) { |
| 385 RefPtr<Image> input = image->cachedImage()->getImage(); | 548 RefPtr<Image> input = image->cachedImage()->getImage(); |
| 386 ParsedOptions parsedOptions = | 549 ParsedOptions parsedOptions = |
| 387 parseOptions(options, cropRect, image->bitmapSourceSize()); | 550 parseOptions(options, cropRect, image->bitmapSourceSize()); |
| 388 if (dstBufferSizeHasOverflow(parsedOptions)) | 551 if (dstBufferSizeHasOverflow(parsedOptions)) |
| 389 return; | 552 return; |
| 390 | 553 |
| 391 if (options.colorSpaceConversion() == "none") { | 554 m_image = |
| 392 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, | 555 cropImage(input.get(), parsedOptions, PremultiplyAlpha, |
| 393 ImageDecoder::ColorSpaceIgnored); | 556 parsedOptions.dstColorSpace ? ImageDecoder::ColorSpaceApplied |
| 394 } else { | 557 : ImageDecoder::ColorSpaceIgnored); |
| 395 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, | |
| 396 ImageDecoder::ColorSpaceApplied); | |
| 397 } | |
| 398 if (!m_image) | 558 if (!m_image) |
| 399 return; | 559 return; |
| 400 // In the case where the source image is lazy-decoded, m_image may not be in | 560 // In the case where the source image is lazy-decoded, m_image may not be in |
| 401 // a decoded state, we trigger it here. | 561 // a decoded state, we trigger it here. |
| 402 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame(); | 562 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame(); |
| 403 SkPixmap pixmap; | 563 SkPixmap pixmap; |
| 404 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { | 564 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { |
| 405 sk_sp<SkSurface> surface = | 565 sk_sp<SkSurface> surface = |
| 406 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); | 566 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); |
| 407 surface->getCanvas()->drawImage(skImage, 0, 0); | 567 surface->getCanvas()->drawImage(skImage, 0, 0); |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 660 std::min(0, -parsedOptions.cropRect.y())); | 820 std::min(0, -parsedOptions.cropRect.y())); |
| 661 if (parsedOptions.cropRect.x() < 0) | 821 if (parsedOptions.cropRect.x() < 0) |
| 662 dstPoint.setX(-parsedOptions.cropRect.x()); | 822 dstPoint.setX(-parsedOptions.cropRect.x()); |
| 663 if (parsedOptions.cropRect.y() < 0) | 823 if (parsedOptions.cropRect.y() < 0) |
| 664 dstPoint.setY(-parsedOptions.cropRect.y()); | 824 dstPoint.setY(-parsedOptions.cropRect.y()); |
| 665 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(), | 825 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(), |
| 666 srcRect, dstPoint); | 826 srcRect, dstPoint); |
| 667 sk_sp<SkImage> skImage = | 827 sk_sp<SkImage> skImage = |
| 668 buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown); | 828 buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown); |
| 669 if (parsedOptions.flipY) | 829 if (parsedOptions.flipY) |
| 670 skImage = flipSkImageVertically(skImage.get(), PremultiplyAlpha); | 830 skImage = flipSkImageVertically(skImage.get(), true); |
| 671 if (!skImage) | 831 if (!skImage) |
| 672 return; | 832 return; |
| 673 if (parsedOptions.shouldScaleInput) { | 833 if (parsedOptions.shouldScaleInput) { |
| 674 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( | 834 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( |
| 675 parsedOptions.resizeWidth, parsedOptions.resizeHeight); | 835 parsedOptions.resizeWidth, parsedOptions.resizeHeight); |
| 676 if (!surface) | 836 if (!surface) |
| 677 return; | 837 return; |
| 678 SkPaint paint; | 838 SkPaint paint; |
| 679 paint.setFilterQuality(parsedOptions.resizeQuality); | 839 paint.setFilterQuality(parsedOptions.resizeQuality); |
| 680 SkRect dstDrawRect = | 840 SkRect dstDrawRect = |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 862 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, | 1022 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, |
| 863 FloatRect* dstRect) const {} | 1023 FloatRect* dstRect) const {} |
| 864 | 1024 |
| 865 FloatSize ImageBitmap::elementSize(const FloatSize&) const { | 1025 FloatSize ImageBitmap::elementSize(const FloatSize&) const { |
| 866 return FloatSize(width(), height()); | 1026 return FloatSize(width(), height()); |
| 867 } | 1027 } |
| 868 | 1028 |
| 869 DEFINE_TRACE(ImageBitmap) {} | 1029 DEFINE_TRACE(ImageBitmap) {} |
| 870 | 1030 |
| 871 } // namespace blink | 1031 } // namespace blink |
| OLD | NEW |