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

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

Issue 2192103002: Implement resize option for createImageBitmap(HTMLVideoElement) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 months 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
« no previous file with comments | « third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-video-resize.html ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
(...skipping 10 matching lines...) Expand all
21 static const char* imageBitmapOptionNone = "none"; 21 static const char* imageBitmapOptionNone = "none";
22 22
23 namespace { 23 namespace {
24 24
25 struct ParsedOptions { 25 struct ParsedOptions {
26 bool flipY = false; 26 bool flipY = false;
27 bool premultiplyAlpha = true; 27 bool premultiplyAlpha = true;
28 bool shouldScaleInput = false; 28 bool shouldScaleInput = false;
29 unsigned resizeWidth = 0; 29 unsigned resizeWidth = 0;
30 unsigned resizeHeight = 0; 30 unsigned resizeHeight = 0;
31 float scaleRatioX = 1;
32 float scaleRatioY = 1;
31 IntRect cropRect; 33 IntRect cropRect;
32 SkFilterQuality resizeQuality = kLow_SkFilterQuality; 34 SkFilterQuality resizeQuality = kLow_SkFilterQuality;
33 }; 35 };
34 36
35 // The following two functions are helpers used in cropImage 37 // The following two functions are helpers used in cropImage
36 static inline IntRect normalizeRect(const IntRect& rect) 38 static inline IntRect normalizeRect(const IntRect& rect)
37 { 39 {
38 return IntRect(std::min(rect.x(), rect.maxX()), 40 return IntRect(std::min(rect.x(), rect.maxX()),
39 std::min(rect.y(), rect.maxY()), 41 std::min(rect.y(), rect.maxY()),
40 std::max(rect.width(), -rect.width()), 42 std::max(rect.width(), -rect.width()),
41 std::max(rect.height(), -rect.height())); 43 std::max(rect.height(), -rect.height()));
42 } 44 }
43 45
44 static bool frameIsValid(const SkBitmap& frameBitmap) 46 static bool frameIsValid(const SkBitmap& frameBitmap)
45 { 47 {
46 ASSERT(!frameBitmap.isNull() && !frameBitmap.empty() && frameBitmap.isImmuta ble()); 48 ASSERT(!frameBitmap.isNull() && !frameBitmap.empty() && frameBitmap.isImmuta ble());
47 return frameBitmap.colorType() == kN32_SkColorType; 49 return frameBitmap.colorType() == kN32_SkColorType;
48 } 50 }
49 51
50 ParsedOptions parseOptions(const ImageBitmapOptions& options, Optional<IntRect> cropRect, IntSize sourceSize) 52 ParsedOptions parseOptions(const ImageBitmapOptions& options, Optional<IntRect> cropRect, IntSize sourceSize, bool shouldCalculateRatio)
51 { 53 {
52 ParsedOptions parsedOptions; 54 ParsedOptions parsedOptions;
53 if (options.imageOrientation() == imageOrientationFlipY) { 55 if (options.imageOrientation() == imageOrientationFlipY) {
54 parsedOptions.flipY = true; 56 parsedOptions.flipY = true;
55 } else { 57 } else {
56 parsedOptions.flipY = false; 58 parsedOptions.flipY = false;
57 DCHECK(options.imageOrientation() == imageBitmapOptionNone); 59 DCHECK(options.imageOrientation() == imageBitmapOptionNone);
58 } 60 }
59 if (options.premultiplyAlpha() == imageBitmapOptionNone) { 61 if (options.premultiplyAlpha() == imageBitmapOptionNone) {
60 parsedOptions.premultiplyAlpha = false; 62 parsedOptions.premultiplyAlpha = false;
(...skipping 20 matching lines...) Expand all
81 parsedOptions.resizeHeight = ceil(static_cast<float>(options.resizeWidth ()) / parsedOptions.cropRect.width() * parsedOptions.cropRect.height()); 83 parsedOptions.resizeHeight = ceil(static_cast<float>(options.resizeWidth ()) / parsedOptions.cropRect.width() * parsedOptions.cropRect.height());
82 } else { 84 } else {
83 parsedOptions.resizeHeight = options.resizeHeight(); 85 parsedOptions.resizeHeight = options.resizeHeight();
84 parsedOptions.resizeWidth = ceil(static_cast<float>(options.resizeHeight ()) / parsedOptions.cropRect.height() * parsedOptions.cropRect.width()); 86 parsedOptions.resizeWidth = ceil(static_cast<float>(options.resizeHeight ()) / parsedOptions.cropRect.height() * parsedOptions.cropRect.width());
85 } 87 }
86 if (static_cast<int>(parsedOptions.resizeWidth) == parsedOptions.cropRect.wi dth() && static_cast<int>(parsedOptions.resizeHeight) == parsedOptions.cropRect. height()) { 88 if (static_cast<int>(parsedOptions.resizeWidth) == parsedOptions.cropRect.wi dth() && static_cast<int>(parsedOptions.resizeHeight) == parsedOptions.cropRect. height()) {
87 parsedOptions.shouldScaleInput = false; 89 parsedOptions.shouldScaleInput = false;
88 return parsedOptions; 90 return parsedOptions;
89 } 91 }
90 parsedOptions.shouldScaleInput = true; 92 parsedOptions.shouldScaleInput = true;
93 if (shouldCalculateRatio) {
94 parsedOptions.scaleRatioX = static_cast<float>(parsedOptions.resizeWidth ) / parsedOptions.cropRect.width();
95 parsedOptions.scaleRatioY = static_cast<float>(parsedOptions.resizeHeigh t) / parsedOptions.cropRect.height();
96 }
91 97
92 if (options.resizeQuality() == "high") 98 if (options.resizeQuality() == "high")
93 parsedOptions.resizeQuality = kHigh_SkFilterQuality; 99 parsedOptions.resizeQuality = kHigh_SkFilterQuality;
94 else if (options.resizeQuality() == "medium") 100 else if (options.resizeQuality() == "medium")
95 parsedOptions.resizeQuality = kMedium_SkFilterQuality; 101 parsedOptions.resizeQuality = kMedium_SkFilterQuality;
96 else if (options.resizeQuality() == "pixelated") 102 else if (options.resizeQuality() == "pixelated")
97 parsedOptions.resizeQuality = kNone_SkFilterQuality; 103 parsedOptions.resizeQuality = kNone_SkFilterQuality;
98 else 104 else
99 parsedOptions.resizeQuality = kLow_SkFilterQuality; 105 parsedOptions.resizeQuality = kLow_SkFilterQuality;
100 return parsedOptions; 106 return parsedOptions;
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 if (imageFormat == PremultiplyAlpha) 281 if (imageFormat == PremultiplyAlpha)
276 return StaticBitmapImage::create(unPremulSkImageToPremul(skiaImage.g et())); 282 return StaticBitmapImage::create(unPremulSkImageToPremul(skiaImage.g et()));
277 return StaticBitmapImage::create(skiaImage.release()); 283 return StaticBitmapImage::create(skiaImage.release());
278 } 284 }
279 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); 285 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get()));
280 } 286 }
281 287
282 ImageBitmap::ImageBitmap(HTMLImageElement* image, Optional<IntRect> cropRect, Do cument* document, const ImageBitmapOptions& options) 288 ImageBitmap::ImageBitmap(HTMLImageElement* image, Optional<IntRect> cropRect, Do cument* document, const ImageBitmapOptions& options)
283 { 289 {
284 RefPtr<Image> input = image->cachedImage()->getImage(); 290 RefPtr<Image> input = image->cachedImage()->getImage();
285 ParsedOptions parsedOptions = parseOptions(options, cropRect, image->bitmapS ourceSize()); 291 ParsedOptions parsedOptions = parseOptions(options, cropRect, image->bitmapS ourceSize(), false);
286 292
287 if (options.colorSpaceConversion() == "none") 293 if (options.colorSpaceConversion() == "none")
288 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, ImageD ecoder::GammaAndColorProfileIgnored); 294 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, ImageD ecoder::GammaAndColorProfileIgnored);
289 else 295 else
290 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, ImageD ecoder::GammaAndColorProfileApplied); 296 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, ImageD ecoder::GammaAndColorProfileApplied);
291 if (!m_image) 297 if (!m_image)
292 return; 298 return;
293 // In the case where the source image is lazy-decoded, m_image may not be in 299 // In the case where the source image is lazy-decoded, m_image may not be in
294 // a decoded state, we trigger it here. 300 // a decoded state, we trigger it here.
295 RefPtr<SkImage> skImage = m_image->imageForCurrentFrame(); 301 RefPtr<SkImage> skImage = m_image->imageForCurrentFrame();
296 SkPixmap pixmap; 302 SkPixmap pixmap;
297 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { 303 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) {
298 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(skImage->width (), skImage->height()); 304 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(skImage->width (), skImage->height());
299 surface->getCanvas()->drawImage(skImage.get(), 0, 0); 305 surface->getCanvas()->drawImage(skImage.get(), 0, 0);
300 m_image = StaticBitmapImage::create(fromSkSp(surface->makeImageSnapshot( ))); 306 m_image = StaticBitmapImage::create(fromSkSp(surface->makeImageSnapshot( )));
301 } 307 }
302 m_image->setOriginClean(!image->wouldTaintOrigin(document->getSecurityOrigin ())); 308 m_image->setOriginClean(!image->wouldTaintOrigin(document->getSecurityOrigin ()));
303 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 309 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
304 } 310 }
305 311
306 ImageBitmap::ImageBitmap(HTMLVideoElement* video, Optional<IntRect> cropRect, Do cument* document, const ImageBitmapOptions& options) 312 ImageBitmap::ImageBitmap(HTMLVideoElement* video, Optional<IntRect> cropRect, Do cument* document, const ImageBitmapOptions& options)
307 { 313 {
308 IntSize playerSize; 314 IntSize playerSize;
309 if (video->webMediaPlayer()) 315 if (video->webMediaPlayer())
310 playerSize = video->webMediaPlayer()->naturalSize(); 316 playerSize = video->webMediaPlayer()->naturalSize();
311 317 ParsedOptions parsedOptions = parseOptions(options, cropRect, video->bitmapS ourceSize(), true);
312 // TODO(xidachen); implement the resize option.
313 ParsedOptions parsedOptions = parseOptions(options, cropRect, video->bitmapS ourceSize());
314 318
315 IntRect videoRect = IntRect(IntPoint(), playerSize); 319 IntRect videoRect = IntRect(IntPoint(), playerSize);
316 IntRect srcRect = intersection(parsedOptions.cropRect, videoRect); 320 IntRect srcRect = intersection(parsedOptions.cropRect, videoRect);
317 std::unique_ptr<ImageBuffer> buffer = ImageBuffer::create(parsedOptions.crop Rect.size(), NonOpaque, DoNotInitializeImagePixels); 321 std::unique_ptr<ImageBuffer> buffer = ImageBuffer::create(IntSize(parsedOpti ons.resizeWidth, parsedOptions.resizeHeight), NonOpaque, DoNotInitializeImagePix els);
318 if (!buffer) 322 if (!buffer)
319 return; 323 return;
320 324
321 if (parsedOptions.flipY) { 325 if (parsedOptions.flipY) {
322 buffer->canvas()->translate(0, buffer->size().height()); 326 buffer->canvas()->translate(0, buffer->size().height());
323 buffer->canvas()->scale(1, -1); 327 buffer->canvas()->scale(1, -1);
324 } 328 }
325 IntPoint dstPoint = IntPoint(std::max(0, -parsedOptions.cropRect.x()), std:: max(0, -parsedOptions.cropRect.y())); 329 IntPoint dstPoint = IntPoint(std::max(0, -parsedOptions.cropRect.x()), std:: max(0, -parsedOptions.cropRect.y()));
326 video->paintCurrentFrame(buffer->canvas(), IntRect(dstPoint, srcRect.size()) , nullptr); 330 IntSize dstSize = srcRect.size();
331 SkPaint paint;
332 if (parsedOptions.shouldScaleInput) {
333 dstPoint.scale(parsedOptions.scaleRatioX, parsedOptions.scaleRatioY);
Justin Novosad 2016/07/29 15:08:52 putting the scaleRAtion in parsedOptions is overki
xidachen 2016/07/29 17:22:10 Yes, that makes perfect sense. Changed in the new
334 paint.setFilterQuality(parsedOptions.resizeQuality);
335 dstSize.scale(parsedOptions.scaleRatioX, parsedOptions.scaleRatioY);
336 }
337 video->paintCurrentFrame(buffer->canvas(), IntRect(dstPoint, dstSize), parse dOptions.shouldScaleInput ? &paint : nullptr);
327 338
328 RefPtr<SkImage> skiaImage = buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown); 339 RefPtr<SkImage> skiaImage = buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown);
329 if (!parsedOptions.premultiplyAlpha) 340 if (!parsedOptions.premultiplyAlpha)
330 skiaImage = premulSkImageToUnPremul(skiaImage.get()); 341 skiaImage = premulSkImageToUnPremul(skiaImage.get());
331 m_image = StaticBitmapImage::create(skiaImage.release()); 342 m_image = StaticBitmapImage::create(skiaImage.release());
332 m_image->setOriginClean(!video->wouldTaintOrigin(document->getSecurityOrigin ())); 343 m_image->setOriginClean(!video->wouldTaintOrigin(document->getSecurityOrigin ()));
333 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 344 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
334 } 345 }
335 346
336 ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, Optional<IntRect> cropRect, const ImageBitmapOptions& options) 347 ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, Optional<IntRect> cropRect, const ImageBitmapOptions& options)
337 { 348 {
338 ASSERT(canvas->isPaintable()); 349 ASSERT(canvas->isPaintable());
339 RefPtr<Image> input = canvas->copiedImage(BackBuffer, PreferAcceleration); 350 RefPtr<Image> input = canvas->copiedImage(BackBuffer, PreferAcceleration);
340 ParsedOptions parsedOptions = parseOptions(options, cropRect, canvas->bitmap SourceSize()); 351 ParsedOptions parsedOptions = parseOptions(options, cropRect, canvas->bitmap SourceSize(), false);
341 352
342 bool isPremultiplyAlphaReverted = false; 353 bool isPremultiplyAlphaReverted = false;
343 if (!parsedOptions.premultiplyAlpha) { 354 if (!parsedOptions.premultiplyAlpha) {
344 parsedOptions.premultiplyAlpha = true; 355 parsedOptions.premultiplyAlpha = true;
345 isPremultiplyAlphaReverted = true; 356 isPremultiplyAlphaReverted = true;
346 } 357 }
347 m_image = cropImage(input.get(), parsedOptions); 358 m_image = cropImage(input.get(), parsedOptions);
348 if (!m_image) 359 if (!m_image)
349 return; 360 return;
350 if (isPremultiplyAlphaReverted) { 361 if (isPremultiplyAlphaReverted) {
(...skipping 21 matching lines...) Expand all
372 return fromSkSp(SkImage::MakeFromRaster(pixmap, [](const void* pixels, void* ) 383 return fromSkSp(SkImage::MakeFromRaster(pixmap, [](const void* pixels, void* )
373 { 384 {
374 delete[] static_cast<const uint8_t*>(pixels); 385 delete[] static_cast<const uint8_t*>(pixels);
375 }, nullptr)); 386 }, nullptr));
376 } 387 }
377 388
378 ImageBitmap::ImageBitmap(ImageData* data, Optional<IntRect> cropRect, const Imag eBitmapOptions& options) 389 ImageBitmap::ImageBitmap(ImageData* data, Optional<IntRect> cropRect, const Imag eBitmapOptions& options)
379 { 390 {
380 // TODO(xidachen): implement the resize option 391 // TODO(xidachen): implement the resize option
381 IntRect dataSrcRect = IntRect(IntPoint(), data->size()); 392 IntRect dataSrcRect = IntRect(IntPoint(), data->size());
382 ParsedOptions parsedOptions = parseOptions(options, cropRect, data->bitmapSo urceSize()); 393 ParsedOptions parsedOptions = parseOptions(options, cropRect, data->bitmapSo urceSize(), false);
383 IntRect srcRect = cropRect ? intersection(parsedOptions.cropRect, dataSrcRec t) : dataSrcRect; 394 IntRect srcRect = cropRect ? intersection(parsedOptions.cropRect, dataSrcRec t) : dataSrcRect;
384 395
385 // treat non-premultiplyAlpha as a special case 396 // treat non-premultiplyAlpha as a special case
386 if (!parsedOptions.premultiplyAlpha) { 397 if (!parsedOptions.premultiplyAlpha) {
387 unsigned char* srcAddr = data->data()->data(); 398 unsigned char* srcAddr = data->data()->data();
388 int srcHeight = data->size().height(); 399 int srcHeight = data->size().height();
389 int dstHeight = parsedOptions.cropRect.height(); 400 int dstHeight = parsedOptions.cropRect.height();
390 401
391 // Using kN32 type, swizzle input if necessary. 402 // Using kN32 type, swizzle input if necessary.
392 SkImageInfo info = SkImageInfo::Make(parsedOptions.cropRect.width(), dst Height, kN32_SkColorType, kUnpremul_SkAlphaType); 403 SkImageInfo info = SkImageInfo::Make(parsedOptions.cropRect.width(), dst Height, kN32_SkColorType, kUnpremul_SkAlphaType);
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 skImage = fromSkSp(surface->makeImageSnapshot()); 484 skImage = fromSkSp(surface->makeImageSnapshot());
474 } 485 }
475 m_image = StaticBitmapImage::create(skImage); 486 m_image = StaticBitmapImage::create(skImage);
476 } 487 }
477 488
478 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, Optional<IntRect> cropRect, const ImageBitmapOptions& options) 489 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, Optional<IntRect> cropRect, const ImageBitmapOptions& options)
479 { 490 {
480 RefPtr<Image> input = bitmap->bitmapImage(); 491 RefPtr<Image> input = bitmap->bitmapImage();
481 if (!input) 492 if (!input)
482 return; 493 return;
483 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()) ; 494 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size(), false);
484 495
485 m_image = cropImage(input.get(), parsedOptions, bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha); 496 m_image = cropImage(input.get(), parsedOptions, bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha);
486 if (!m_image) 497 if (!m_image)
487 return; 498 return;
488 m_image->setOriginClean(bitmap->originClean()); 499 m_image->setOriginClean(bitmap->originClean());
489 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 500 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
490 } 501 }
491 502
492 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, Optional<IntRect> cropRect, const ImageBitmapOptions& options) 503 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, Optional<IntRect> cropRect, const ImageBitmapOptions& options)
493 { 504 {
494 bool originClean = image->originClean(); 505 bool originClean = image->originClean();
495 RefPtr<Image> input = image; 506 RefPtr<Image> input = image;
496 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()) ; 507 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size(), false);
497 508
498 m_image = cropImage(input.get(), parsedOptions, DontPremultiplyAlpha); 509 m_image = cropImage(input.get(), parsedOptions, DontPremultiplyAlpha);
499 if (!m_image) 510 if (!m_image)
500 return; 511 return;
501 m_image->setOriginClean(originClean); 512 m_image->setOriginClean(originClean);
502 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); 513 m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
503 } 514 }
504 515
505 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) 516 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image)
506 { 517 {
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
641 FloatSize ImageBitmap::elementSize(const FloatSize&) const 652 FloatSize ImageBitmap::elementSize(const FloatSize&) const
642 { 653 {
643 return FloatSize(width(), height()); 654 return FloatSize(width(), height());
644 } 655 }
645 656
646 DEFINE_TRACE(ImageBitmap) 657 DEFINE_TRACE(ImageBitmap)
647 { 658 {
648 } 659 }
649 660
650 } // namespace blink 661 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-video-resize.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698