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/SkSurface.h" | 13 #include "third_party/skia/include/core/SkSurface.h" |
| 14 #include "ui/gfx/icc_profile.h" | |
| 15 #include "ui/gfx/color_space.h" | |
| 14 #include "wtf/CheckedNumeric.h" | 16 #include "wtf/CheckedNumeric.h" |
| 15 #include "wtf/PtrUtil.h" | 17 #include "wtf/PtrUtil.h" |
| 16 #include "wtf/RefPtr.h" | 18 #include "wtf/RefPtr.h" |
| 17 #include <memory> | 19 #include <memory> |
| 18 | 20 |
| 19 namespace blink { | 21 namespace blink { |
| 20 | 22 |
| 21 static const char* imageOrientationFlipY = "flipY"; | 23 static const char* imageOrientationFlipY = "flipY"; |
| 22 static const char* imageBitmapOptionNone = "none"; | 24 static const char* imageBitmapOptionNone = "none"; |
| 23 | 25 |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 225 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), | 227 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), |
| 226 kN32_SkColorType, kPremul_SkAlphaType); | 228 kN32_SkColorType, kPremul_SkAlphaType); |
| 227 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); | 229 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); |
| 228 if (!dstPixels) | 230 if (!dstPixels) |
| 229 return nullptr; | 231 return nullptr; |
| 230 return newSkImageFromRaster( | 232 return newSkImageFromRaster( |
| 231 info, std::move(dstPixels), | 233 info, std::move(dstPixels), |
| 232 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); | 234 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); |
| 233 } | 235 } |
| 234 | 236 |
| 237 static sk_sp<SkImage> applyColorSpaceConversion( | |
| 238 sk_sp<SkImage> image, | |
| 239 bool premultiplyAlpha, | |
| 240 const ImageBitmapOptions* options) { | |
| 241 // Valid values for colorSpaceConversion are "default", "srgb" and | |
| 242 // "linear-rgb" here. | |
| 243 if (options->colorSpaceConversion() != "default" && | |
| 244 options->colorSpaceConversion() != "srgb" && | |
| 245 options->colorSpaceConversion() != "linear-rgb") { | |
| 246 NOTREACHED() << "Invalid ImageBitmap creation attribute colorConversionSpace : " | |
| 247 << options->colorSpaceConversion(); | |
| 248 return image; | |
| 249 } | |
| 250 | |
| 251 bool colorCorrectRendering = | |
| 252 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() && | |
| 253 RuntimeEnabledFeatures::colorCorrectRenderingEnabled(); | |
| 254 | |
| 255 // If color correct rendering is not set, only "default" is accepted here. | |
| 256 if (options->colorSpaceConversion() != "default" && | |
| 257 !colorCorrectRendering) { | |
| 258 NOTREACHED() << "Invalid ImageBitmap creation attribute colorConversionSpace in\ | |
| 259 not-color-corrected mode: " | |
| 260 << options->colorSpaceConversion(); | |
| 261 return image; | |
| 262 } | |
| 263 | |
| 264 SkImageInfo imageInfo; | |
| 265 // If color space conversion is default and color correct rendering is | |
| 266 // not set, color correct the image to display color space. | |
| 267 // For now we assume 8 bit per channel for display. This must be fixed | |
| 268 // to properly support color space conversion on HDR displays. | |
| 269 if (options->colorSpaceConversion() == "default" && | |
| 270 !colorCorrectRendering) { | |
|
ccameron
2016/11/21 22:11:36
Ah -- as soon as https://codereview.chromium.org/2
| |
| 271 gfx::ICCProfile iccProfile = gfx::ICCProfile::FromBestMonitor(); | |
| 272 gfx::ColorSpace gfxColorSpace = iccProfile.GetColorSpace(); | |
| 273 sk_sp<SkColorSpace> colorSpace = | |
| 274 (gfxColorSpace != gfx::ColorSpace()) ? | |
| 275 gfxColorSpace.ToSkColorSpace() : | |
| 276 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); | |
| 277 imageInfo = SkImageInfo::Make( | |
| 278 image->width(), image->height(), | |
| 279 SkColorType::kN32_SkColorType, | |
| 280 SkAlphaType::kPremul_SkAlphaType, | |
| 281 colorSpace); | |
| 282 | |
| 283 // If color space conversion is default and color correct rendering is | |
| 284 // set, color correct the image to sRGB. | |
| 285 } else if (options->colorSpaceConversion() == "default" || | |
| 286 options->colorSpaceConversion() == "srgb") { | |
| 287 imageInfo = SkImageInfo::MakeS32( | |
| 288 image->width(), image->height(), | |
| 289 SkAlphaType::kPremul_SkAlphaType); | |
| 290 | |
| 291 } else if (options->colorSpaceConversion() == "linear-rgb") { | |
| 292 imageInfo = SkImageInfo::Make( | |
| 293 image->width(), image->height(), | |
| 294 SkColorType::kRGBA_F16_SkColorType, | |
| 295 SkAlphaType::kPremul_SkAlphaType, | |
| 296 SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named)); | |
| 297 } | |
| 298 | |
| 299 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo); | |
| 300 surface->getCanvas()->drawImage(image, 0, 0); | |
| 301 return surface->makeImageSnapshot(); | |
| 302 } | |
| 303 | |
| 235 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( | 304 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( |
| 236 std::unique_ptr<ImageDecoder> decoder) { | 305 std::unique_ptr<ImageDecoder> decoder) { |
| 237 if (!decoder->frameCount()) | 306 if (!decoder->frameCount()) |
| 238 return nullptr; | 307 return nullptr; |
| 239 ImageFrame* frame = decoder->frameBufferAtIndex(0); | 308 ImageFrame* frame = decoder->frameBufferAtIndex(0); |
| 240 if (!frame || frame->getStatus() != ImageFrame::FrameComplete) | 309 if (!frame || frame->getStatus() != ImageFrame::FrameComplete) |
| 241 return nullptr; | 310 return nullptr; |
| 242 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty()); | 311 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty()); |
| 243 return frame->finalizePixelsAndGetImage(); | 312 return frame->finalizePixelsAndGetImage(); |
| 244 } | 313 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 270 // The parameter imageFormat indicates whether the first parameter "image" is | 339 // The parameter imageFormat indicates whether the first parameter "image" is |
| 271 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in | 340 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in |
| 272 // premuliplied format For example, if the image is already in unpremultiplied | 341 // 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 | 342 // 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. | 343 // need to use the ImageDecoder to decode the image. |
| 275 static PassRefPtr<StaticBitmapImage> cropImage( | 344 static PassRefPtr<StaticBitmapImage> cropImage( |
| 276 Image* image, | 345 Image* image, |
| 277 const ParsedOptions& parsedOptions, | 346 const ParsedOptions& parsedOptions, |
| 278 AlphaDisposition imageFormat = PremultiplyAlpha, | 347 AlphaDisposition imageFormat = PremultiplyAlpha, |
| 279 ImageDecoder::ColorSpaceOption colorSpaceOp = | 348 ImageDecoder::ColorSpaceOption colorSpaceOp = |
| 280 ImageDecoder::ColorSpaceApplied) { | 349 ImageDecoder::ColorSpaceApplied, |
| 350 const ImageBitmapOptions* imageBitmapOptions = nullptr) { | |
| 351 | |
| 281 ASSERT(image); | 352 ASSERT(image); |
| 282 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); | 353 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); |
| 283 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); | 354 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); |
| 284 | 355 |
| 285 // In the case when cropRect doesn't intersect the source image and it | 356 // 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 | 357 // requires a umpremul image We immediately return a transparent black image |
| 287 // with cropRect.size() | 358 // with cropRect.size() |
| 288 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) { | 359 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) { |
| 289 SkImageInfo info = | 360 SkImageInfo info = |
| 290 SkImageInfo::Make(parsedOptions.resizeWidth, parsedOptions.resizeHeight, | 361 SkImageInfo::Make(parsedOptions.resizeWidth, parsedOptions.resizeHeight, |
| 291 kN32_SkColorType, kUnpremul_SkAlphaType); | 362 kN32_SkColorType, kUnpremul_SkAlphaType); |
| 292 RefPtr<ArrayBuffer> dstBuffer = ArrayBuffer::createOrNull( | 363 RefPtr<ArrayBuffer> dstBuffer = ArrayBuffer::createOrNull( |
| 293 static_cast<unsigned>(info.width()) * info.height(), | 364 static_cast<unsigned>(info.width()) * info.height(), |
| 294 info.bytesPerPixel()); | 365 info.bytesPerPixel()); |
| 295 if (!dstBuffer) | 366 if (!dstBuffer) |
| 296 return nullptr; | 367 return nullptr; |
| 297 RefPtr<Uint8Array> dstPixels = | 368 RefPtr<Uint8Array> dstPixels = |
| 298 Uint8Array::create(dstBuffer, 0, dstBuffer->byteLength()); | 369 Uint8Array::create(dstBuffer, 0, dstBuffer->byteLength()); |
| 299 return StaticBitmapImage::create(newSkImageFromRaster( | 370 sk_sp<SkImage> croppedImage = newSkImageFromRaster( |
| 300 info, std::move(dstPixels), | 371 info, std::move(dstPixels), |
| 301 static_cast<unsigned>(info.width()) * info.bytesPerPixel())); | 372 static_cast<size_t>(info.width()) * info.bytesPerPixel()); |
| 373 return StaticBitmapImage::create(croppedImage); | |
| 302 } | 374 } |
| 303 | 375 |
| 304 sk_sp<SkImage> skiaImage = image->imageForCurrentFrame(); | 376 sk_sp<SkImage> skiaImage = image->imageForCurrentFrame(); |
| 305 // Attempt to get raw unpremultiplied image data, executed only when skiaImage | 377 // Attempt to get raw unpremultiplied image data, executed only when skiaImage |
| 306 // is premultiplied. | 378 // is premultiplied. |
| 307 if ((((!parsedOptions.premultiplyAlpha && !skiaImage->isOpaque()) || | 379 if ((((!parsedOptions.premultiplyAlpha && !skiaImage->isOpaque()) || |
| 308 !skiaImage) && | 380 !skiaImage) && |
| 309 image->data() && imageFormat == PremultiplyAlpha) || | 381 image->data() && imageFormat == PremultiplyAlpha) || |
| 310 colorSpaceOp == ImageDecoder::ColorSpaceIgnored) { | 382 colorSpaceOp == ImageDecoder::ColorSpaceIgnored) { |
| 311 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create( | 383 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create( |
| 312 image->data(), true, | 384 image->data(), true, |
| 313 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied | 385 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied |
| 314 : ImageDecoder::AlphaNotPremultiplied, | 386 : ImageDecoder::AlphaNotPremultiplied, |
| 315 colorSpaceOp)); | 387 colorSpaceOp)); |
| 316 if (!decoder) | 388 if (!decoder) |
| 317 return nullptr; | 389 return nullptr; |
| 318 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder)); | 390 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder)); |
| 319 if (!skiaImage) | 391 if (!skiaImage) |
| 320 return nullptr; | 392 return nullptr; |
| 321 } | 393 } |
| 322 | 394 |
| 323 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { | 395 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { |
| 324 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); | 396 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); |
| 397 if (colorSpaceOp == ImageDecoder::ColorSpaceApplied) | |
| 398 croppedSkImage = applyColorSpaceConversion( | |
| 399 croppedSkImage, | |
| 400 parsedOptions.premultiplyAlpha, | |
| 401 imageBitmapOptions); | |
| 325 if (parsedOptions.flipY) | 402 if (parsedOptions.flipY) |
| 326 return StaticBitmapImage::create(flipSkImageVertically( | 403 return StaticBitmapImage::create(flipSkImageVertically( |
| 327 croppedSkImage.get(), parsedOptions.premultiplyAlpha | 404 croppedSkImage.get(), parsedOptions.premultiplyAlpha |
| 328 ? PremultiplyAlpha | 405 ? PremultiplyAlpha |
| 329 : DontPremultiplyAlpha)); | 406 : DontPremultiplyAlpha)); |
| 330 // Special case: The first parameter image is unpremul but we need to turn | 407 // Special case: The first parameter image is unpremul but we need to turn |
| 331 // it into premul. | 408 // it into premul. |
| 332 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) | 409 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) |
| 333 return StaticBitmapImage::create( | 410 return StaticBitmapImage::create( |
| 334 unPremulSkImageToPremul(croppedSkImage.get())); | 411 unPremulSkImageToPremul(croppedSkImage.get())); |
| 335 // Call preroll to trigger image decoding. | 412 // Call preroll to trigger image decoding. |
| 336 croppedSkImage->preroll(); | 413 croppedSkImage->preroll(); |
| 337 return StaticBitmapImage::create(std::move(croppedSkImage)); | 414 return StaticBitmapImage::create(std::move(croppedSkImage)); |
| 338 } | 415 } |
| 339 | 416 |
| 417 // Currently ImageDecoder assumes at most 8 bits per channel for the decoded | |
| 418 // image. When this is fixed, we should change this code to create the | |
| 419 // surface according to the color depth of the decoded image. | |
| 340 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( | 420 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( |
| 341 parsedOptions.resizeWidth, parsedOptions.resizeHeight); | 421 parsedOptions.resizeWidth, parsedOptions.resizeHeight); |
| 342 if (!surface) | 422 if (!surface) |
| 343 return nullptr; | 423 return nullptr; |
| 344 if (srcRect.isEmpty()) | 424 if (srcRect.isEmpty()) |
| 345 return StaticBitmapImage::create(surface->makeImageSnapshot()); | 425 return StaticBitmapImage::create(surface->makeImageSnapshot()); |
| 346 | 426 |
| 347 SkScalar dstLeft = std::min(0, -parsedOptions.cropRect.x()); | 427 SkScalar dstLeft = std::min(0, -parsedOptions.cropRect.x()); |
| 348 SkScalar dstTop = std::min(0, -parsedOptions.cropRect.y()); | 428 SkScalar dstTop = std::min(0, -parsedOptions.cropRect.y()); |
| 349 if (parsedOptions.cropRect.x() < 0) | 429 if (parsedOptions.cropRect.x() < 0) |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 362 parsedOptions.resizeHeight); | 442 parsedOptions.resizeHeight); |
| 363 SkPaint paint; | 443 SkPaint paint; |
| 364 paint.setFilterQuality(parsedOptions.resizeQuality); | 444 paint.setFilterQuality(parsedOptions.resizeQuality); |
| 365 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, | 445 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, |
| 366 &paint); | 446 &paint); |
| 367 } else { | 447 } else { |
| 368 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); | 448 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); |
| 369 } | 449 } |
| 370 skiaImage = surface->makeImageSnapshot(); | 450 skiaImage = surface->makeImageSnapshot(); |
| 371 | 451 |
| 452 if (colorSpaceOp == ImageDecoder::ColorSpaceApplied) | |
| 453 skiaImage = applyColorSpaceConversion(skiaImage, | |
| 454 parsedOptions.premultiplyAlpha, | |
| 455 imageBitmapOptions); | |
| 456 | |
| 372 if (parsedOptions.premultiplyAlpha) { | 457 if (parsedOptions.premultiplyAlpha) { |
| 373 if (imageFormat == DontPremultiplyAlpha) | 458 if (imageFormat == DontPremultiplyAlpha) |
| 374 return StaticBitmapImage::create( | 459 return StaticBitmapImage::create( |
| 375 unPremulSkImageToPremul(skiaImage.get())); | 460 unPremulSkImageToPremul(skiaImage.get())); |
| 376 return StaticBitmapImage::create(std::move(skiaImage)); | 461 return StaticBitmapImage::create(std::move(skiaImage)); |
| 377 } | 462 } |
| 378 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); | 463 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); |
| 379 } | 464 } |
| 380 | 465 |
| 381 ImageBitmap::ImageBitmap(HTMLImageElement* image, | 466 ImageBitmap::ImageBitmap(HTMLImageElement* image, |
| 382 Optional<IntRect> cropRect, | 467 Optional<IntRect> cropRect, |
| 383 Document* document, | 468 Document* document, |
| 384 const ImageBitmapOptions& options) { | 469 const ImageBitmapOptions& options) { |
| 385 RefPtr<Image> input = image->cachedImage()->getImage(); | 470 RefPtr<Image> input = image->cachedImage()->getImage(); |
| 386 ParsedOptions parsedOptions = | 471 ParsedOptions parsedOptions = |
| 387 parseOptions(options, cropRect, image->bitmapSourceSize()); | 472 parseOptions(options, cropRect, image->bitmapSourceSize()); |
| 388 if (dstBufferSizeHasOverflow(parsedOptions)) | 473 if (dstBufferSizeHasOverflow(parsedOptions)) |
| 389 return; | 474 return; |
| 390 | 475 |
| 391 if (options.colorSpaceConversion() == "none") { | 476 if (options.colorSpaceConversion() == "none") { |
| 392 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, | 477 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, |
| 393 ImageDecoder::ColorSpaceIgnored); | 478 ImageDecoder::ColorSpaceIgnored); |
| 394 } else { | 479 } else { |
| 395 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, | 480 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, |
| 396 ImageDecoder::ColorSpaceApplied); | 481 ImageDecoder::ColorSpaceApplied, &options); |
| 397 } | 482 } |
| 398 if (!m_image) | 483 if (!m_image) |
| 399 return; | 484 return; |
| 400 // In the case where the source image is lazy-decoded, m_image may not be in | 485 // In the case where the source image is lazy-decoded, m_image may not be in |
| 401 // a decoded state, we trigger it here. | 486 // a decoded state, we trigger it here. |
| 402 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame(); | 487 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame(); |
| 403 SkPixmap pixmap; | 488 SkPixmap pixmap; |
| 404 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { | 489 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { |
| 405 sk_sp<SkSurface> surface = | 490 sk_sp<SkSurface> surface = |
| 406 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); | 491 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 862 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, | 947 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, |
| 863 FloatRect* dstRect) const {} | 948 FloatRect* dstRect) const {} |
| 864 | 949 |
| 865 FloatSize ImageBitmap::elementSize(const FloatSize&) const { | 950 FloatSize ImageBitmap::elementSize(const FloatSize&) const { |
| 866 return FloatSize(width(), height()); | 951 return FloatSize(width(), height()); |
| 867 } | 952 } |
| 868 | 953 |
| 869 DEFINE_TRACE(ImageBitmap) {} | 954 DEFINE_TRACE(ImageBitmap) {} |
| 870 | 955 |
| 871 } // namespace blink | 956 } // namespace blink |
| OLD | NEW |