9a6ab1291d794f04528ee59e55f43cfdaa344a60
[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 "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_source(this)
52 {
53 }
54
55 BitmapImage::BitmapImage(NativeImagePtr&& image, ImageObserver* observer)
56     : Image(observer)
57     , m_source(WTFMove(image))
58 {
59 }
60
61 BitmapImage::~BitmapImage()
62 {
63     invalidatePlatformData();
64     clearTimer();
65     m_source.stopAsyncDecodingQueue();
66 }
67
68 void BitmapImage::updateFromSettings(const Settings& settings)
69 {
70     m_allowSubsampling = settings.imageSubsamplingEnabled();
71     m_allowLargeImageAsyncDecoding = settings.largeImageAsyncDecodingEnabled();
72     m_allowAnimatedImageAsyncDecoding = settings.animatedImageAsyncDecodingEnabled();
73     m_showDebugBackground = settings.showDebugBorders();
74 }
75
76 void BitmapImage::destroyDecodedData(bool destroyAll)
77 {
78     LOG(Images, "BitmapImage::%s - %p - url: %s", __FUNCTION__, this, sourceURL().string().utf8().data());
79
80     if (!destroyAll)
81         m_source.destroyDecodedDataBeforeFrame(m_currentFrame);
82     else if (m_source.hasAsyncDecodingQueue())
83         m_source.destroyAllDecodedDataExcludeFrame(m_currentFrame);
84     else
85         m_source.destroyAllDecodedData();
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.clear(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     return m_source.dataChanged(data(), allDataReceived);
113 }
114
115 NativeImagePtr BitmapImage::frameImageAtIndexCacheIfNeeded(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
116 {
117     if (!frameHasFullSizeNativeImageAtIndex(index, subsamplingLevel)) {
118         LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]", __FUNCTION__, this, sourceURL().string().utf8().data(), static_cast<int>(frameSubsamplingLevelAtIndex(index)));
119         invalidatePlatformData();
120     }
121
122     return m_source.frameImageAtIndexCacheIfNeeded(index, subsamplingLevel, targetContext);
123 }
124
125 NativeImagePtr BitmapImage::nativeImage(const GraphicsContext* targetContext)
126 {
127     return frameImageAtIndexCacheIfNeeded(0, SubsamplingLevel::Default, targetContext);
128 }
129
130 NativeImagePtr BitmapImage::nativeImageForCurrentFrame(const GraphicsContext* targetContext)
131 {
132     return frameImageAtIndexCacheIfNeeded(m_currentFrame, SubsamplingLevel::Default, targetContext);
133 }
134
135 #if USE(CG)
136 NativeImagePtr BitmapImage::nativeImageOfSize(const IntSize& size, const GraphicsContext* targetContext)
137 {
138     size_t count = frameCount();
139
140     for (size_t i = 0; i < count; ++i) {
141         auto image = frameImageAtIndexCacheIfNeeded(i, SubsamplingLevel::Default, targetContext);
142         if (image && nativeImageSize(image) == size)
143             return image;
144     }
145
146     // Fallback to the first frame image if we can't find the right size
147     return frameImageAtIndexCacheIfNeeded(0, SubsamplingLevel::Default, targetContext);
148 }
149
150 Vector<NativeImagePtr> BitmapImage::framesNativeImages()
151 {
152     Vector<NativeImagePtr> images;
153     size_t count = frameCount();
154
155     for (size_t i = 0; i < count; ++i) {
156         if (auto image = frameImageAtIndexCacheIfNeeded(i))
157             images.append(image);
158     }
159
160     return images;
161 }
162 #endif
163
164 #if !ASSERT_DISABLED
165 bool BitmapImage::notSolidColor()
166 {
167     return size().width() != 1 || size().height() != 1 || frameCount() > 1;
168 }
169 #endif
170
171 void BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode mode, DecodingMode decodingMode, ImageOrientationDescription description)
172 {
173     if (destRect.isEmpty() || srcRect.isEmpty())
174         return;
175
176     FloatSize scaleFactorForDrawing = context.scaleFactorForDrawing(destRect, srcRect);
177     IntSize sizeForDrawing = expandedIntSize(size() * scaleFactorForDrawing);
178     
179     m_currentSubsamplingLevel = m_allowSubsampling ? m_source.subsamplingLevelForScaleFactor(context, scaleFactorForDrawing) : SubsamplingLevel::Default;
180     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());
181
182     NativeImagePtr image;
183     if (decodingMode == DecodingMode::Asynchronous && shouldUseAsyncDecodingForLargeImages()) {
184         ASSERT(!canAnimate() && !m_currentFrame);
185
186         if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingOptions(sizeForDrawing))
187             && !frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingOptions(sizeForDrawing))) {
188             LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().string().utf8().data());
189             m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing);
190         }
191
192         if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingMode::Asynchronous)) {
193             if (m_showDebugBackground)
194                 fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
195             return;
196         }
197
198         image = frameImageAtIndex(m_currentFrame);
199         LOG(Images, "BitmapImage::%s - %p - url: %s [a decoded image frame is available for drawing]", __FUNCTION__, this, sourceURL().string().utf8().data());
200     } else {
201         StartAnimationStatus status = internalStartAnimation();
202         ASSERT_IMPLIES(status == StartAnimationStatus::DecodingActive, frameHasFullSizeNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel));
203
204         if (status == StartAnimationStatus::DecodingActive && m_showDebugBackground) {
205             fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
206             return;
207         }
208
209         if (frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingMode::Asynchronous)) {
210             // FIXME: instead of showing the yellow rectangle and returning we need to wait for this the frame to finish decoding.
211             if (m_showDebugBackground) {
212                 fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
213                 LOG(Images, "BitmapImage::%s - %p - url: %s [waiting for async decoding to finish]", __FUNCTION__, this, sourceURL().string().utf8().data());
214             }
215             return;
216         }
217
218         image = frameImageAtIndexCacheIfNeeded(m_currentFrame, m_currentSubsamplingLevel, &context);
219         if (!image) // If it's too early we won't have an image yet.
220             return;
221     }
222
223     ASSERT(image);
224     Color color = singlePixelSolidColor();
225     if (color.isValid()) {
226         fillWithSolidColor(context, destRect, color, op);
227         return;
228     }
229
230     ImageOrientation orientation(description.imageOrientation());
231     if (description.respectImageOrientation() == RespectImageOrientation)
232         orientation = frameOrientationAtIndex(m_currentFrame);
233
234     drawNativeImage(image, context, destRect, srcRect, IntSize(size()), op, mode, orientation);
235
236     if (imageObserver())
237         imageObserver()->didDraw(this);
238 }
239
240 void BitmapImage::drawPattern(GraphicsContext& ctxt, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& transform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode)
241 {
242     if (tileRect.isEmpty())
243         return;
244
245     if (!ctxt.drawLuminanceMask()) {
246         Image::drawPattern(ctxt, destRect, tileRect, transform, phase, spacing, op, blendMode);
247         return;
248     }
249
250     if (!m_cachedImage) {
251         auto buffer = ImageBuffer::createCompatibleBuffer(expandedIntSize(tileRect.size()), ColorSpaceSRGB, ctxt);
252         if (!buffer)
253             return;
254
255         ImageObserver* observer = imageObserver();
256
257         // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout.
258         setImageObserver(nullptr);
259
260         draw(buffer->context(), tileRect, tileRect, op, blendMode, DecodingMode::Synchronous, ImageOrientationDescription());
261
262         setImageObserver(observer);
263         buffer->convertToLuminanceMask();
264
265         m_cachedImage = buffer->copyImage(DontCopyBackingStore, Unscaled);
266         if (!m_cachedImage)
267             return;
268     }
269
270     ctxt.setDrawLuminanceMask(false);
271     m_cachedImage->drawPattern(ctxt, destRect, tileRect, transform, phase, spacing, op, blendMode);
272 }
273
274 bool BitmapImage::shouldAnimate()
275 {
276     return repetitionCount() && !m_animationFinished && imageObserver();
277 }
278
279 bool BitmapImage::canAnimate()
280 {
281     return shouldAnimate() && frameCount() > 1;
282 }
283
284 bool BitmapImage::shouldUseAsyncDecodingForLargeImages()
285 {
286     return !canAnimate() && m_allowLargeImageAsyncDecoding && m_source.shouldUseAsyncDecoding();
287 }
288
289 bool BitmapImage::shouldUseAsyncDecodingForAnimatedImages()
290 {
291     return canAnimate() && m_allowAnimatedImageAsyncDecoding && (shouldUseAsyncDecodingForAnimatedImagesForTesting() || m_source.shouldUseAsyncDecoding());
292 }
293
294 void BitmapImage::clearTimer()
295 {
296     m_frameTimer = nullptr;
297 }
298
299 void BitmapImage::startTimer(Seconds delay)
300 {
301     ASSERT(!m_frameTimer);
302     m_frameTimer = std::make_unique<Timer>(*this, &BitmapImage::advanceAnimation);
303     m_frameTimer->startOneShot(delay);
304 }
305
306 BitmapImage::StartAnimationStatus BitmapImage::internalStartAnimation()
307 {
308     if (!canAnimate())
309         return StartAnimationStatus::CannotStart;
310
311     if (m_frameTimer)
312         return StartAnimationStatus::TimerActive;
313
314     // Don't start a new animation until we draw the frame that is currently being decoded.
315     size_t nextFrame = (m_currentFrame + 1) % frameCount();
316     if (frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(nextFrame, DecodingMode::Asynchronous)) {
317         LOG(Images, "BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]", __FUNCTION__, this, sourceURL().string().utf8().data(), nextFrame);
318         return StartAnimationStatus::DecodingActive;
319     }
320
321     if (m_currentFrame >= frameCount() - 1) {
322         // Don't advance past the last frame if we haven't decoded the whole image
323         // yet and our repetition count is potentially unset. The repetition count
324         // in a GIF can potentially come after all the rest of the image data, so
325         // wait on it.
326         if (!m_source.isAllDataReceived() && repetitionCount() == RepetitionCountOnce)
327             return StartAnimationStatus::IncompleteData;
328
329         ++m_repetitionsComplete;
330
331         // Check for the end of animation.
332         if (repetitionCount() != RepetitionCountInfinite && m_repetitionsComplete >= repetitionCount()) {
333             m_animationFinished = true;
334             destroyDecodedDataIfNecessary(false);
335             return StartAnimationStatus::CannotStart;
336         }
337
338         destroyDecodedDataIfNecessary(true);
339     }
340
341     // Don't advance the animation to an incomplete frame.
342     if (!m_source.isAllDataReceived() && !frameIsCompleteAtIndex(nextFrame))
343         return StartAnimationStatus::IncompleteData;
344
345     MonotonicTime time = MonotonicTime::now();
346
347     // Handle initial state.
348     if (!m_desiredFrameStartTime)
349         m_desiredFrameStartTime = time;
350
351     // Setting 'm_desiredFrameStartTime' to 'time' means we are late; otherwise we are early.
352     m_desiredFrameStartTime = std::max(time, m_desiredFrameStartTime + Seconds { frameDurationAtIndex(m_currentFrame) });
353
354     // Request async decoding for nextFrame only if this is required. If nextFrame is not in the frameCache,
355     // it will be decoded on a separate work queue. When decoding nextFrame finishes, we will be notified
356     // through the callback newFrameNativeImageAvailableAtIndex(). Otherwise, advanceAnimation() will be called
357     // when the timer fires and m_currentFrame will be advanced to nextFrame since it is not being decoded.
358     if (shouldUseAsyncDecodingForAnimatedImages()) {
359         bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel);
360
361 #if !LOG_DISABLED
362         if (isAsyncDecode)
363             LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), nextFrame);
364         else
365             LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_cachedFrameCount, nextFrame);
366 #else
367         UNUSED_PARAM(isAsyncDecode);
368 #endif
369
370         m_desiredFrameDecodeTimeForTesting = time + std::max(m_frameDecodingDurationForTesting, 0_s);
371         if (m_clearDecoderAfterAsyncFrameRequestForTesting)
372             m_source.clear(data());
373     }
374
375     ASSERT(!m_frameTimer);
376     startTimer(m_desiredFrameStartTime - time);
377     return StartAnimationStatus::Started;
378 }
379
380 void BitmapImage::advanceAnimation()
381 {
382     clearTimer();
383
384     // Pretend as if decoding nextFrame has taken m_frameDecodingDurationForTesting from
385     // the time this decoding was requested.
386     if (shouldUseAsyncDecodingForAnimatedImagesForTesting()) {
387         MonotonicTime time = MonotonicTime::now();
388         // Start a timer with the remaining time from now till the m_desiredFrameDecodeTime.
389         if (m_desiredFrameDecodeTimeForTesting > std::max(time, m_desiredFrameStartTime)) {
390             startTimer(m_desiredFrameDecodeTimeForTesting - time);
391             return;
392         }
393     }
394
395     // Don't advance to nextFrame unless its decoding has finished or was not required.
396     size_t nextFrame = (m_currentFrame + 1) % frameCount();
397     if (!frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(nextFrame, DecodingMode::Asynchronous))
398         internalAdvanceAnimation();
399     else {
400         // Force repaint if showDebugBackground() is on.
401         if (m_showDebugBackground)
402             imageObserver()->changedInRect(this);
403         LOG(Images, "BitmapImage::%s - %p - url: %s [lateFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_lateFrameCount, nextFrame);
404     }
405 }
406
407 void BitmapImage::internalAdvanceAnimation()
408 {
409     m_currentFrame = (m_currentFrame + 1) % frameCount();
410     ASSERT(!frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingMode::Asynchronous));
411
412     destroyDecodedDataIfNecessary(false);
413
414     if (imageObserver())
415         imageObserver()->imageFrameAvailable(this, ImageAnimatingState::Yes);
416
417     LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), m_currentFrame);
418 }
419
420 bool BitmapImage::isAnimating() const
421 {
422     return !!m_frameTimer;
423 }
424
425 void BitmapImage::stopAnimation()
426 {
427     // This timer is used to animate all occurrences of this image. Don't invalidate
428     // the timer unless all renderers have stopped drawing.
429     clearTimer();
430     if (canAnimate())
431         m_source.stopAsyncDecodingQueue();
432 }
433
434 void BitmapImage::resetAnimation()
435 {
436     stopAnimation();
437     m_currentFrame = 0;
438     m_repetitionsComplete = RepetitionCountNone;
439     m_desiredFrameStartTime = { };
440     m_animationFinished = false;
441
442     // For extremely large animations, when the animation is reset, we just throw everything away.
443     destroyDecodedDataIfNecessary(true);
444 }
445
446 void BitmapImage::imageFrameAvailableAtIndex(size_t index)
447 {
448     UNUSED_PARAM(index);
449     LOG(Images, "BitmapImage::%s - %p - url: %s [requested frame %ld is now available]", __FUNCTION__, this, sourceURL().string().utf8().data(), index);
450
451     if (canAnimate()) {
452         ASSERT(index == (m_currentFrame + 1) % frameCount());
453         
454         // Don't advance to nextFrame unless the timer was fired before its decoding finishes.
455         if (canAnimate() && !m_frameTimer)
456             internalAdvanceAnimation();
457         else
458             LOG(Images, "BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_earlyFrameCount, index);
459     } else {
460         ASSERT(index == m_currentFrame && !m_currentFrame);
461         imageObserver()->imageFrameAvailable(this, ImageAnimatingState::No);
462         
463         if (m_source.isAsyncDecodingQueueIdle())
464             m_source.stopAsyncDecodingQueue();
465     }
466 }
467
468 void BitmapImage::dump(TextStream& ts) const
469 {
470     Image::dump(ts);
471     
472     if (isAnimated())
473         ts.dumpProperty("current-frame", m_currentFrame);
474     
475     m_source.dump(ts);
476 }
477
478 }