Tiling CSS gradients is slow
[WebKit-https.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 "Settings.h"
37 #include "Timer.h"
38 #include <wtf/Vector.h>
39 #include <wtf/text/TextStream.h>
40 #include <wtf/text/WTFString.h>
41 #if USE(CG) && PLATFORM(WIN)
42 #include <WebKitSystemInterface/WebKitSystemInterface.h>
43 #endif
44
45 namespace WebCore {
46
47 BitmapImage::BitmapImage(ImageObserver* observer)
48     : Image(observer)
49     , m_source(ImageSource::create(this))
50 {
51 }
52
53 BitmapImage::BitmapImage(NativeImagePtr&& image, ImageObserver* observer)
54     : Image(observer)
55     , m_source(ImageSource::create(WTFMove(image)))
56 {
57 }
58
59 BitmapImage::~BitmapImage()
60 {
61     invalidatePlatformData();
62     clearTimer();
63     m_source->clearImage();
64     m_source->stopAsyncDecodingQueue();
65 }
66
67 void BitmapImage::updateFromSettings(const Settings& settings)
68 {
69     m_allowSubsampling = settings.imageSubsamplingEnabled();
70     m_allowAnimatedImageAsyncDecoding = settings.animatedImageAsyncDecodingEnabled();
71     m_showDebugBackground = settings.showDebugBorders();
72 }
73
74 void BitmapImage::destroyDecodedData(bool destroyAll)
75 {
76     LOG(Images, "BitmapImage::%s - %p - url: %s", __FUNCTION__, this, sourceURL().string().utf8().data());
77
78     if (!destroyAll)
79         m_source->destroyDecodedDataBeforeFrame(m_currentFrame);
80     else if (!canDestroyDecodedData())
81         m_source->destroyAllDecodedDataExcludeFrame(m_currentFrame);
82     else {
83         m_source->destroyAllDecodedData();
84         m_currentFrameDecodingStatus = DecodingStatus::Invalid;
85     }
86
87     // There's no need to throw away the decoder unless we're explicitly asked
88     // to destroy all of the frames.
89     if (!destroyAll || m_source->hasAsyncDecodingQueue())
90         m_source->clearFrameBufferCache(m_currentFrame);
91     else
92         m_source->resetData(data());
93
94     invalidatePlatformData();
95 }
96
97 void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll)
98 {
99     // If we have decoded frames but there is no encoded data, we shouldn't destroy
100     // the decoded image since we won't be able to reconstruct it later.
101     if (!data() && frameCount())
102         return;
103
104     if (m_source->decodedSize() < LargeAnimationCutoff)
105         return;
106
107     destroyDecodedData(destroyAll);
108 }
109
110 EncodedDataStatus BitmapImage::dataChanged(bool allDataReceived)
111 {
112     if (m_source->decodedSize() && !canUseAsyncDecodingForLargeImages())
113         m_source->destroyIncompleteDecodedData();
114
115     m_currentFrameDecodingStatus = DecodingStatus::Invalid;
116     return m_source->dataChanged(data(), allDataReceived);
117 }
118     
119 void BitmapImage::setCurrentFrameDecodingStatusIfNecessary(DecodingStatus decodingStatus)
120 {
121     // When new data is received, m_currentFrameDecodingStatus is set to DecodingStatus::Invalid
122     // to force decoding the frame when it's drawn. m_currentFrameDecodingStatus should not be
123     // changed in this case till draw() is called and sets its value to DecodingStatus::Decoding.
124     if (m_currentFrameDecodingStatus != DecodingStatus::Decoding)
125         return;
126     m_currentFrameDecodingStatus = decodingStatus;
127 }
128
129 NativeImagePtr BitmapImage::frameImageAtIndexCacheIfNeeded(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
130 {
131     if (!frameHasFullSizeNativeImageAtIndex(index, subsamplingLevel)) {
132         LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]", __FUNCTION__, this, sourceURL().string().utf8().data(), static_cast<int>(frameSubsamplingLevelAtIndex(index)));
133         invalidatePlatformData();
134     }
135 #if USE(DIRECT2D)
136     m_source->setTargetContext(targetContext);
137 #else
138     UNUSED_PARAM(targetContext);
139 #endif
140     return m_source->frameImageAtIndexCacheIfNeeded(index, subsamplingLevel);
141 }
142
143 NativeImagePtr BitmapImage::nativeImage(const GraphicsContext* targetContext)
144 {
145     return frameImageAtIndexCacheIfNeeded(0, SubsamplingLevel::Default, targetContext);
146 }
147
148 NativeImagePtr BitmapImage::nativeImageForCurrentFrame(const GraphicsContext* targetContext)
149 {
150     return frameImageAtIndexCacheIfNeeded(m_currentFrame, SubsamplingLevel::Default, targetContext);
151 }
152
153 #if USE(CG)
154 NativeImagePtr BitmapImage::nativeImageOfSize(const IntSize& size, const GraphicsContext* targetContext)
155 {
156     size_t count = frameCount();
157
158     for (size_t i = 0; i < count; ++i) {
159         auto image = frameImageAtIndexCacheIfNeeded(i, SubsamplingLevel::Default, targetContext);
160         if (image && nativeImageSize(image) == size)
161             return image;
162     }
163
164     // Fallback to the first frame image if we can't find the right size
165     return frameImageAtIndexCacheIfNeeded(0, SubsamplingLevel::Default, targetContext);
166 }
167
168 Vector<NativeImagePtr> BitmapImage::framesNativeImages()
169 {
170     Vector<NativeImagePtr> images;
171     size_t count = frameCount();
172
173     for (size_t i = 0; i < count; ++i) {
174         if (auto image = frameImageAtIndexCacheIfNeeded(i))
175             images.append(image);
176     }
177
178     return images;
179 }
180 #endif
181
182 #if !ASSERT_DISABLED
183 bool BitmapImage::notSolidColor()
184 {
185     return size().width() != 1 || size().height() != 1 || frameCount() > 1;
186 }
187 #endif
188
189 ImageDrawResult BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode mode, DecodingMode decodingMode, ImageOrientationDescription description)
190 {
191     if (destRect.isEmpty() || srcRect.isEmpty())
192         return ImageDrawResult::DidNothing;
193
194     FloatSize scaleFactorForDrawing = context.scaleFactorForDrawing(destRect, srcRect);
195     IntSize sizeForDrawing = expandedIntSize(size() * scaleFactorForDrawing);
196     ImageDrawResult result = ImageDrawResult::DidDraw;
197
198     m_currentSubsamplingLevel = m_allowSubsampling ? subsamplingLevelForScaleFactor(context, scaleFactorForDrawing) : SubsamplingLevel::Default;
199     LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel = %d scaleFactorForDrawing = (%.4f, %.4f)]", __FUNCTION__, this, sourceURL().string().utf8().data(), static_cast<int>(m_currentSubsamplingLevel), scaleFactorForDrawing.width(), scaleFactorForDrawing.height());
200
201     NativeImagePtr image;
202     if (decodingMode == DecodingMode::Asynchronous) {
203         ASSERT(!canAnimate());
204         ASSERT(!m_currentFrame || m_animationFinished);
205
206         bool frameIsCompatible = frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingOptions(sizeForDrawing));
207         bool frameIsBeingDecoded = frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingOptions(sizeForDrawing));
208
209         // If the current frame is incomplete, a new request for decoding this frame has to be made even if
210         // it is currently being decoded. New data may have been received since the previous request was made.
211         if ((!frameIsCompatible && !frameIsBeingDecoded) || m_currentFrameDecodingStatus == DecodingStatus::Invalid) {
212             LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().string().utf8().data());
213             m_source->requestFrameAsyncDecodingAtIndex(m_currentFrame, m_currentSubsamplingLevel, sizeForDrawing);
214             m_currentFrameDecodingStatus = DecodingStatus::Decoding;
215         }
216
217         if (m_currentFrameDecodingStatus == DecodingStatus::Decoding)
218             result = ImageDrawResult::DidRequestDecoding;
219
220         if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingOptions(DecodingMode::Asynchronous))) {
221             if (m_showDebugBackground)
222                 fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
223             return result;
224         }
225
226         image = frameImageAtIndex(m_currentFrame);
227         LOG(Images, "BitmapImage::%s - %p - url: %s [a decoded frame will be used for asynchronous drawing]", __FUNCTION__, this, sourceURL().string().utf8().data());
228     } else {
229         StartAnimationStatus status = internalStartAnimation();
230         ASSERT_IMPLIES(status == StartAnimationStatus::DecodingActive, (!m_currentFrame && !m_repetitionsComplete) || frameHasFullSizeNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel));
231
232         if (status == StartAnimationStatus::DecodingActive && m_showDebugBackground) {
233             fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
234             return result;
235         }
236         
237         // If the decodingMode changes from asynchronous to synchronous and new data is received,
238         // the current incomplete decoded frame has to be destroyed.
239         if (m_currentFrameDecodingStatus == DecodingStatus::Invalid)
240             m_source->destroyIncompleteDecodedData();
241         
242         bool frameIsCompatible = frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingOptions(sizeForDrawing));
243         bool frameIsBeingDecoded = frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingOptions(DecodingMode::Asynchronous));
244         
245         if (frameIsCompatible) {
246             image = frameImageAtIndex(m_currentFrame);
247             LOG(Images, "BitmapImage::%s - %p - url: %s [a decoded frame will reused for synchronous drawing]", __FUNCTION__, this, sourceURL().string().utf8().data());
248         } else if (frameIsBeingDecoded) {
249             // FIXME: instead of showing the yellow rectangle and returning we need to wait for this frame to finish decoding.
250             if (m_showDebugBackground) {
251                 fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
252                 LOG(Images, "BitmapImage::%s - %p - url: %s [waiting for async decoding to finish]", __FUNCTION__, this, sourceURL().string().utf8().data());
253             }
254             return ImageDrawResult::DidRequestDecoding;
255         } else {
256             image = frameImageAtIndexCacheIfNeeded(m_currentFrame, m_currentSubsamplingLevel, &context);
257             LOG(Images, "BitmapImage::%s - %p - url: %s [an image frame will be decoded synchronously]", __FUNCTION__, this, sourceURL().string().utf8().data());
258         }
259         
260         if (!image) // If it's too early we won't have an image yet.
261             return ImageDrawResult::DidNothing;
262
263         if (m_currentFrameDecodingStatus != DecodingStatus::Complete)
264             ++m_decodeCountForTesting;
265     }
266
267     ASSERT(image);
268     Color color = singlePixelSolidColor();
269     if (color.isValid()) {
270         fillWithSolidColor(context, destRect, color, op);
271         return result;
272     }
273
274     ImageOrientation orientation(description.imageOrientation());
275     if (description.respectImageOrientation() == RespectImageOrientation)
276         orientation = frameOrientationAtIndex(m_currentFrame);
277
278     drawNativeImage(image, context, destRect, srcRect, IntSize(size()), op, mode, orientation);
279     m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
280
281     if (imageObserver())
282         imageObserver()->didDraw(*this);
283
284     return result;
285 }
286
287 void BitmapImage::drawPattern(GraphicsContext& ctxt, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& transform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode)
288 {
289     if (tileRect.isEmpty())
290         return;
291
292     if (!ctxt.drawLuminanceMask()) {
293         // If new data is received, the current incomplete decoded frame has to be destroyed.
294         if (m_currentFrameDecodingStatus == DecodingStatus::Invalid)
295             m_source->destroyIncompleteDecodedData();
296         
297         Image::drawPattern(ctxt, destRect, tileRect, transform, phase, spacing, op, blendMode);
298         m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
299         return;
300     }
301
302     if (!m_cachedImage) {
303         auto buffer = ImageBuffer::createCompatibleBuffer(expandedIntSize(tileRect.size()), ColorSpaceSRGB, ctxt);
304         if (!buffer)
305             return;
306
307         ImageObserver* observer = imageObserver();
308
309         // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout.
310         setImageObserver(nullptr);
311
312         draw(buffer->context(), tileRect, tileRect, op, blendMode, DecodingMode::Synchronous, ImageOrientationDescription());
313
314         setImageObserver(observer);
315         buffer->convertToLuminanceMask();
316
317         m_cachedImage = ImageBuffer::sinkIntoImage(WTFMove(buffer), PreserveResolution::Yes);
318         if (!m_cachedImage)
319             return;
320     }
321
322     ctxt.setDrawLuminanceMask(false);
323     m_cachedImage->drawPattern(ctxt, destRect, tileRect, transform, phase, spacing, op, blendMode);
324 }
325
326 bool BitmapImage::shouldAnimate() const
327 {
328     return repetitionCount() && !m_animationFinished && imageObserver();
329 }
330
331 bool BitmapImage::canAnimate() const
332 {
333     return shouldAnimate() && frameCount() > 1;
334 }
335
336 bool BitmapImage::canUseAsyncDecodingForLargeImages() const
337 {
338     return !canAnimate() && m_source->canUseAsyncDecoding();
339 }
340
341 bool BitmapImage::shouldUseAsyncDecodingForAnimatedImages() const
342 {
343     return canAnimate() && m_allowAnimatedImageAsyncDecoding && (shouldUseAsyncDecodingForTesting() || m_source->canUseAsyncDecoding());
344 }
345
346 void BitmapImage::clearTimer()
347 {
348     m_frameTimer = nullptr;
349 }
350
351 void BitmapImage::startTimer(Seconds delay)
352 {
353     ASSERT(!m_frameTimer);
354     m_frameTimer = std::make_unique<Timer>(*this, &BitmapImage::advanceAnimation);
355     m_frameTimer->startOneShot(delay);
356 }
357
358 SubsamplingLevel BitmapImage::subsamplingLevelForScaleFactor(GraphicsContext& context, const FloatSize& scaleFactor)
359 {
360 #if USE(CG)
361     // Never use subsampled images for drawing into PDF contexts.
362     if (CGContextGetType(context.platformContext()) == kCGContextTypePDF)
363         return SubsamplingLevel::Default;
364
365     float scale = std::min(float(1), std::max(scaleFactor.width(), scaleFactor.height()));
366     if (!(scale > 0 && scale <= 1))
367         return SubsamplingLevel::Default;
368
369     int result = std::ceil(std::log2(1 / scale));
370     return static_cast<SubsamplingLevel>(std::min(result, static_cast<int>(m_source->maximumSubsamplingLevel())));
371 #else
372     UNUSED_PARAM(context);
373     UNUSED_PARAM(scaleFactor);
374     return SubsamplingLevel::Default;
375 #endif
376 }
377
378 bool BitmapImage::canDestroyDecodedData()
379 {
380     // Animated images should preserve the current frame till the next one finishes decoding.
381     if (m_source->hasAsyncDecodingQueue())
382         return false;
383
384     // Small image should be decoded synchronously. Deleting its decoded frame is fine.
385     if (!canUseAsyncDecodingForLargeImages())
386         return true;
387
388     return !imageObserver() || imageObserver()->canDestroyDecodedData(*this);
389 }
390
391 BitmapImage::StartAnimationStatus BitmapImage::internalStartAnimation()
392 {
393     LOG_WITH_STREAM(Images, stream << "BitmapImage " << this << " internalStartAnimation");
394
395     if (!canAnimate())
396         return StartAnimationStatus::CannotStart;
397
398     if (m_frameTimer)
399         return StartAnimationStatus::TimerActive;
400
401     // Don't start a new animation until we draw the frame that is currently being decoded.
402     size_t nextFrame = (m_currentFrame + 1) % frameCount();
403     if (frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(nextFrame, DecodingOptions(DecodingMode::Asynchronous))) {
404         LOG(Images, "BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]", __FUNCTION__, this, sourceURL().string().utf8().data(), nextFrame);
405         return StartAnimationStatus::DecodingActive;
406     }
407
408     if (m_currentFrame >= frameCount() - 1) {
409         // Don't advance past the last frame if we haven't decoded the whole image
410         // yet and our repetition count is potentially unset. The repetition count
411         // in a GIF can potentially come after all the rest of the image data, so
412         // wait on it.
413         if (!m_source->isAllDataReceived() && repetitionCount() == RepetitionCountOnce)
414             return StartAnimationStatus::IncompleteData;
415
416         ++m_repetitionsComplete;
417
418         // Check for the end of animation.
419         if (repetitionCount() != RepetitionCountInfinite && m_repetitionsComplete >= repetitionCount()) {
420             m_animationFinished = true;
421             destroyDecodedDataIfNecessary(false);
422             return StartAnimationStatus::CannotStart;
423         }
424
425         destroyDecodedDataIfNecessary(true);
426     }
427
428     // Don't advance the animation to an incomplete frame.
429     if (!m_source->isAllDataReceived() && !frameIsCompleteAtIndex(nextFrame))
430         return StartAnimationStatus::IncompleteData;
431
432     MonotonicTime time = MonotonicTime::now();
433
434     // Handle initial state.
435     if (!m_desiredFrameStartTime)
436         m_desiredFrameStartTime = time;
437
438     // Setting 'm_desiredFrameStartTime' to 'time' means we are late; otherwise we are early.
439     m_desiredFrameStartTime = std::max(time, m_desiredFrameStartTime + Seconds { frameDurationAtIndex(m_currentFrame) });
440
441     // Request async decoding for nextFrame only if this is required. If nextFrame is not in the frameCache,
442     // it will be decoded on a separate work queue. When decoding nextFrame finishes, we will be notified
443     // through the callback newFrameNativeImageAvailableAtIndex(). Otherwise, advanceAnimation() will be called
444     // when the timer fires and m_currentFrame will be advanced to nextFrame since it is not being decoded.
445     if (shouldUseAsyncDecodingForAnimatedImages()) {
446         if (frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(nextFrame, m_currentSubsamplingLevel, DecodingOptions(std::optional<IntSize>())))
447             LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_cachedFrameCount, nextFrame);
448         else {
449             m_source->requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel);
450             m_currentFrameDecodingStatus = DecodingStatus::Decoding;
451             LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), nextFrame);
452         }
453
454         if (m_clearDecoderAfterAsyncFrameRequestForTesting)
455             m_source->resetData(data());
456     }
457
458     ASSERT(!m_frameTimer);
459     startTimer(m_desiredFrameStartTime - time);
460     return StartAnimationStatus::Started;
461 }
462
463 void BitmapImage::advanceAnimation()
464 {
465     clearTimer();
466
467     // Don't advance to nextFrame unless its decoding has finished or was not required.
468     size_t nextFrame = (m_currentFrame + 1) % frameCount();
469     if (!frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(nextFrame, DecodingOptions(DecodingMode::Asynchronous)))
470         internalAdvanceAnimation();
471     else {
472         // Force repaint if showDebugBackground() is on.
473         if (m_showDebugBackground)
474             imageObserver()->changedInRect(*this);
475         LOG(Images, "BitmapImage::%s - %p - url: %s [lateFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_lateFrameCount, nextFrame);
476     }
477 }
478
479 void BitmapImage::internalAdvanceAnimation()
480 {
481     m_currentFrame = (m_currentFrame + 1) % frameCount();
482     ASSERT(!frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingOptions(DecodingMode::Asynchronous)));
483
484     destroyDecodedDataIfNecessary(false);
485
486     DecodingStatus decodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
487     setCurrentFrameDecodingStatusIfNecessary(decodingStatus);
488
489     callDecodingCallbacks();
490
491     if (imageObserver())
492         imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::Yes, nullptr, decodingStatus);
493
494     LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), m_currentFrame);
495 }
496
497 bool BitmapImage::isAnimating() const
498 {
499     return !!m_frameTimer;
500 }
501
502 void BitmapImage::stopAnimation()
503 {
504     // This timer is used to animate all occurrences of this image. Don't invalidate
505     // the timer unless all renderers have stopped drawing.
506     clearTimer();
507     if (canAnimate())
508         m_source->stopAsyncDecodingQueue();
509 }
510
511 void BitmapImage::resetAnimation()
512 {
513     stopAnimation();
514     m_currentFrame = 0;
515     m_repetitionsComplete = RepetitionCountNone;
516     m_desiredFrameStartTime = { };
517     m_animationFinished = false;
518
519     // For extremely large animations, when the animation is reset, we just throw everything away.
520     destroyDecodedDataIfNecessary(true);
521 }
522
523 void BitmapImage::decode(WTF::Function<void()>&& callback)
524 {
525     if (!m_decodingCallbacks)
526         m_decodingCallbacks = std::make_unique<Vector<Function<void()>, 1>>();
527
528     m_decodingCallbacks->append(WTFMove(callback));
529
530     if (canAnimate())  {
531         if (m_desiredFrameStartTime) {
532             internalStartAnimation();
533             return;
534         }
535
536         // The animated image has not been displayed. In this case, either the first frame has not been decoded yet or the animation has not started yet.
537         bool frameIsCompatible = frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>());
538         bool frameIsBeingDecoded = frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, std::optional<IntSize>());
539
540         if (frameIsCompatible)
541             internalStartAnimation();
542         else if (!frameIsBeingDecoded) {
543             m_source->requestFrameAsyncDecodingAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>());
544             m_currentFrameDecodingStatus = DecodingStatus::Decoding;
545         }
546         return;
547     }
548
549     bool frameIsCompatible = frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>());
550     bool frameIsBeingDecoded = frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, std::optional<IntSize>());
551     
552     if (frameIsCompatible)
553         callDecodingCallbacks();
554     else if (!frameIsBeingDecoded) {
555         m_source->requestFrameAsyncDecodingAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>());
556         m_currentFrameDecodingStatus = DecodingStatus::Decoding;
557     }
558 }
559
560 void BitmapImage::callDecodingCallbacks()
561 {
562     if (!m_decodingCallbacks)
563         return;
564     for (auto& decodingCallback : *m_decodingCallbacks)
565         decodingCallback();
566     m_decodingCallbacks = nullptr;
567 }
568
569 void BitmapImage::imageFrameAvailableAtIndex(size_t index)
570 {
571     LOG(Images, "BitmapImage::%s - %p - url: %s [requested frame %ld is now available]", __FUNCTION__, this, sourceURL().string().utf8().data(), index);
572
573     if (canAnimate()) {
574         if (index == (m_currentFrame + 1) % frameCount()) {
575             // Don't advance to nextFrame unless the timer was fired before its decoding finishes.
576             if (!m_frameTimer)
577                 internalAdvanceAnimation();
578             else
579                 LOG(Images, "BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_earlyFrameCount, index);
580             return;
581         }
582
583         // Because of image partial loading, an image may start decoding as a large static image. But
584         // when more data is received, frameCount() changes to be > 1 so the image starts animating.
585         // The animation may even start before finishing the decoding of the first frame.
586         ASSERT(!m_repetitionsComplete);
587         LOG(Images, "BitmapImage::%s - %p - url: %s [More data makes frameCount() > 1]", __FUNCTION__, this, sourceURL().string().utf8().data());
588     }
589
590     ASSERT(index == m_currentFrame && !m_currentFrame);
591     if (m_source->isAsyncDecodingQueueIdle())
592         m_source->stopAsyncDecodingQueue();
593
594     DecodingStatus decodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
595     setCurrentFrameDecodingStatusIfNecessary(decodingStatus);
596
597     if (m_currentFrameDecodingStatus == DecodingStatus::Complete)
598         ++m_decodeCountForTesting;
599
600     // Call m_decodingCallbacks only if the image frame was decoded with the native size.
601     if (frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>()))
602         callDecodingCallbacks();
603
604     if (imageObserver())
605         imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::No, nullptr, decodingStatus);
606 }
607
608 unsigned BitmapImage::decodeCountForTesting() const
609 {
610     return m_decodeCountForTesting;
611 }
612
613 void BitmapImage::dump(TextStream& ts) const
614 {
615     Image::dump(ts);
616     
617     if (isAnimated())
618         ts.dumpProperty("current-frame", m_currentFrame);
619     
620     m_source->dump(ts);
621 }
622
623 }