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" |
(...skipping 10 matching lines...) Expand all Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |