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/AcceleratedStaticBitmapImage.h" | 10 #include "platform/graphics/AcceleratedStaticBitmapImage.h" |
| 11 #include "platform/graphics/skia/SkiaUtils.h" | 11 #include "platform/graphics/skia/SkiaUtils.h" |
| 12 #include "platform/image-decoders/ImageDecoder.h" | 12 #include "platform/image-decoders/ImageDecoder.h" |
| 13 #include "third_party/skia/include/core/SkCanvas.h" | 13 #include "third_party/skia/include/core/SkCanvas.h" |
| 14 #include "third_party/skia/include/core/SkSurface.h" | 14 #include "third_party/skia/include/core/SkSurface.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 { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 parsedOptions.resizeQuality = kHigh_SkFilterQuality; | 95 parsedOptions.resizeQuality = kHigh_SkFilterQuality; |
| 95 else if (options.resizeQuality() == "medium") | 96 else if (options.resizeQuality() == "medium") |
| 96 parsedOptions.resizeQuality = kMedium_SkFilterQuality; | 97 parsedOptions.resizeQuality = kMedium_SkFilterQuality; |
| 97 else if (options.resizeQuality() == "pixelated") | 98 else if (options.resizeQuality() == "pixelated") |
| 98 parsedOptions.resizeQuality = kNone_SkFilterQuality; | 99 parsedOptions.resizeQuality = kNone_SkFilterQuality; |
| 99 else | 100 else |
| 100 parsedOptions.resizeQuality = kLow_SkFilterQuality; | 101 parsedOptions.resizeQuality = kLow_SkFilterQuality; |
| 101 return parsedOptions; | 102 return parsedOptions; |
| 102 } | 103 } |
| 103 | 104 |
| 105 bool couldDstSizeOverflow(int width, int height) | |
|
Justin Novosad
2016/08/18 16:42:14
DstBufferSizeHasOverflow
xidachen
2016/08/22 12:02:28
Done.
| |
| 106 { | |
| 107 CheckedNumeric<int> totalBytes = width; | |
|
Justin Novosad
2016/08/18 16:42:14
Why int and not size_t? If there is code somewhere
xidachen
2016/08/22 12:02:28
Done.
| |
| 108 totalBytes *= height; | |
| 109 if (!totalBytes.IsValid()) | |
|
Justin Novosad
2016/08/18 16:42:14
This one is not necessary. Just check is Valid at
xidachen
2016/08/22 12:02:28
Done.
| |
| 110 return true; | |
| 111 totalBytes *= 4; | |
|
Justin Novosad
2016/08/18 16:42:14
This hardcoded 4 is dangerous. We will soon suppor
xidachen
2016/08/22 12:02:28
Done.
| |
| 112 if (!totalBytes.IsValid()) | |
| 113 return true; | |
| 114 return false; | |
| 115 } | |
| 116 | |
| 104 } // namespace | 117 } // namespace |
| 105 | 118 |
| 106 static std::unique_ptr<uint8_t[]> copySkImageData(SkImage* input, const SkImageI nfo& info) | 119 static std::unique_ptr<uint8_t[]> copySkImageData(SkImage* input, const SkImageI nfo& info) |
| 107 { | 120 { |
| 108 std::unique_ptr<uint8_t[]> dstPixels = wrapArrayUnique(new uint8_t[input->wi dth() * input->height() * info.bytesPerPixel()]); | 121 std::unique_ptr<uint8_t[]> dstPixels = wrapArrayUnique(new uint8_t[input->wi dth() * input->height() * info.bytesPerPixel()]); |
| 109 input->readPixels(info, dstPixels.get(), input->width() * info.bytesPerPixel (), 0, 0); | 122 input->readPixels(info, dstPixels.get(), input->width() * info.bytesPerPixel (), 0, 0); |
| 110 return dstPixels; | 123 return dstPixels; |
| 111 } | 124 } |
| 112 | 125 |
| 113 static PassRefPtr<SkImage> newSkImageFromRaster(const SkImageInfo& info, std::un ique_ptr<uint8_t[]> imagePixels, int imageRowBytes) | 126 static PassRefPtr<SkImage> newSkImageFromRaster(const SkImageInfo& info, std::un ique_ptr<uint8_t[]> imagePixels, int imageRowBytes) |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 282 return StaticBitmapImage::create(unPremulSkImageToPremul(skiaImage.g et())); | 295 return StaticBitmapImage::create(unPremulSkImageToPremul(skiaImage.g et())); |
| 283 return StaticBitmapImage::create(skiaImage.release()); | 296 return StaticBitmapImage::create(skiaImage.release()); |
| 284 } | 297 } |
| 285 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); | 298 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); |
| 286 } | 299 } |
| 287 | 300 |
| 288 ImageBitmap::ImageBitmap(HTMLImageElement* image, Optional<IntRect> cropRect, Do cument* document, const ImageBitmapOptions& options) | 301 ImageBitmap::ImageBitmap(HTMLImageElement* image, Optional<IntRect> cropRect, Do cument* document, const ImageBitmapOptions& options) |
| 289 { | 302 { |
| 290 RefPtr<Image> input = image->cachedImage()->getImage(); | 303 RefPtr<Image> input = image->cachedImage()->getImage(); |
| 291 ParsedOptions parsedOptions = parseOptions(options, cropRect, image->bitmapS ourceSize()); | 304 ParsedOptions parsedOptions = parseOptions(options, cropRect, image->bitmapS ourceSize()); |
| 305 if (couldDstSizeOverflow(parsedOptions.cropRect.width(), parsedOptions.cropR ect.height())) | |
|
Justin Novosad
2016/08/18 16:42:14
This repeated bit of code could be made simpler if
xidachen
2016/08/22 12:02:28
Moving the check to the place where overflow occur
| |
| 306 return; | |
| 307 if (parsedOptions.shouldScaleInput && couldDstSizeOverflow(parsedOptions.res izeWidth, parsedOptions.resizeHeight)) | |
| 308 return; | |
| 292 | 309 |
| 293 if (options.colorSpaceConversion() == "none") | 310 if (options.colorSpaceConversion() == "none") |
| 294 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, ImageD ecoder::GammaAndColorProfileIgnored); | 311 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, ImageD ecoder::GammaAndColorProfileIgnored); |
| 295 else | 312 else |
| 296 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, ImageD ecoder::GammaAndColorProfileApplied); | 313 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, ImageD ecoder::GammaAndColorProfileApplied); |
| 297 if (!m_image) | 314 if (!m_image) |
| 298 return; | 315 return; |
| 299 // In the case where the source image is lazy-decoded, m_image may not be in | 316 // In the case where the source image is lazy-decoded, m_image may not be in |
| 300 // a decoded state, we trigger it here. | 317 // a decoded state, we trigger it here. |
| 301 RefPtr<SkImage> skImage = m_image->imageForCurrentFrame(); | 318 RefPtr<SkImage> skImage = m_image->imageForCurrentFrame(); |
| 302 SkPixmap pixmap; | 319 SkPixmap pixmap; |
| 303 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { | 320 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { |
| 304 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(skImage->width (), skImage->height()); | 321 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(skImage->width (), skImage->height()); |
| 305 surface->getCanvas()->drawImage(skImage.get(), 0, 0); | 322 surface->getCanvas()->drawImage(skImage.get(), 0, 0); |
| 306 m_image = StaticBitmapImage::create(fromSkSp(surface->makeImageSnapshot( ))); | 323 m_image = StaticBitmapImage::create(fromSkSp(surface->makeImageSnapshot( ))); |
| 307 } | 324 } |
| 308 m_image->setOriginClean(!image->wouldTaintOrigin(document->getSecurityOrigin ())); | 325 m_image->setOriginClean(!image->wouldTaintOrigin(document->getSecurityOrigin ())); |
| 309 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); | 326 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| 310 } | 327 } |
| 311 | 328 |
| 312 ImageBitmap::ImageBitmap(HTMLVideoElement* video, Optional<IntRect> cropRect, Do cument* document, const ImageBitmapOptions& options) | 329 ImageBitmap::ImageBitmap(HTMLVideoElement* video, Optional<IntRect> cropRect, Do cument* document, const ImageBitmapOptions& options) |
| 313 { | 330 { |
| 314 IntSize playerSize; | 331 IntSize playerSize; |
| 315 if (video->webMediaPlayer()) | 332 if (video->webMediaPlayer()) |
| 316 playerSize = video->webMediaPlayer()->naturalSize(); | 333 playerSize = video->webMediaPlayer()->naturalSize(); |
| 317 ParsedOptions parsedOptions = parseOptions(options, cropRect, video->bitmapS ourceSize()); | 334 ParsedOptions parsedOptions = parseOptions(options, cropRect, video->bitmapS ourceSize()); |
| 335 if (couldDstSizeOverflow(parsedOptions.cropRect.width(), parsedOptions.cropR ect.height())) | |
| 336 return; | |
| 337 if (parsedOptions.shouldScaleInput && couldDstSizeOverflow(parsedOptions.res izeWidth, parsedOptions.resizeHeight)) | |
| 338 return; | |
| 318 | 339 |
| 319 IntRect videoRect = IntRect(IntPoint(), playerSize); | 340 IntRect videoRect = IntRect(IntPoint(), playerSize); |
| 320 IntRect srcRect = intersection(parsedOptions.cropRect, videoRect); | 341 IntRect srcRect = intersection(parsedOptions.cropRect, videoRect); |
| 321 std::unique_ptr<ImageBuffer> buffer = ImageBuffer::create(IntSize(parsedOpti ons.resizeWidth, parsedOptions.resizeHeight), NonOpaque, DoNotInitializeImagePix els); | 342 std::unique_ptr<ImageBuffer> buffer = ImageBuffer::create(IntSize(parsedOpti ons.resizeWidth, parsedOptions.resizeHeight), NonOpaque, DoNotInitializeImagePix els); |
| 322 if (!buffer) | 343 if (!buffer) |
| 323 return; | 344 return; |
| 324 | 345 |
| 325 if (parsedOptions.flipY) { | 346 if (parsedOptions.flipY) { |
| 326 buffer->canvas()->translate(0, buffer->size().height()); | 347 buffer->canvas()->translate(0, buffer->size().height()); |
| 327 buffer->canvas()->scale(1, -1); | 348 buffer->canvas()->scale(1, -1); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 344 m_image = StaticBitmapImage::create(skiaImage.release()); | 365 m_image = StaticBitmapImage::create(skiaImage.release()); |
| 345 m_image->setOriginClean(!video->wouldTaintOrigin(document->getSecurityOrigin ())); | 366 m_image->setOriginClean(!video->wouldTaintOrigin(document->getSecurityOrigin ())); |
| 346 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); | 367 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| 347 } | 368 } |
| 348 | 369 |
| 349 ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, Optional<IntRect> cropRect, const ImageBitmapOptions& options) | 370 ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, Optional<IntRect> cropRect, const ImageBitmapOptions& options) |
| 350 { | 371 { |
| 351 ASSERT(canvas->isPaintable()); | 372 ASSERT(canvas->isPaintable()); |
| 352 RefPtr<Image> input = canvas->copiedImage(BackBuffer, PreferAcceleration); | 373 RefPtr<Image> input = canvas->copiedImage(BackBuffer, PreferAcceleration); |
| 353 ParsedOptions parsedOptions = parseOptions(options, cropRect, canvas->bitmap SourceSize()); | 374 ParsedOptions parsedOptions = parseOptions(options, cropRect, canvas->bitmap SourceSize()); |
| 375 if (couldDstSizeOverflow(parsedOptions.cropRect.width(), parsedOptions.cropR ect.height())) | |
| 376 return; | |
| 377 if (parsedOptions.shouldScaleInput && couldDstSizeOverflow(parsedOptions.res izeWidth, parsedOptions.resizeHeight)) | |
| 378 return; | |
| 354 | 379 |
| 355 bool isPremultiplyAlphaReverted = false; | 380 bool isPremultiplyAlphaReverted = false; |
| 356 if (!parsedOptions.premultiplyAlpha) { | 381 if (!parsedOptions.premultiplyAlpha) { |
| 357 parsedOptions.premultiplyAlpha = true; | 382 parsedOptions.premultiplyAlpha = true; |
| 358 isPremultiplyAlphaReverted = true; | 383 isPremultiplyAlphaReverted = true; |
| 359 } | 384 } |
| 360 m_image = cropImage(input.get(), parsedOptions); | 385 m_image = cropImage(input.get(), parsedOptions); |
| 361 if (!m_image) | 386 if (!m_image) |
| 362 return; | 387 return; |
| 363 if (isPremultiplyAlphaReverted) { | 388 if (isPremultiplyAlphaReverted) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 386 { | 411 { |
| 387 delete[] static_cast<const uint8_t*>(pixels); | 412 delete[] static_cast<const uint8_t*>(pixels); |
| 388 }, nullptr)); | 413 }, nullptr)); |
| 389 } | 414 } |
| 390 | 415 |
| 391 ImageBitmap::ImageBitmap(ImageData* data, Optional<IntRect> cropRect, const Imag eBitmapOptions& options) | 416 ImageBitmap::ImageBitmap(ImageData* data, Optional<IntRect> cropRect, const Imag eBitmapOptions& options) |
| 392 { | 417 { |
| 393 // TODO(xidachen): implement the resize option | 418 // TODO(xidachen): implement the resize option |
| 394 IntRect dataSrcRect = IntRect(IntPoint(), data->size()); | 419 IntRect dataSrcRect = IntRect(IntPoint(), data->size()); |
| 395 ParsedOptions parsedOptions = parseOptions(options, cropRect, data->bitmapSo urceSize()); | 420 ParsedOptions parsedOptions = parseOptions(options, cropRect, data->bitmapSo urceSize()); |
| 421 if (couldDstSizeOverflow(parsedOptions.cropRect.width(), parsedOptions.cropR ect.height())) | |
| 422 return; | |
| 423 if (parsedOptions.shouldScaleInput && couldDstSizeOverflow(parsedOptions.res izeWidth, parsedOptions.resizeHeight)) | |
| 424 return; | |
| 396 IntRect srcRect = cropRect ? intersection(parsedOptions.cropRect, dataSrcRec t) : dataSrcRect; | 425 IntRect srcRect = cropRect ? intersection(parsedOptions.cropRect, dataSrcRec t) : dataSrcRect; |
| 397 | 426 |
| 398 // treat non-premultiplyAlpha as a special case | 427 // treat non-premultiplyAlpha as a special case |
| 399 if (!parsedOptions.premultiplyAlpha) { | 428 if (!parsedOptions.premultiplyAlpha) { |
| 400 unsigned char* srcAddr = data->data()->data(); | 429 unsigned char* srcAddr = data->data()->data(); |
| 401 int srcHeight = data->size().height(); | 430 int srcHeight = data->size().height(); |
| 402 int dstHeight = parsedOptions.cropRect.height(); | 431 int dstHeight = parsedOptions.cropRect.height(); |
| 403 | 432 |
| 404 // Using kN32 type, swizzle input if necessary. | 433 // Using kN32 type, swizzle input if necessary. |
| 405 SkImageInfo info = SkImageInfo::Make(parsedOptions.cropRect.width(), dst Height, kN32_SkColorType, kUnpremul_SkAlphaType); | 434 SkImageInfo info = SkImageInfo::Make(parsedOptions.cropRect.width(), dst Height, kN32_SkColorType, kUnpremul_SkAlphaType); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 485 } | 514 } |
| 486 m_image = StaticBitmapImage::create(skImage); | 515 m_image = StaticBitmapImage::create(skImage); |
| 487 } | 516 } |
| 488 | 517 |
| 489 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, Optional<IntRect> cropRect, const ImageBitmapOptions& options) | 518 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, Optional<IntRect> cropRect, const ImageBitmapOptions& options) |
| 490 { | 519 { |
| 491 RefPtr<Image> input = bitmap->bitmapImage(); | 520 RefPtr<Image> input = bitmap->bitmapImage(); |
| 492 if (!input) | 521 if (!input) |
| 493 return; | 522 return; |
| 494 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()) ; | 523 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()) ; |
| 524 if (couldDstSizeOverflow(parsedOptions.cropRect.width(), parsedOptions.cropR ect.height())) | |
| 525 return; | |
| 526 if (parsedOptions.shouldScaleInput && couldDstSizeOverflow(parsedOptions.res izeWidth, parsedOptions.resizeHeight)) | |
| 527 return; | |
| 495 | 528 |
| 496 m_image = cropImage(input.get(), parsedOptions, bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha); | 529 m_image = cropImage(input.get(), parsedOptions, bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha); |
| 497 if (!m_image) | 530 if (!m_image) |
| 498 return; | 531 return; |
| 499 m_image->setOriginClean(bitmap->originClean()); | 532 m_image->setOriginClean(bitmap->originClean()); |
| 500 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); | 533 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| 501 } | 534 } |
| 502 | 535 |
| 503 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, Optional<IntRect> cropRect, const ImageBitmapOptions& options) | 536 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, Optional<IntRect> cropRect, const ImageBitmapOptions& options) |
| 504 { | 537 { |
| 505 bool originClean = image->originClean(); | 538 bool originClean = image->originClean(); |
| 506 RefPtr<Image> input = image; | 539 RefPtr<Image> input = image; |
| 507 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()) ; | 540 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()) ; |
| 541 if (couldDstSizeOverflow(parsedOptions.cropRect.width(), parsedOptions.cropR ect.height())) | |
| 542 return; | |
| 543 if (parsedOptions.shouldScaleInput && couldDstSizeOverflow(parsedOptions.res izeWidth, parsedOptions.resizeHeight)) | |
| 544 return; | |
| 508 | 545 |
| 509 m_image = cropImage(input.get(), parsedOptions, DontPremultiplyAlpha); | 546 m_image = cropImage(input.get(), parsedOptions, DontPremultiplyAlpha); |
| 510 if (!m_image) | 547 if (!m_image) |
| 511 return; | 548 return; |
| 512 m_image->setOriginClean(originClean); | 549 m_image->setOriginClean(originClean); |
| 513 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); | 550 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| 514 } | 551 } |
| 515 | 552 |
| 516 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) | 553 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) |
| 517 { | 554 { |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 652 FloatSize ImageBitmap::elementSize(const FloatSize&) const | 689 FloatSize ImageBitmap::elementSize(const FloatSize&) const |
| 653 { | 690 { |
| 654 return FloatSize(width(), height()); | 691 return FloatSize(width(), height()); |
| 655 } | 692 } |
| 656 | 693 |
| 657 DEFINE_TRACE(ImageBitmap) | 694 DEFINE_TRACE(ImageBitmap) |
| 658 { | 695 { |
| 659 } | 696 } |
| 660 | 697 |
| 661 } // namespace blink | 698 } // namespace blink |
| OLD | NEW |