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 |