Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) | 2 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) |
| 3 * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. | 3 * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 62 , m_repetitionsComplete(0) | 62 , m_repetitionsComplete(0) |
| 63 , m_desiredFrameStartTime(0) | 63 , m_desiredFrameStartTime(0) |
| 64 , m_frameCount(0) | 64 , m_frameCount(0) |
| 65 , m_animationPolicy(ImageAnimationPolicyAllowed) | 65 , m_animationPolicy(ImageAnimationPolicyAllowed) |
| 66 , m_animationFinished(false) | 66 , m_animationFinished(false) |
| 67 , m_allDataReceived(false) | 67 , m_allDataReceived(false) |
| 68 , m_haveSize(false) | 68 , m_haveSize(false) |
| 69 , m_sizeAvailable(false) | 69 , m_sizeAvailable(false) |
| 70 , m_hasUniformFrameSize(true) | 70 , m_hasUniformFrameSize(true) |
| 71 , m_haveFrameCount(false) | 71 , m_haveFrameCount(false) |
| 72 , m_frameIndex(0) | |
|
Peter Kasting
2016/05/04 03:01:06
Here and below: Initialize members in the same ord
aleksandar.stojiljkovic
2016/05/07 19:50:52
Done.
| |
| 72 { | 73 { |
| 73 } | 74 } |
| 74 | 75 |
| 75 BitmapImage::BitmapImage(const SkBitmap& bitmap, ImageObserver* observer) | 76 BitmapImage::BitmapImage(const SkBitmap& bitmap, ImageObserver* observer) |
| 76 : Image(observer) | 77 : Image(observer) |
| 77 , m_size(bitmap.width(), bitmap.height()) | 78 , m_size(bitmap.width(), bitmap.height()) |
| 78 , m_currentFrame(0) | 79 , m_currentFrame(0) |
| 79 , m_repetitionCount(cAnimationNone) | 80 , m_repetitionCount(cAnimationNone) |
| 80 , m_repetitionCountStatus(Unknown) | 81 , m_repetitionCountStatus(Unknown) |
| 81 , m_repetitionsComplete(0) | 82 , m_repetitionsComplete(0) |
| 82 , m_frameCount(1) | 83 , m_frameCount(1) |
| 83 , m_animationPolicy(ImageAnimationPolicyAllowed) | 84 , m_animationPolicy(ImageAnimationPolicyAllowed) |
| 84 , m_animationFinished(true) | 85 , m_animationFinished(true) |
| 85 , m_allDataReceived(true) | 86 , m_allDataReceived(true) |
| 86 , m_haveSize(true) | 87 , m_haveSize(true) |
| 87 , m_sizeAvailable(true) | 88 , m_sizeAvailable(true) |
| 88 , m_haveFrameCount(true) | 89 , m_haveFrameCount(true) |
| 90 , m_frameIndex(0) | |
| 91 , m_frame(adoptRef(SkImage::NewFromBitmap(bitmap))) | |
| 89 { | 92 { |
| 90 // Since we don't have a decoder, we can't figure out the image orientation. | 93 // Since we don't have a decoder, we can't figure out the image orientation. |
| 91 // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0. | 94 // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0. |
| 92 m_sizeRespectingOrientation = m_size; | 95 m_sizeRespectingOrientation = m_size; |
| 93 | 96 |
| 94 m_frames.grow(1); | 97 m_frames.grow(1); |
| 95 m_frames[0].m_hasAlpha = !bitmap.isOpaque(); | 98 m_frames[0].m_hasAlpha = !bitmap.isOpaque(); |
| 96 m_frames[0].m_frame = adoptRef(SkImage::NewFromBitmap(bitmap)); | |
| 97 m_frames[0].m_haveMetadata = true; | 99 m_frames[0].m_haveMetadata = true; |
| 98 } | 100 } |
| 99 | 101 |
| 100 BitmapImage::~BitmapImage() | 102 BitmapImage::~BitmapImage() |
| 101 { | 103 { |
| 102 stopAnimation(); | 104 stopAnimation(); |
| 103 } | 105 } |
| 104 | 106 |
| 105 bool BitmapImage::currentFrameHasSingleSecurityOrigin() const | 107 bool BitmapImage::currentFrameHasSingleSecurityOrigin() const |
| 106 { | 108 { |
| 107 return true; | 109 return true; |
| 108 } | 110 } |
| 109 | 111 |
| 110 void BitmapImage::destroyDecodedData(bool destroyAll) | 112 void BitmapImage::destroyDecodedData() |
| 111 { | 113 { |
| 112 for (size_t i = 0; i < m_frames.size(); ++i) { | 114 m_frame.clear(); |
| 113 // The underlying frame isn't actually changing (we're just trying to | 115 for (size_t i = 0; i < m_frames.size(); ++i) |
| 114 // save the memory for the framebuffer data), so we don't need to clear | 116 m_frames[i].clear(true); |
| 115 // the metadata. | 117 m_source.clearCacheExceptFrame(kNotFound); |
| 116 m_frames[i].clear(false); | |
| 117 } | |
| 118 | |
| 119 m_source.clearCacheExceptFrame(destroyAll ? kNotFound : m_currentFrame); | |
| 120 notifyMemoryChanged(); | 118 notifyMemoryChanged(); |
| 121 } | 119 } |
| 122 | 120 |
| 123 void BitmapImage::destroyDecodedDataIfNecessary() | |
| 124 { | |
| 125 // Animated images >5MB are considered large enough that we'll only hang on | |
| 126 // to one frame at a time. | |
| 127 static const size_t cLargeAnimationCutoff = 5242880; | |
| 128 size_t allFrameBytes = 0; | |
| 129 for (size_t i = 0; i < m_frames.size(); ++i) | |
| 130 allFrameBytes += m_frames[i].m_frameBytes; | |
| 131 | |
| 132 if (allFrameBytes > cLargeAnimationCutoff) { | |
| 133 destroyDecodedData(false); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 void BitmapImage::notifyMemoryChanged() | 121 void BitmapImage::notifyMemoryChanged() |
| 138 { | 122 { |
| 139 if (getImageObserver()) | 123 if (getImageObserver()) |
| 140 getImageObserver()->decodedSizeChangedTo(this, totalFrameBytes()); | 124 getImageObserver()->decodedSizeChangedTo(this, totalFrameBytes()); |
| 141 } | 125 } |
| 142 | 126 |
| 143 size_t BitmapImage::totalFrameBytes() | 127 size_t BitmapImage::totalFrameBytes() |
| 144 { | 128 { |
| 145 const size_t numFrames = frameCount(); | 129 const size_t numFrames = frameCount(); |
| 146 size_t totalBytes = 0; | 130 size_t totalBytes = 0; |
| 147 for (size_t i = 0; i < numFrames; ++i) | 131 for (size_t i = 0; i < numFrames; ++i) |
| 148 totalBytes += m_source.frameBytesAtIndex(i); | 132 totalBytes += m_source.frameBytesAtIndex(i); |
| 149 return totalBytes; | 133 return totalBytes; |
| 150 } | 134 } |
| 151 | 135 |
| 152 void BitmapImage::cacheFrame(size_t index) | 136 PassRefPtr<SkImage> BitmapImage::cacheFrame(size_t index) |
| 153 { | 137 { |
| 154 size_t numFrames = frameCount(); | 138 size_t numFrames = frameCount(); |
| 155 if (m_frames.size() < numFrames) | 139 if (m_frames.size() < numFrames) |
| 156 m_frames.grow(numFrames); | 140 m_frames.grow(numFrames); |
| 157 | 141 |
| 158 // We are caching frame snapshots. This is OK even for partially decoded fr ames, | 142 // We are caching frame snapshots. This is OK even for partially decoded fr ames, |
| 159 // as they are cleared by dataChanged() when new data arrives. | 143 // as they are cleared by dataChanged() when new data arrives. |
| 160 m_frames[index].m_frame = m_source.createFrameAtIndex(index); | 144 RefPtr<SkImage> image = m_source.createFrameAtIndex(index); |
|
Peter Kasting
2016/05/04 03:01:06
Note that Skia is currently switching to sk_sp and
aleksandar.stojiljkovic
2016/05/04 20:56:29
I found several patches related to switch to sk_sp
| |
| 145 m_frame = image; | |
| 146 m_frameIndex = index; | |
| 161 | 147 |
| 162 m_frames[index].m_orientation = m_source.orientationAtIndex(index); | 148 m_frames[index].m_orientation = m_source.orientationAtIndex(index); |
| 163 m_frames[index].m_haveMetadata = true; | 149 m_frames[index].m_haveMetadata = true; |
| 164 m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index); | 150 m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index); |
| 165 if (repetitionCount(false) != cAnimationNone) | 151 if (repetitionCount(false) != cAnimationNone) |
| 166 m_frames[index].m_duration = m_source.frameDurationAtIndex(index); | 152 m_frames[index].m_duration = m_source.frameDurationAtIndex(index); |
| 167 m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index); | 153 m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index); |
| 168 m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index); | 154 m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index); |
| 169 | 155 |
| 170 const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size); | 156 const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size); |
| 171 if (frameSize != m_size) | 157 if (frameSize != m_size) |
| 172 m_hasUniformFrameSize = false; | 158 m_hasUniformFrameSize = false; |
| 173 | 159 |
| 174 notifyMemoryChanged(); | 160 notifyMemoryChanged(); |
| 161 return image.release(); | |
| 175 } | 162 } |
| 176 | 163 |
| 177 void BitmapImage::updateSize() const | 164 void BitmapImage::updateSize() const |
| 178 { | 165 { |
| 179 if (!m_sizeAvailable || m_haveSize) | 166 if (!m_sizeAvailable || m_haveSize) |
| 180 return; | 167 return; |
| 181 | 168 |
| 182 m_size = m_source.size(); | 169 m_size = m_source.size(); |
| 183 m_sizeRespectingOrientation = m_source.size(RespectImageOrientation); | 170 m_sizeRespectingOrientation = m_source.size(RespectImageOrientation); |
| 184 m_haveSize = true; | 171 m_haveSize = true; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 // frame affected by appending new data here. Thus we have to clear all the | 210 // frame affected by appending new data here. Thus we have to clear all the |
| 224 // incomplete frames to be safe. | 211 // incomplete frames to be safe. |
| 225 for (size_t i = 0; i < m_frames.size(); ++i) { | 212 for (size_t i = 0; i < m_frames.size(); ++i) { |
| 226 // NOTE: Don't call frameIsCompleteAtIndex() here, that will try to | 213 // NOTE: Don't call frameIsCompleteAtIndex() here, that will try to |
| 227 // decode any uncached (i.e. never-decoded or | 214 // decode any uncached (i.e. never-decoded or |
| 228 // cleared-on-a-previous-pass) frames! | 215 // cleared-on-a-previous-pass) frames! |
| 229 if (m_frames[i].m_haveMetadata && !m_frames[i].m_isComplete) | 216 if (m_frames[i].m_haveMetadata && !m_frames[i].m_isComplete) |
| 230 m_frames[i].clear(true); | 217 m_frames[i].clear(true); |
| 231 } | 218 } |
| 232 | 219 |
| 220 if (m_frameIndex < m_frames.size() && m_frames[m_frameIndex].m_haveMetadata && !m_frames[m_frameIndex].m_isComplete) | |
| 221 m_frame.clear(); | |
|
Peter Kasting
2016/05/04 03:01:06
I think this would be more clearly associated with
aleksandar.stojiljkovic
2016/05/04 20:56:29
Done.
| |
| 222 | |
| 233 // Feed all the data we've seen so far to the image decoder. | 223 // Feed all the data we've seen so far to the image decoder. |
| 234 m_allDataReceived = allDataReceived; | 224 m_allDataReceived = allDataReceived; |
| 235 ASSERT(data()); | 225 ASSERT(data()); |
| 236 m_source.setData(*data(), allDataReceived); | 226 m_source.setData(*data(), allDataReceived); |
| 237 | 227 |
| 238 m_haveFrameCount = false; | 228 m_haveFrameCount = false; |
| 239 m_hasUniformFrameSize = true; | 229 m_hasUniformFrameSize = true; |
| 240 return isSizeAvailable(); | 230 return isSizeAvailable(); |
| 241 } | 231 } |
| 242 | 232 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 284 // the image, as it was needed for page layout, so we need to revers e it back here. | 274 // the image, as it was needed for page layout, so we need to revers e it back here. |
| 285 adjustedDstRect = FloatRect(adjustedDstRect.x(), adjustedDstRect.y() , adjustedDstRect.height(), adjustedDstRect.width()); | 275 adjustedDstRect = FloatRect(adjustedDstRect.x(), adjustedDstRect.y() , adjustedDstRect.height(), adjustedDstRect.width()); |
| 286 } | 276 } |
| 287 } | 277 } |
| 288 | 278 |
| 289 SkRect skSrcRect = adjustedSrcRect; | 279 SkRect skSrcRect = adjustedSrcRect; |
| 290 canvas->drawImageRect(image.get(), skSrcRect, adjustedDstRect, &paint, | 280 canvas->drawImageRect(image.get(), skSrcRect, adjustedDstRect, &paint, |
| 291 WebCoreClampingModeToSkiaRectConstraint(clampMode)); | 281 WebCoreClampingModeToSkiaRectConstraint(clampMode)); |
| 292 canvas->restoreToCount(initialSaveCount); | 282 canvas->restoreToCount(initialSaveCount); |
| 293 | 283 |
| 294 if (currentFrameIsLazyDecoded()) | 284 if (image->isLazyGenerated()) |
| 295 PlatformInstrumentation::didDrawLazyPixelRef(image->uniqueID()); | 285 PlatformInstrumentation::didDrawLazyPixelRef(image->uniqueID()); |
| 296 | 286 |
| 297 if (ImageObserver* observer = getImageObserver()) | 287 if (ImageObserver* observer = getImageObserver()) |
| 298 observer->didDraw(this); | 288 observer->didDraw(this); |
| 299 | 289 |
| 300 startAnimation(); | 290 startAnimation(); |
| 301 } | 291 } |
| 302 | 292 |
| 303 size_t BitmapImage::frameCount() | 293 size_t BitmapImage::frameCount() |
| 304 { | 294 { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 326 | 316 |
| 327 if (m_sizeAvailable && hasVisibleImageSize(size())) { | 317 if (m_sizeAvailable && hasVisibleImageSize(size())) { |
| 328 BitmapImageMetrics::countDecodedImageType(m_source.filenameExtension()); | 318 BitmapImageMetrics::countDecodedImageType(m_source.filenameExtension()); |
| 329 if (m_source.filenameExtension() == "jpg") | 319 if (m_source.filenameExtension() == "jpg") |
| 330 BitmapImageMetrics::countImageOrientation(m_source.orientationAtInde x(0).orientation()); | 320 BitmapImageMetrics::countImageOrientation(m_source.orientationAtInde x(0).orientation()); |
| 331 } | 321 } |
| 332 | 322 |
| 333 return m_sizeAvailable; | 323 return m_sizeAvailable; |
| 334 } | 324 } |
| 335 | 325 |
| 336 bool BitmapImage::ensureFrameIsCached(size_t index) | |
| 337 { | |
| 338 if (index >= frameCount()) | |
| 339 return false; | |
| 340 | |
| 341 if (index >= m_frames.size() || !m_frames[index].m_frame) | |
| 342 cacheFrame(index); | |
| 343 | |
| 344 return true; | |
| 345 } | |
| 346 | |
| 347 PassRefPtr<SkImage> BitmapImage::frameAtIndex(size_t index) | 326 PassRefPtr<SkImage> BitmapImage::frameAtIndex(size_t index) |
| 348 { | 327 { |
| 349 if (!ensureFrameIsCached(index)) | 328 if (index >= frameCount()) |
| 350 return nullptr; | 329 return nullptr; |
| 351 | 330 |
| 352 return m_frames[index].m_frame; | 331 RefPtr<SkImage> image; |
| 332 if (index == m_frameIndex) | |
| 333 image = m_frame; | |
| 334 | |
| 335 if (image) { | |
| 336 return image.release(); | |
| 337 } | |
| 338 return cacheFrame(index); | |
|
Peter Kasting
2016/05/04 03:01:06
It seems like this is a long-winded way of writing
aleksandar.stojiljkovic
2016/05/04 20:56:29
Done.
| |
| 353 } | 339 } |
| 354 | 340 |
| 355 bool BitmapImage::frameIsCompleteAtIndex(size_t index) | 341 bool BitmapImage::frameIsCompleteAtIndex(size_t index) |
| 356 { | 342 { |
| 357 if (index < m_frames.size() && m_frames[index].m_haveMetadata && m_frames[in dex].m_isComplete) | 343 if (index < m_frames.size() && m_frames[index].m_haveMetadata && m_frames[in dex].m_isComplete) |
| 358 return true; | 344 return true; |
| 359 | 345 |
| 360 return m_source.frameIsCompleteAtIndex(index); | 346 return m_source.frameIsCompleteAtIndex(index); |
| 361 } | 347 } |
| 362 | 348 |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 557 // the timer unless all renderers have stopped drawing. | 543 // the timer unless all renderers have stopped drawing. |
| 558 m_frameTimer.clear(); | 544 m_frameTimer.clear(); |
| 559 } | 545 } |
| 560 | 546 |
| 561 void BitmapImage::resetAnimation() | 547 void BitmapImage::resetAnimation() |
| 562 { | 548 { |
| 563 stopAnimation(); | 549 stopAnimation(); |
| 564 m_currentFrame = 0; | 550 m_currentFrame = 0; |
| 565 m_repetitionsComplete = 0; | 551 m_repetitionsComplete = 0; |
| 566 m_desiredFrameStartTime = 0; | 552 m_desiredFrameStartTime = 0; |
| 567 m_animationFinished = false; | 553 m_animationFinished = false; |
|
Peter Kasting
2016/05/04 03:01:06
Should we clear m_frame here?
aleksandar.stojiljkovic
2016/05/04 20:56:29
Done.
Peter Kasting
2016/05/07 01:58:29
For clarity, I wasn't very sure whether we should
aleksandar.stojiljkovic
2016/05/07 19:50:52
Sorry, the way I handled this clear() was obscure
| |
| 568 | |
| 569 // For extremely large animations, when the animation is reset, we just thro w everything away. | |
| 570 destroyDecodedDataIfNecessary(); | |
| 571 } | 554 } |
| 572 | 555 |
| 573 bool BitmapImage::maybeAnimated() | 556 bool BitmapImage::maybeAnimated() |
| 574 { | 557 { |
| 575 if (m_animationFinished) | 558 if (m_animationFinished) |
| 576 return false; | 559 return false; |
| 577 if (frameCount() > 1) | 560 if (frameCount() > 1) |
| 578 return true; | 561 return true; |
| 579 | 562 |
| 580 return m_source.repetitionCount() != cAnimationNone; | 563 return m_source.repetitionCount() != cAnimationNone; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 618 // because it is 0 (see comments on its declaration in ImageAnimation.h) . | 601 // because it is 0 (see comments on its declaration in ImageAnimation.h) . |
| 619 if ((repetitionCount(true) != cAnimationLoopInfinite && m_repetitionsCom plete > m_repetitionCount) | 602 if ((repetitionCount(true) != cAnimationLoopInfinite && m_repetitionsCom plete > m_repetitionCount) |
| 620 || (m_animationPolicy == ImageAnimationPolicyAnimateOnce && m_repeti tionsComplete > 0)) { | 603 || (m_animationPolicy == ImageAnimationPolicyAnimateOnce && m_repeti tionsComplete > 0)) { |
| 621 m_animationFinished = true; | 604 m_animationFinished = true; |
| 622 m_desiredFrameStartTime = 0; | 605 m_desiredFrameStartTime = 0; |
| 623 --m_currentFrame; | 606 --m_currentFrame; |
| 624 advancedAnimation = false; | 607 advancedAnimation = false; |
| 625 } else | 608 } else |
| 626 m_currentFrame = 0; | 609 m_currentFrame = 0; |
| 627 } | 610 } |
| 628 destroyDecodedDataIfNecessary(); | |
| 629 | 611 |
| 630 // We need to draw this frame if we advanced to it while not skipping, or if | 612 // We need to draw this frame if we advanced to it while not skipping, or if |
| 631 // while trying to skip frames we hit the last frame and thus had to stop. | 613 // while trying to skip frames we hit the last frame and thus had to stop. |
| 632 if (skippingFrames != advancedAnimation) | 614 if (skippingFrames != advancedAnimation) |
| 633 getImageObserver()->animationAdvanced(this); | 615 getImageObserver()->animationAdvanced(this); |
| 616 | |
| 634 return advancedAnimation; | 617 return advancedAnimation; |
| 635 } | 618 } |
| 636 | 619 |
| 637 } // namespace blink | 620 } // namespace blink |
| OLD | NEW |