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_haveFrameCount(false) | 71 , m_haveFrameCount(false) |
71 { | 72 { |
72 } | 73 } |
73 | 74 |
74 BitmapImage::BitmapImage(const SkBitmap& bitmap, ImageObserver* observer) | 75 BitmapImage::BitmapImage(const SkBitmap& bitmap, ImageObserver* observer) |
75 : Image(observer) | 76 : Image(observer) |
76 , m_size(bitmap.width(), bitmap.height()) | 77 , m_size(bitmap.width(), bitmap.height()) |
77 , m_currentFrame(0) | 78 , m_currentFrame(0) |
| 79 , m_cachedFrame(adoptRef(SkImage::NewFromBitmap(bitmap))) |
| 80 , m_cachedFrameIndex(0) |
78 , m_repetitionCount(cAnimationNone) | 81 , m_repetitionCount(cAnimationNone) |
79 , m_repetitionCountStatus(Unknown) | 82 , m_repetitionCountStatus(Unknown) |
80 , m_repetitionsComplete(0) | 83 , m_repetitionsComplete(0) |
81 , m_frameCount(1) | 84 , m_frameCount(1) |
82 , m_animationPolicy(ImageAnimationPolicyAllowed) | 85 , m_animationPolicy(ImageAnimationPolicyAllowed) |
83 , m_animationFinished(true) | 86 , m_animationFinished(true) |
84 , m_allDataReceived(true) | 87 , m_allDataReceived(true) |
85 , m_haveSize(true) | 88 , m_haveSize(true) |
86 , m_sizeAvailable(true) | 89 , m_sizeAvailable(true) |
87 , m_haveFrameCount(true) | 90 , m_haveFrameCount(true) |
88 { | 91 { |
89 // Since we don't have a decoder, we can't figure out the image orientation. | 92 // Since we don't have a decoder, we can't figure out the image orientation. |
90 // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0. | 93 // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0. |
91 m_sizeRespectingOrientation = m_size; | 94 m_sizeRespectingOrientation = m_size; |
92 | 95 |
93 m_frames.grow(1); | 96 m_frames.grow(1); |
94 m_frames[0].m_hasAlpha = !bitmap.isOpaque(); | 97 m_frames[0].m_hasAlpha = !bitmap.isOpaque(); |
95 m_frames[0].m_frame = adoptRef(SkImage::NewFromBitmap(bitmap)); | |
96 m_frames[0].m_haveMetadata = true; | 98 m_frames[0].m_haveMetadata = true; |
97 } | 99 } |
98 | 100 |
99 BitmapImage::~BitmapImage() | 101 BitmapImage::~BitmapImage() |
100 { | 102 { |
101 stopAnimation(); | 103 stopAnimation(); |
102 } | 104 } |
103 | 105 |
104 bool BitmapImage::currentFrameHasSingleSecurityOrigin() const | 106 bool BitmapImage::currentFrameHasSingleSecurityOrigin() const |
105 { | 107 { |
106 return true; | 108 return true; |
107 } | 109 } |
108 | 110 |
109 void BitmapImage::destroyDecodedData(bool destroyAll) | 111 void BitmapImage::destroyDecodedData() |
110 { | 112 { |
111 for (size_t i = 0; i < m_frames.size(); ++i) { | 113 m_cachedFrame.clear(); |
112 // The underlying frame isn't actually changing (we're just trying to | 114 for (size_t i = 0; i < m_frames.size(); ++i) |
113 // save the memory for the framebuffer data), so we don't need to clear | 115 m_frames[i].clear(true); |
114 // the metadata. | 116 m_source.clearCacheExceptFrame(kNotFound); |
115 m_frames[i].clear(false); | |
116 } | |
117 | |
118 m_source.clearCacheExceptFrame(destroyAll ? kNotFound : m_currentFrame); | |
119 notifyMemoryChanged(); | 117 notifyMemoryChanged(); |
120 } | 118 } |
121 | 119 |
122 void BitmapImage::destroyDecodedDataIfNecessary() | |
123 { | |
124 // Animated images >5MB are considered large enough that we'll only hang on | |
125 // to one frame at a time. | |
126 static const size_t cLargeAnimationCutoff = 5242880; | |
127 size_t allFrameBytes = 0; | |
128 for (size_t i = 0; i < m_frames.size(); ++i) | |
129 allFrameBytes += m_frames[i].m_frameBytes; | |
130 | |
131 if (allFrameBytes > cLargeAnimationCutoff) { | |
132 destroyDecodedData(false); | |
133 } | |
134 } | |
135 | |
136 void BitmapImage::notifyMemoryChanged() | 120 void BitmapImage::notifyMemoryChanged() |
137 { | 121 { |
138 if (getImageObserver()) | 122 if (getImageObserver()) |
139 getImageObserver()->decodedSizeChangedTo(this, totalFrameBytes()); | 123 getImageObserver()->decodedSizeChangedTo(this, totalFrameBytes()); |
140 } | 124 } |
141 | 125 |
142 size_t BitmapImage::totalFrameBytes() | 126 size_t BitmapImage::totalFrameBytes() |
143 { | 127 { |
144 const size_t numFrames = frameCount(); | 128 const size_t numFrames = frameCount(); |
145 size_t totalBytes = 0; | 129 size_t totalBytes = 0; |
146 for (size_t i = 0; i < numFrames; ++i) | 130 for (size_t i = 0; i < numFrames; ++i) |
147 totalBytes += m_source.frameBytesAtIndex(i); | 131 totalBytes += m_source.frameBytesAtIndex(i); |
148 return totalBytes; | 132 return totalBytes; |
149 } | 133 } |
150 | 134 |
151 void BitmapImage::cacheFrame(size_t index) | 135 PassRefPtr<SkImage> BitmapImage::decodeAndCacheFrame(size_t index) |
152 { | 136 { |
153 size_t numFrames = frameCount(); | 137 size_t numFrames = frameCount(); |
154 if (m_frames.size() < numFrames) | 138 if (m_frames.size() < numFrames) |
155 m_frames.grow(numFrames); | 139 m_frames.grow(numFrames); |
156 | 140 |
157 // We are caching frame snapshots. This is OK even for partially decoded fr
ames, | 141 // We are caching frame snapshots. This is OK even for partially decoded fr
ames, |
158 // as they are cleared by dataChanged() when new data arrives. | 142 // as they are cleared by dataChanged() when new data arrives. |
159 m_frames[index].m_frame = m_source.createFrameAtIndex(index); | 143 RefPtr<SkImage> image = m_source.createFrameAtIndex(index); |
| 144 m_cachedFrame = image; |
| 145 m_cachedFrameIndex = index; |
160 | 146 |
161 m_frames[index].m_orientation = m_source.orientationAtIndex(index); | 147 m_frames[index].m_orientation = m_source.orientationAtIndex(index); |
162 m_frames[index].m_haveMetadata = true; | 148 m_frames[index].m_haveMetadata = true; |
163 m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index); | 149 m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index); |
164 if (repetitionCount(false) != cAnimationNone) | 150 if (repetitionCount(false) != cAnimationNone) |
165 m_frames[index].m_duration = m_source.frameDurationAtIndex(index); | 151 m_frames[index].m_duration = m_source.frameDurationAtIndex(index); |
166 m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index); | 152 m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index); |
167 m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index); | 153 m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index); |
168 | 154 |
169 notifyMemoryChanged(); | 155 notifyMemoryChanged(); |
| 156 return image.release(); |
170 } | 157 } |
171 | 158 |
172 void BitmapImage::updateSize() const | 159 void BitmapImage::updateSize() const |
173 { | 160 { |
174 if (!m_sizeAvailable || m_haveSize) | 161 if (!m_sizeAvailable || m_haveSize) |
175 return; | 162 return; |
176 | 163 |
177 m_size = m_source.size(); | 164 m_size = m_source.size(); |
178 m_sizeRespectingOrientation = m_source.size(RespectImageOrientation); | 165 m_sizeRespectingOrientation = m_source.size(RespectImageOrientation); |
179 m_haveSize = true; | 166 m_haveSize = true; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 // and the frames aren't even guaranteed to appear in the file in the same | 201 // and the frames aren't even guaranteed to appear in the file in the same |
215 // order as in the directory, so an arbitrary number of the frames might be | 202 // order as in the directory, so an arbitrary number of the frames might be |
216 // incomplete (if we ask for frames for which we've not yet reached the | 203 // incomplete (if we ask for frames for which we've not yet reached the |
217 // start of the frame data), and any or none of them might be the particular | 204 // start of the frame data), and any or none of them might be the particular |
218 // frame affected by appending new data here. Thus we have to clear all the | 205 // frame affected by appending new data here. Thus we have to clear all the |
219 // incomplete frames to be safe. | 206 // incomplete frames to be safe. |
220 for (size_t i = 0; i < m_frames.size(); ++i) { | 207 for (size_t i = 0; i < m_frames.size(); ++i) { |
221 // NOTE: Don't call frameIsCompleteAtIndex() here, that will try to | 208 // NOTE: Don't call frameIsCompleteAtIndex() here, that will try to |
222 // decode any uncached (i.e. never-decoded or | 209 // decode any uncached (i.e. never-decoded or |
223 // cleared-on-a-previous-pass) frames! | 210 // cleared-on-a-previous-pass) frames! |
224 if (m_frames[i].m_haveMetadata && !m_frames[i].m_isComplete) | 211 if (m_frames[i].m_haveMetadata && !m_frames[i].m_isComplete) { |
225 m_frames[i].clear(true); | 212 m_frames[i].clear(true); |
| 213 if (i == m_cachedFrameIndex) |
| 214 m_cachedFrame.clear(); |
| 215 } |
226 } | 216 } |
227 | 217 |
228 // Feed all the data we've seen so far to the image decoder. | 218 // Feed all the data we've seen so far to the image decoder. |
229 m_allDataReceived = allDataReceived; | 219 m_allDataReceived = allDataReceived; |
230 ASSERT(data()); | 220 ASSERT(data()); |
231 m_source.setData(*data(), allDataReceived); | 221 m_source.setData(*data(), allDataReceived); |
232 | 222 |
233 m_haveFrameCount = false; | 223 m_haveFrameCount = false; |
234 return isSizeAvailable(); | 224 return isSizeAvailable(); |
235 } | 225 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 if (orientation.usesWidthAsHeight()) { | 266 if (orientation.usesWidthAsHeight()) { |
277 // The destination rect will have it's width and height already reve
rsed for the orientation of | 267 // The destination rect will have it's width and height already reve
rsed for the orientation of |
278 // the image, as it was needed for page layout, so we need to revers
e it back here. | 268 // the image, as it was needed for page layout, so we need to revers
e it back here. |
279 adjustedDstRect = FloatRect(adjustedDstRect.x(), adjustedDstRect.y()
, adjustedDstRect.height(), adjustedDstRect.width()); | 269 adjustedDstRect = FloatRect(adjustedDstRect.x(), adjustedDstRect.y()
, adjustedDstRect.height(), adjustedDstRect.width()); |
280 } | 270 } |
281 } | 271 } |
282 | 272 |
283 canvas->drawImageRect(image.get(), adjustedSrcRect, adjustedDstRect, &paint, | 273 canvas->drawImageRect(image.get(), adjustedSrcRect, adjustedDstRect, &paint, |
284 WebCoreClampingModeToSkiaRectConstraint(clampMode)); | 274 WebCoreClampingModeToSkiaRectConstraint(clampMode)); |
285 | 275 |
286 if (currentFrameIsLazyDecoded()) | 276 if (image->isLazyGenerated()) |
287 PlatformInstrumentation::didDrawLazyPixelRef(image->uniqueID()); | 277 PlatformInstrumentation::didDrawLazyPixelRef(image->uniqueID()); |
288 | 278 |
289 if (ImageObserver* observer = getImageObserver()) | 279 if (ImageObserver* observer = getImageObserver()) |
290 observer->didDraw(this); | 280 observer->didDraw(this); |
291 | 281 |
292 startAnimation(); | 282 startAnimation(); |
293 } | 283 } |
294 | 284 |
295 size_t BitmapImage::frameCount() | 285 size_t BitmapImage::frameCount() |
296 { | 286 { |
(...skipping 21 matching lines...) Expand all Loading... |
318 | 308 |
319 if (m_sizeAvailable && hasVisibleImageSize(size())) { | 309 if (m_sizeAvailable && hasVisibleImageSize(size())) { |
320 BitmapImageMetrics::countDecodedImageType(m_source.filenameExtension()); | 310 BitmapImageMetrics::countDecodedImageType(m_source.filenameExtension()); |
321 if (m_source.filenameExtension() == "jpg") | 311 if (m_source.filenameExtension() == "jpg") |
322 BitmapImageMetrics::countImageOrientation(m_source.orientationAtInde
x(0).orientation()); | 312 BitmapImageMetrics::countImageOrientation(m_source.orientationAtInde
x(0).orientation()); |
323 } | 313 } |
324 | 314 |
325 return m_sizeAvailable; | 315 return m_sizeAvailable; |
326 } | 316 } |
327 | 317 |
328 bool BitmapImage::ensureFrameIsCached(size_t index) | |
329 { | |
330 if (index >= frameCount()) | |
331 return false; | |
332 | |
333 if (index >= m_frames.size() || !m_frames[index].m_frame) | |
334 cacheFrame(index); | |
335 | |
336 return true; | |
337 } | |
338 | |
339 PassRefPtr<SkImage> BitmapImage::frameAtIndex(size_t index) | 318 PassRefPtr<SkImage> BitmapImage::frameAtIndex(size_t index) |
340 { | 319 { |
341 if (!ensureFrameIsCached(index)) | 320 if (index >= frameCount()) |
342 return nullptr; | 321 return nullptr; |
343 | 322 |
344 return m_frames[index].m_frame; | 323 if (index == m_cachedFrameIndex && m_cachedFrame) |
| 324 return m_cachedFrame; |
| 325 |
| 326 return decodeAndCacheFrame(index); |
345 } | 327 } |
346 | 328 |
347 bool BitmapImage::frameIsCompleteAtIndex(size_t index) | 329 bool BitmapImage::frameIsCompleteAtIndex(size_t index) |
348 { | 330 { |
349 if (index < m_frames.size() && m_frames[index].m_haveMetadata && m_frames[in
dex].m_isComplete) | 331 if (index < m_frames.size() && m_frames[index].m_haveMetadata && m_frames[in
dex].m_isComplete) |
350 return true; | 332 return true; |
351 | 333 |
352 return m_source.frameIsCompleteAtIndex(index); | 334 return m_source.frameIsCompleteAtIndex(index); |
353 } | 335 } |
354 | 336 |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 m_frameTimer.clear(); | 532 m_frameTimer.clear(); |
551 } | 533 } |
552 | 534 |
553 void BitmapImage::resetAnimation() | 535 void BitmapImage::resetAnimation() |
554 { | 536 { |
555 stopAnimation(); | 537 stopAnimation(); |
556 m_currentFrame = 0; | 538 m_currentFrame = 0; |
557 m_repetitionsComplete = 0; | 539 m_repetitionsComplete = 0; |
558 m_desiredFrameStartTime = 0; | 540 m_desiredFrameStartTime = 0; |
559 m_animationFinished = false; | 541 m_animationFinished = false; |
560 | 542 m_cachedFrame.clear(); |
561 // For extremely large animations, when the animation is reset, we just thro
w everything away. | |
562 destroyDecodedDataIfNecessary(); | |
563 } | 543 } |
564 | 544 |
565 bool BitmapImage::maybeAnimated() | 545 bool BitmapImage::maybeAnimated() |
566 { | 546 { |
567 if (m_animationFinished) | 547 if (m_animationFinished) |
568 return false; | 548 return false; |
569 if (frameCount() > 1) | 549 if (frameCount() > 1) |
570 return true; | 550 return true; |
571 | 551 |
572 return m_source.repetitionCount() != cAnimationNone; | 552 return m_source.repetitionCount() != cAnimationNone; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
610 // because it is 0 (see comments on its declaration in ImageAnimation.h)
. | 590 // because it is 0 (see comments on its declaration in ImageAnimation.h)
. |
611 if ((repetitionCount(true) != cAnimationLoopInfinite && m_repetitionsCom
plete > m_repetitionCount) | 591 if ((repetitionCount(true) != cAnimationLoopInfinite && m_repetitionsCom
plete > m_repetitionCount) |
612 || (m_animationPolicy == ImageAnimationPolicyAnimateOnce && m_repeti
tionsComplete > 0)) { | 592 || (m_animationPolicy == ImageAnimationPolicyAnimateOnce && m_repeti
tionsComplete > 0)) { |
613 m_animationFinished = true; | 593 m_animationFinished = true; |
614 m_desiredFrameStartTime = 0; | 594 m_desiredFrameStartTime = 0; |
615 --m_currentFrame; | 595 --m_currentFrame; |
616 advancedAnimation = false; | 596 advancedAnimation = false; |
617 } else | 597 } else |
618 m_currentFrame = 0; | 598 m_currentFrame = 0; |
619 } | 599 } |
620 destroyDecodedDataIfNecessary(); | |
621 | 600 |
622 // We need to draw this frame if we advanced to it while not skipping, or if | 601 // We need to draw this frame if we advanced to it while not skipping, or if |
623 // while trying to skip frames we hit the last frame and thus had to stop. | 602 // while trying to skip frames we hit the last frame and thus had to stop. |
624 if (skippingFrames != advancedAnimation) | 603 if (skippingFrames != advancedAnimation) |
625 getImageObserver()->animationAdvanced(this); | 604 getImageObserver()->animationAdvanced(this); |
| 605 |
626 return advancedAnimation; | 606 return advancedAnimation; |
627 } | 607 } |
628 | 608 |
629 } // namespace blink | 609 } // namespace blink |
OLD | NEW |