Add a WebCore logging channel for images
[WebKit.git] / Source / WebCore / platform / graphics / BitmapImage.cpp
1 /*
2  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
3  * Copyright (C) 2004, 2005, 2006, 2008, 2015 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "BitmapImage.h"
29
30 #include "FloatRect.h"
31 #include "GraphicsContext.h"
32 #include "ImageBuffer.h"
33 #include "ImageObserver.h"
34 #include "IntRect.h"
35 #include "Logging.h"
36 #include "MIMETypeRegistry.h"
37 #include "TextStream.h"
38 #include "Timer.h"
39 #include <wtf/CurrentTime.h>
40 #include <wtf/Vector.h>
41 #include <wtf/text/WTFString.h>
42
43 #if PLATFORM(IOS)
44 #include <limits>
45 #endif
46
47 namespace WebCore {
48
49 BitmapImage::BitmapImage(ImageObserver* observer)
50     : Image(observer)
51     , m_isSolidColor(false)
52     , m_checkedForSolidColor(false)
53     , m_animationFinished(false)
54     , m_allDataReceived(false)
55     , m_haveSize(false)
56     , m_sizeAvailable(false)
57     , m_haveFrameCount(false)
58     , m_animationFinishedWhenCatchingUp(false)
59 {
60 }
61
62 BitmapImage::BitmapImage(NativeImagePtr&& image, ImageObserver* observer)
63     : Image(observer)
64     , m_source(image)
65     , m_frameCount(1)
66     , m_isSolidColor(false)
67     , m_checkedForSolidColor(false)
68     , m_animationFinished(true)
69     , m_allDataReceived(true)
70     , m_haveSize(true)
71     , m_sizeAvailable(true)
72     , m_haveFrameCount(true)
73     , m_animationFinishedWhenCatchingUp(false)
74 {
75     // Since we don't have a decoder, we can't figure out the image orientation.
76     // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0.
77     m_sizeRespectingOrientation = m_size = NativeImage::size(image);
78     m_decodedSize = m_size.area() * 4;
79     
80     m_frames.grow(1);
81     m_frames[0].m_hasAlpha = NativeImage::hasAlpha(image);
82     m_frames[0].m_haveMetadata = true;
83     m_frames[0].m_image = WTFMove(image);
84     
85     checkForSolidColor();
86 }
87
88 BitmapImage::~BitmapImage()
89 {
90     invalidatePlatformData();
91     stopAnimation();
92 }
93
94 void BitmapImage::clearTimer()
95 {
96     m_frameTimer = nullptr;
97 }
98
99 void BitmapImage::startTimer(double delay)
100 {
101     ASSERT(!m_frameTimer);
102     m_frameTimer = std::make_unique<Timer>(*this, &BitmapImage::advanceAnimation);
103     m_frameTimer->startOneShot(delay);
104 }
105
106 bool BitmapImage::haveFrameImageAtIndex(size_t index)
107 {
108     if (index >= frameCount())
109         return false;
110
111     if (index >= m_frames.size())
112         return false;
113
114     return m_frames[index].m_image;
115 }
116
117 bool BitmapImage::hasSingleSecurityOrigin() const
118 {
119     return true;
120 }
121
122 void BitmapImage::destroyDecodedData(bool destroyAll)
123 {
124     unsigned frameBytesCleared = 0;
125     const size_t clearBeforeFrame = destroyAll ? m_frames.size() : m_currentFrame;
126
127     // Because we can advance frames without always needing to decode the actual
128     // bitmap data, |m_currentFrame| may be larger than m_frames.size();
129     // make sure not to walk off the end of the container in this case.
130     for (size_t i = 0; i <  std::min(clearBeforeFrame, m_frames.size()); ++i) {
131         // The underlying frame isn't actually changing (we're just trying to
132         // save the memory for the framebuffer data), so we don't need to clear
133         // the metadata.
134         unsigned frameBytes = m_frames[i].m_frameBytes;
135         if (m_frames[i].clear(false))
136             frameBytesCleared += frameBytes;
137     }
138
139     m_source.clear(destroyAll, clearBeforeFrame, data(), m_allDataReceived);
140     destroyMetadataAndNotify(frameBytesCleared, ClearedSource::Yes);
141 }
142
143 void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll)
144 {
145     // Animated images over a certain size are considered large enough that we'll only hang on
146     // to one frame at a time.
147 #if PLATFORM(IOS)
148     const unsigned largeAnimationCutoff = 2097152;
149 #else
150     const unsigned largeAnimationCutoff = 5242880;
151 #endif
152
153     // If we have decoded frames but there is no encoded data, we shouldn't destroy
154     // the decoded image since we won't be able to reconstruct it later.
155     if (!data() && m_frames.size())
156         return;
157
158     unsigned allFrameBytes = 0;
159     for (size_t i = 0; i < m_frames.size(); ++i)
160         allFrameBytes += m_frames[i].m_frameBytes;
161
162     if (allFrameBytes > largeAnimationCutoff) {
163         LOG(Images, "BitmapImage %p destroyDecodedDataIfNecessary destryingData: allFrameBytes=%u cutoff=%u", this, allFrameBytes, largeAnimationCutoff);
164         destroyDecodedData(destroyAll);
165     }
166 }
167
168 void BitmapImage::destroyMetadataAndNotify(unsigned frameBytesCleared, ClearedSource clearedSource)
169 {
170     m_isSolidColor = false;
171     m_checkedForSolidColor = false;
172     invalidatePlatformData();
173
174     ASSERT(m_decodedSize >= frameBytesCleared);
175     m_decodedSize -= frameBytesCleared;
176
177     // Clearing the ImageSource destroys the extra decoded data used for determining image properties.
178     if (clearedSource == ClearedSource::Yes) {
179         frameBytesCleared += m_decodedPropertiesSize;
180         m_decodedPropertiesSize = 0;
181     }
182
183     if (frameBytesCleared && imageObserver())
184         imageObserver()->decodedSizeChanged(this, -safeCast<int>(frameBytesCleared));
185 }
186
187 void BitmapImage::cacheFrame(size_t index, SubsamplingLevel subsamplingLevel, ImageFrameCaching frameCaching)
188 {
189     size_t numFrames = frameCount();
190     ASSERT(m_decodedSize == 0 || numFrames > 1);
191     
192     if (m_frames.size() < numFrames)
193         m_frames.grow(numFrames);
194
195     if (frameCaching == CacheMetadataAndFrame) {
196         m_frames[index].m_image = m_source.createFrameImageAtIndex(index, subsamplingLevel);
197         m_frames[index].m_subsamplingLevel = subsamplingLevel;
198         if (numFrames == 1 && m_frames[index].m_image)
199             checkForSolidColor();
200     }
201
202     m_frames[index].m_orientation = m_source.orientationAtIndex(index);
203     m_frames[index].m_haveMetadata = true;
204     m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index);
205
206     if (repetitionCount(false) != cAnimationNone)
207         m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
208
209     m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
210     m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index, subsamplingLevel);
211
212     LOG(Images, "BitmapImage %p cacheFrame %lu (%s%u bytes, complete %d)", this, index, frameCaching == CacheMetadataOnly ? "metadata only, " : "", m_frames[index].m_frameBytes, m_frames[index].m_isComplete);
213
214     if (m_frames[index].m_image) {
215         int deltaBytes = safeCast<int>(m_frames[index].m_frameBytes);
216         m_decodedSize += deltaBytes;
217         // The fully-decoded frame will subsume the partially decoded data used
218         // to determine image properties.
219         deltaBytes -= m_decodedPropertiesSize;
220         m_decodedPropertiesSize = 0;
221         if (imageObserver())
222             imageObserver()->decodedSizeChanged(this, deltaBytes);
223     }
224 }
225
226 void BitmapImage::didDecodeProperties() const
227 {
228     if (m_decodedSize)
229         return;
230
231     size_t updatedSize = m_source.bytesDecodedToDetermineProperties();
232     if (m_decodedPropertiesSize == updatedSize)
233         return;
234
235     int deltaBytes = updatedSize - m_decodedPropertiesSize;
236 #if !ASSERT_DISABLED
237     bool overflow = updatedSize > m_decodedPropertiesSize && deltaBytes < 0;
238     bool underflow = updatedSize < m_decodedPropertiesSize && deltaBytes > 0;
239     ASSERT(!overflow && !underflow);
240 #endif
241     m_decodedPropertiesSize = updatedSize;
242     if (imageObserver())
243         imageObserver()->decodedSizeChanged(this, deltaBytes);
244 }
245
246 void BitmapImage::updateSize() const
247 {
248     if (!m_sizeAvailable || m_haveSize)
249         return;
250
251     m_size = m_source.size();
252     m_sizeRespectingOrientation = m_source.sizeRespectingOrientation();
253
254     m_haveSize = true;
255     didDecodeProperties();
256 }
257
258 FloatSize BitmapImage::size() const
259 {
260     updateSize();
261     return m_size;
262 }
263
264 IntSize BitmapImage::sizeRespectingOrientation() const
265 {
266     updateSize();
267     return m_sizeRespectingOrientation;
268 }
269
270 Optional<IntPoint> BitmapImage::hotSpot() const
271 {
272     auto result = m_source.hotSpot();
273     didDecodeProperties();
274     return result;
275 }
276
277 bool BitmapImage::dataChanged(bool allDataReceived)
278 {
279     // Because we're modifying the current frame, clear its (now possibly
280     // inaccurate) metadata as well.
281 #if !PLATFORM(IOS)
282     // Clear all partially-decoded frames. For most image formats, there is only
283     // one frame, but at least GIF and ICO can have more. With GIFs, the frames
284     // come in order and we ask to decode them in order, waiting to request a
285     // subsequent frame until the prior one is complete. Given that we clear
286     // incomplete frames here, this means there is at most one incomplete frame
287     // (even if we use destroyDecodedData() -- since it doesn't reset the
288     // metadata), and it is after all the complete frames.
289     //
290     // With ICOs, on the other hand, we may ask for arbitrary frames at
291     // different times (e.g. because we're displaying a higher-resolution image
292     // in the content area and using a lower-resolution one for the favicon),
293     // and the frames aren't even guaranteed to appear in the file in the same
294     // order as in the directory, so an arbitrary number of the frames might be
295     // incomplete (if we ask for frames for which we've not yet reached the
296     // start of the frame data), and any or none of them might be the particular
297     // frame affected by appending new data here. Thus we have to clear all the
298     // incomplete frames to be safe.
299     unsigned frameBytesCleared = 0;
300     for (size_t i = 0; i < m_frames.size(); ++i) {
301         // NOTE: Don't call frameIsCompleteAtIndex() here, that will try to
302         // decode any uncached (i.e. never-decoded or
303         // cleared-on-a-previous-pass) frames!
304         unsigned frameBytes = m_frames[i].m_frameBytes;
305         if (m_frames[i].m_haveMetadata && !m_frames[i].m_isComplete)
306             frameBytesCleared += (m_frames[i].clear(true) ? frameBytes : 0);
307     }
308     destroyMetadataAndNotify(frameBytesCleared, ClearedSource::No);
309 #else
310     // FIXME: why is this different for iOS?
311     int deltaBytes = 0;
312     if (!m_frames.isEmpty()) {
313         int bytes = m_frames[m_frames.size() - 1].m_frameBytes;
314         if (m_frames[m_frames.size() - 1].clear(true)) {
315             deltaBytes += bytes;
316             deltaBytes += m_decodedPropertiesSize;
317             m_decodedPropertiesSize = 0;
318         }
319     }
320     destroyMetadataAndNotify(deltaBytes, ClearedSource::No);
321 #endif
322     
323     // Feed all the data we've seen so far to the image decoder.
324     m_allDataReceived = allDataReceived;
325 #if PLATFORM(IOS)
326     // FIXME: We should expose a setting to enable/disable progressive loading and make this
327     // code conditional on it. Then we can remove the PLATFORM(IOS)-guard.
328     static const double chunkLoadIntervals[] = {0, 1, 3, 6, 15};
329     double interval = chunkLoadIntervals[std::min(m_progressiveLoadChunkCount, static_cast<uint16_t>(4))];
330
331     bool needsUpdate = false;
332     if (currentTime() - m_progressiveLoadChunkTime > interval) { // The first time through, the chunk time will be 0 and the image will get an update.
333         needsUpdate = true;
334         m_progressiveLoadChunkTime = currentTime();
335         ASSERT(m_progressiveLoadChunkCount <= std::numeric_limits<uint16_t>::max());
336         ++m_progressiveLoadChunkCount;
337     }
338     if (needsUpdate || allDataReceived)
339         m_source.setData(data(), allDataReceived);
340 #else
341     m_source.setData(data(), allDataReceived);
342 #endif
343
344     m_haveFrameCount = false;
345     m_source.setNeedsUpdateMetadata();
346     return isSizeAvailable();
347 }
348
349 String BitmapImage::filenameExtension() const
350 {
351     return m_source.filenameExtension();
352 }
353
354 size_t BitmapImage::frameCount()
355 {
356     if (!m_haveFrameCount) {
357         m_frameCount = m_source.frameCount();
358         // If decoder is not initialized yet, m_source.frameCount() returns 0.
359         if (m_frameCount) {
360             didDecodeProperties();
361             m_haveFrameCount = true;
362         }
363     }
364     return m_frameCount;
365 }
366
367 bool BitmapImage::isSizeAvailable()
368 {
369     if (m_sizeAvailable)
370         return true;
371
372     m_sizeAvailable = m_source.isSizeAvailable();
373     didDecodeProperties();
374
375     return m_sizeAvailable;
376 }
377
378 bool BitmapImage::ensureFrameIsCached(size_t index, ImageFrameCaching frameCaching)
379 {
380     if (index >= frameCount())
381         return false;
382
383     if (index >= m_frames.size()
384         || (frameCaching == CacheMetadataAndFrame && !m_frames[index].m_image)
385         || (frameCaching == CacheMetadataOnly && !m_frames[index].m_haveMetadata))
386         cacheFrame(index, 0, frameCaching);
387
388     return true;
389 }
390
391 NativeImagePtr BitmapImage::frameImageAtIndex(size_t index, float presentationScaleHint)
392 {
393     if (index >= frameCount())
394         return nullptr;
395
396     SubsamplingLevel subsamplingLevel = m_source.subsamplingLevelForScale(presentationScaleHint);
397
398     // We may have cached a frame with a higher subsampling level, in which case we need to
399     // re-decode with a lower level.
400     if (index < m_frames.size() && m_frames[index].m_image && subsamplingLevel < m_frames[index].m_subsamplingLevel) {
401         // If the image is already cached, but at too small a size, re-decode a larger version.
402         int sizeChange = -m_frames[index].m_frameBytes;
403         m_frames[index].clear(true);
404         invalidatePlatformData();
405         m_decodedSize += sizeChange;
406         if (imageObserver())
407             imageObserver()->decodedSizeChanged(this, sizeChange);
408     }
409
410     // If we haven't fetched a frame yet, do so.
411     if (index >= m_frames.size() || !m_frames[index].m_image)
412         cacheFrame(index, subsamplingLevel, CacheMetadataAndFrame);
413
414     return m_frames[index].m_image;
415 }
416
417 bool BitmapImage::frameIsCompleteAtIndex(size_t index)
418 {
419     if (!ensureFrameIsCached(index, CacheMetadataOnly))
420         return false;
421
422     return m_frames[index].m_isComplete;
423 }
424
425 float BitmapImage::frameDurationAtIndex(size_t index)
426 {
427     if (!ensureFrameIsCached(index, CacheMetadataOnly))
428         return 0;
429
430     return m_frames[index].m_duration;
431 }
432
433 NativeImagePtr BitmapImage::nativeImageForCurrentFrame()
434 {
435     return frameImageAtIndex(currentFrame());
436 }
437
438 bool BitmapImage::frameHasAlphaAtIndex(size_t index)
439 {
440     if (!ensureFrameIsCached(index, CacheMetadataOnly))
441         return true;
442
443     if (m_frames[index].m_haveMetadata)
444         return m_frames[index].m_hasAlpha;
445
446     return m_source.frameHasAlphaAtIndex(index);
447 }
448
449 bool BitmapImage::currentFrameKnownToBeOpaque()
450 {
451     return !frameHasAlphaAtIndex(currentFrame());
452 }
453
454 ImageOrientation BitmapImage::frameOrientationAtIndex(size_t index)
455 {
456     if (!ensureFrameIsCached(index, CacheMetadataOnly))
457         return ImageOrientation();
458
459     if (m_frames[index].m_haveMetadata)
460         return m_frames[index].m_orientation;
461
462     return m_source.orientationAtIndex(index);
463 }
464
465 #if !ASSERT_DISABLED
466 bool BitmapImage::notSolidColor()
467 {
468     return size().width() != 1 || size().height() != 1 || frameCount() > 1;
469 }
470 #endif
471
472 int BitmapImage::repetitionCount(bool imageKnownToBeComplete)
473 {
474     if ((m_repetitionCountStatus == Unknown) || ((m_repetitionCountStatus == Uncertain) && imageKnownToBeComplete)) {
475         // Snag the repetition count. If |imageKnownToBeComplete| is false, the
476         // repetition count may not be accurate yet for GIFs; in this case the
477         // decoder will default to cAnimationLoopOnce, and we'll try and read
478         // the count again once the whole image is decoded.
479         m_repetitionCount = m_source.repetitionCount();
480         didDecodeProperties();
481         m_repetitionCountStatus = (imageKnownToBeComplete || m_repetitionCount == cAnimationNone) ? Certain : Uncertain;
482     }
483     return m_repetitionCount;
484 }
485
486 bool BitmapImage::shouldAnimate()
487 {
488     return (repetitionCount(false) != cAnimationNone && !m_animationFinished && imageObserver());
489 }
490
491 void BitmapImage::startAnimation(CatchUpAnimation catchUpIfNecessary)
492 {
493     if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
494         return;
495
496     // If we aren't already animating, set now as the animation start time.
497     const double time = monotonicallyIncreasingTime();
498     if (!m_desiredFrameStartTime)
499         m_desiredFrameStartTime = time;
500
501     // Don't advance the animation to an incomplete frame.
502     size_t nextFrame = (m_currentFrame + 1) % frameCount();
503     if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame))
504         return;
505
506     // Don't advance past the last frame if we haven't decoded the whole image
507     // yet and our repetition count is potentially unset. The repetition count
508     // in a GIF can potentially come after all the rest of the image data, so
509     // wait on it.
510     if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1))
511         return;
512
513     // Determine time for next frame to start. By ignoring paint and timer lag
514     // in this calculation, we make the animation appear to run at its desired
515     // rate regardless of how fast it's being repainted.
516     const double currentDuration = frameDurationAtIndex(m_currentFrame);
517     m_desiredFrameStartTime += currentDuration;
518
519 #if !PLATFORM(IOS)
520     // When an animated image is more than five minutes out of date, the
521     // user probably doesn't care about resyncing and we could burn a lot of
522     // time looping through frames below. Just reset the timings.
523     const double cAnimationResyncCutoff = 5 * 60;
524     if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff)
525         m_desiredFrameStartTime = time + currentDuration;
526 #else
527     // Maintaining frame-to-frame delays is more important than
528     // maintaining absolute animation timing, so reset the timings each frame.
529     m_desiredFrameStartTime = time + currentDuration;
530 #endif
531
532     // The image may load more slowly than it's supposed to animate, so that by
533     // the time we reach the end of the first repetition, we're well behind.
534     // Clamp the desired frame start time in this case, so that we don't skip
535     // frames (or whole iterations) trying to "catch up". This is a tradeoff:
536     // It guarantees users see the whole animation the second time through and
537     // don't miss any repetitions, and is closer to what other browsers do; on
538     // the other hand, it makes animations "less accurate" for pages that try to
539     // sync an image and some other resource (e.g. audio), especially if users
540     // switch tabs (and thus stop drawing the animation, which will pause it)
541     // during that initial loop, then switch back later.
542     if (nextFrame == 0 && m_repetitionsComplete == 0 && m_desiredFrameStartTime < time)
543         m_desiredFrameStartTime = time;
544
545     if (catchUpIfNecessary == DoNotCatchUp || time < m_desiredFrameStartTime) {
546         // Haven't yet reached time for next frame to start; delay until then.
547         startTimer(std::max<double>(m_desiredFrameStartTime - time, 0));
548         return;
549     }
550
551     ASSERT(!m_frameTimer);
552
553     // We've already reached or passed the time for the next frame to start.
554     // See if we've also passed the time for frames after that to start, in
555     // case we need to skip some frames entirely. Remember not to advance
556     // to an incomplete frame.
557
558 #if !LOG_DISABLED
559     size_t startCatchupFrameIndex = nextFrame;
560 #endif
561     
562     for (size_t frameAfterNext = (nextFrame + 1) % frameCount(); frameIsCompleteAtIndex(frameAfterNext); frameAfterNext = (nextFrame + 1) % frameCount()) {
563         // Should we skip the next frame?
564         double frameAfterNextStartTime = m_desiredFrameStartTime + frameDurationAtIndex(nextFrame);
565         if (time < frameAfterNextStartTime)
566             break;
567
568         // Yes; skip over it without notifying our observers. If we hit the end while catching up,
569         // tell the observer asynchronously.
570         if (!internalAdvanceAnimation(SkippingFramesToCatchUp)) {
571             m_animationFinishedWhenCatchingUp = true;
572             startTimer(0);
573             LOG(Images, "BitmapImage %p startAnimation catching up from frame %lu, ended", this, startCatchupFrameIndex);
574             return;
575         }
576         m_desiredFrameStartTime = frameAfterNextStartTime;
577         nextFrame = frameAfterNext;
578     }
579
580     LOG(Images, "BitmapImage %p startAnimation catching up jumped from from frame %lu to %d", this, startCatchupFrameIndex, (int)nextFrame - 1);
581
582     // Draw the next frame as soon as possible. Note that m_desiredFrameStartTime
583     // may be in the past, meaning the next time through this function we'll
584     // kick off the next advancement sooner than this frame's duration would suggest.
585     startTimer(0);
586 }
587
588 void BitmapImage::stopAnimation()
589 {
590     // This timer is used to animate all occurrences of this image. Don't invalidate
591     // the timer unless all renderers have stopped drawing.
592     clearTimer();
593 }
594
595 void BitmapImage::resetAnimation()
596 {
597     stopAnimation();
598     m_currentFrame = 0;
599     m_repetitionsComplete = 0;
600     m_desiredFrameStartTime = 0;
601     m_animationFinished = false;
602     
603     // For extremely large animations, when the animation is reset, we just throw everything away.
604     destroyDecodedDataIfNecessary(true);
605 }
606
607 void BitmapImage::drawPattern(GraphicsContext& ctxt, const FloatRect& tileRect, const AffineTransform& transform,
608     const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode)
609 {
610     if (tileRect.isEmpty())
611         return;
612
613     if (!ctxt.drawLuminanceMask()) {
614         Image::drawPattern(ctxt, tileRect, transform, phase, spacing, op, destRect, blendMode);
615         return;
616     }
617     if (!m_cachedImage) {
618         std::unique_ptr<ImageBuffer> buffer = ctxt.createCompatibleBuffer(expandedIntSize(tileRect.size()));
619         if (!buffer)
620             return;
621
622         ImageObserver* observer = imageObserver();
623         ASSERT(observer);
624
625         // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout.
626         setImageObserver(nullptr);
627
628         draw(buffer->context(), tileRect, tileRect, op, blendMode, ImageOrientationDescription());
629
630         setImageObserver(observer);
631         buffer->convertToLuminanceMask();
632
633         m_cachedImage = buffer->copyImage(DontCopyBackingStore, Unscaled);
634         if (!m_cachedImage)
635             return;
636     }
637
638     ctxt.setDrawLuminanceMask(false);
639     m_cachedImage->drawPattern(ctxt, tileRect, transform, phase, spacing, op, destRect, blendMode);
640 }
641
642
643 void BitmapImage::advanceAnimation()
644 {
645     internalAdvanceAnimation();
646     // At this point the image region has been marked dirty, and if it's
647     // onscreen, we'll soon make a call to draw(), which will call
648     // startAnimation() again to keep the animation moving.
649 }
650
651 bool BitmapImage::internalAdvanceAnimation(AnimationAdvancement advancement)
652 {
653     clearTimer();
654
655     if (m_animationFinishedWhenCatchingUp) {
656         imageObserver()->animationAdvanced(this);
657         m_animationFinishedWhenCatchingUp = false;
658         return false;
659     }
660     
661     ++m_currentFrame;
662     bool advancedAnimation = true;
663     bool destroyAll = false;
664     if (m_currentFrame >= frameCount()) {
665         ++m_repetitionsComplete;
666
667         // Get the repetition count again. If we weren't able to get a
668         // repetition count before, we should have decoded the whole image by
669         // now, so it should now be available.
670         // Note that we don't need to special-case cAnimationLoopOnce here
671         // because it is 0 (see comments on its declaration in ImageSource.h).
672         if (repetitionCount(true) != cAnimationLoopInfinite && m_repetitionsComplete > m_repetitionCount) {
673             m_animationFinished = true;
674             m_desiredFrameStartTime = 0;
675             --m_currentFrame;
676             advancedAnimation = false;
677         } else {
678             m_currentFrame = 0;
679             destroyAll = true;
680         }
681     }
682     destroyDecodedDataIfNecessary(destroyAll);
683
684     // We need to draw this frame if we advanced to it while not skipping, or if
685     // while trying to skip frames we hit the last frame and thus had to stop.
686     if (advancement == Normal && advancedAnimation)
687         imageObserver()->animationAdvanced(this);
688
689     return advancedAnimation;
690 }
691
692 bool BitmapImage::mayFillWithSolidColor()
693 {
694     if (!m_checkedForSolidColor && frameCount() > 0) {
695         checkForSolidColor();
696         ASSERT(m_checkedForSolidColor);
697     }
698     return m_isSolidColor && !m_currentFrame;
699 }
700
701 Color BitmapImage::solidColor() const
702 {
703     return m_solidColor;
704 }
705     
706 bool BitmapImage::canAnimate()
707 {
708     return shouldAnimate() && frameCount() > 1;
709 }
710
711 void BitmapImage::dump(TextStream& ts) const
712 {
713     Image::dump(ts);
714
715     ts.dumpProperty("type", m_source.filenameExtension());
716
717     if (isAnimated()) {
718         ts.dumpProperty("frame-count", m_frameCount);
719         ts.dumpProperty("repetitions", m_repetitionCount);
720         ts.dumpProperty("current-frame", m_currentFrame);
721     }
722     
723     if (m_isSolidColor)
724         ts.dumpProperty("solid-color", m_isSolidColor);
725     
726     m_source.dump(ts);
727 }
728
729 }