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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
50 RefPtr<BitmapImage> result = adoptRef(new BitmapImage(bitmap)); | 50 RefPtr<BitmapImage> result = adoptRef(new BitmapImage(bitmap)); |
51 result->m_frames[0].m_orientation = orientation; | 51 result->m_frames[0].m_orientation = orientation; |
52 if (orientation.usesWidthAsHeight()) | 52 if (orientation.usesWidthAsHeight()) |
53 result->m_sizeRespectingOrientation = result->m_size.transposedSize(); | 53 result->m_sizeRespectingOrientation = result->m_size.transposedSize(); |
54 return result.release(); | 54 return result.release(); |
55 } | 55 } |
56 | 56 |
57 BitmapImage::BitmapImage(ImageObserver* observer) | 57 BitmapImage::BitmapImage(ImageObserver* observer) |
58 : Image(observer) | 58 : Image(observer) |
59 , m_currentFrame(0) | 59 , m_currentFrame(0) |
60 , m_cachedFrameIndex(0) | |
60 , m_repetitionCount(cAnimationNone) | 61 , m_repetitionCount(cAnimationNone) |
61 , m_repetitionCountStatus(Unknown) | 62 , m_repetitionCountStatus(Unknown) |
62 , m_repetitionsComplete(0) | 63 , m_repetitionsComplete(0) |
63 , m_desiredFrameStartTime(0) | 64 , m_desiredFrameStartTime(0) |
64 , m_frameCount(0) | 65 , m_frameCount(0) |
65 , m_animationPolicy(ImageAnimationPolicyAllowed) | 66 , m_animationPolicy(ImageAnimationPolicyAllowed) |
66 , m_animationFinished(false) | 67 , m_animationFinished(false) |
67 , m_allDataReceived(false) | 68 , m_allDataReceived(false) |
68 , m_haveSize(false) | 69 , m_haveSize(false) |
69 , m_sizeAvailable(false) | 70 , m_sizeAvailable(false) |
70 , m_hasUniformFrameSize(true) | 71 , m_hasUniformFrameSize(true) |
71 , m_haveFrameCount(false) | 72 , m_haveFrameCount(false) |
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) |
80 , m_cachedFrame(adoptRef(SkImage::NewFromBitmap(bitmap))) | |
81 , m_cachedFrameIndex(0) | |
79 , m_repetitionCount(cAnimationNone) | 82 , m_repetitionCount(cAnimationNone) |
80 , m_repetitionCountStatus(Unknown) | 83 , m_repetitionCountStatus(Unknown) |
81 , m_repetitionsComplete(0) | 84 , m_repetitionsComplete(0) |
82 , m_frameCount(1) | 85 , m_frameCount(1) |
83 , m_animationPolicy(ImageAnimationPolicyAllowed) | 86 , m_animationPolicy(ImageAnimationPolicyAllowed) |
84 , m_animationFinished(true) | 87 , m_animationFinished(true) |
85 , m_allDataReceived(true) | 88 , m_allDataReceived(true) |
86 , m_haveSize(true) | 89 , m_haveSize(true) |
87 , m_sizeAvailable(true) | 90 , m_sizeAvailable(true) |
88 , m_haveFrameCount(true) | 91 , m_haveFrameCount(true) |
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_cachedFrame.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::decodeAndCacheFrame(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); |
145 m_cachedFrame = image; | |
146 m_cachedFrameIndex = 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
219 // and the frames aren't even guaranteed to appear in the file in the same | 206 // and the frames aren't even guaranteed to appear in the file in the same |
220 // order as in the directory, so an arbitrary number of the frames might be | 207 // order as in the directory, so an arbitrary number of the frames might be |
221 // incomplete (if we ask for frames for which we've not yet reached the | 208 // incomplete (if we ask for frames for which we've not yet reached the |
222 // start of the frame data), and any or none of them might be the particular | 209 // start of the frame data), and any or none of them might be the particular |
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); |
218 if (i == m_cachedFrameIndex) | |
219 m_cachedFrame.clear(); | |
scroggo_chromium
2016/05/04 21:15:54
Should we set m_cachedFrameIndex to an invalid val
aleksandar.stojiljkovic
2016/05/04 21:28:07
No need, once a non null value is assigned to it a
| |
220 } | |
231 } | 221 } |
232 | 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(); |
(...skipping 43 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 if (index == m_cachedFrameIndex && m_cachedFrame) |
332 return m_cachedFrame; | |
Peter Kasting
2016/05/07 01:58:29
Does this implicitly ref m_cachedFrame and then pa
aleksandar.stojiljkovic
2016/05/07 19:50:53
Yes, see PasRefPtr.h.
template <typename U> PassR
| |
333 | |
334 return decodeAndCacheFrame(index); | |
353 } | 335 } |
354 | 336 |
355 bool BitmapImage::frameIsCompleteAtIndex(size_t index) | 337 bool BitmapImage::frameIsCompleteAtIndex(size_t index) |
356 { | 338 { |
357 if (index < m_frames.size() && m_frames[index].m_haveMetadata && m_frames[in dex].m_isComplete) | 339 if (index < m_frames.size() && m_frames[index].m_haveMetadata && m_frames[in dex].m_isComplete) |
358 return true; | 340 return true; |
359 | 341 |
360 return m_source.frameIsCompleteAtIndex(index); | 342 return m_source.frameIsCompleteAtIndex(index); |
361 } | 343 } |
362 | 344 |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
558 m_frameTimer.clear(); | 540 m_frameTimer.clear(); |
559 } | 541 } |
560 | 542 |
561 void BitmapImage::resetAnimation() | 543 void BitmapImage::resetAnimation() |
562 { | 544 { |
563 stopAnimation(); | 545 stopAnimation(); |
564 m_currentFrame = 0; | 546 m_currentFrame = 0; |
565 m_repetitionsComplete = 0; | 547 m_repetitionsComplete = 0; |
566 m_desiredFrameStartTime = 0; | 548 m_desiredFrameStartTime = 0; |
567 m_animationFinished = false; | 549 m_animationFinished = false; |
568 | 550 m_cachedFrame.clear(); |
569 // For extremely large animations, when the animation is reset, we just thro w everything away. | |
570 destroyDecodedDataIfNecessary(); | |
571 } | 551 } |
572 | 552 |
573 bool BitmapImage::maybeAnimated() | 553 bool BitmapImage::maybeAnimated() |
574 { | 554 { |
575 if (m_animationFinished) | 555 if (m_animationFinished) |
576 return false; | 556 return false; |
577 if (frameCount() > 1) | 557 if (frameCount() > 1) |
578 return true; | 558 return true; |
579 | 559 |
580 return m_source.repetitionCount() != cAnimationNone; | 560 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) . | 598 // because it is 0 (see comments on its declaration in ImageAnimation.h) . |
619 if ((repetitionCount(true) != cAnimationLoopInfinite && m_repetitionsCom plete > m_repetitionCount) | 599 if ((repetitionCount(true) != cAnimationLoopInfinite && m_repetitionsCom plete > m_repetitionCount) |
620 || (m_animationPolicy == ImageAnimationPolicyAnimateOnce && m_repeti tionsComplete > 0)) { | 600 || (m_animationPolicy == ImageAnimationPolicyAnimateOnce && m_repeti tionsComplete > 0)) { |
621 m_animationFinished = true; | 601 m_animationFinished = true; |
622 m_desiredFrameStartTime = 0; | 602 m_desiredFrameStartTime = 0; |
623 --m_currentFrame; | 603 --m_currentFrame; |
624 advancedAnimation = false; | 604 advancedAnimation = false; |
625 } else | 605 } else |
626 m_currentFrame = 0; | 606 m_currentFrame = 0; |
627 } | 607 } |
628 destroyDecodedDataIfNecessary(); | |
629 | 608 |
630 // We need to draw this frame if we advanced to it while not skipping, or if | 609 // 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. | 610 // while trying to skip frames we hit the last frame and thus had to stop. |
632 if (skippingFrames != advancedAnimation) | 611 if (skippingFrames != advancedAnimation) |
633 getImageObserver()->animationAdvanced(this); | 612 getImageObserver()->animationAdvanced(this); |
613 | |
634 return advancedAnimation; | 614 return advancedAnimation; |
635 } | 615 } |
636 | 616 |
637 } // namespace blink | 617 } // namespace blink |
OLD | NEW |