[Win][Direct2D] Implement basic SVG support
[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 "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_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     stopAnimation();
65 }
66
67 void BitmapImage::destroyDecodedData(bool destroyAll)
68 {
69     m_source.destroyDecodedData(data(), destroyAll, m_currentFrame);
70     invalidatePlatformData();
71 }
72
73 void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll)
74 {
75     m_source.destroyDecodedDataIfNecessary(data(), destroyAll, m_currentFrame);
76 }
77
78 bool BitmapImage::dataChanged(bool allDataReceived)
79 {
80     return m_source.dataChanged(data(), allDataReceived);
81 }
82
83 NativeImagePtr BitmapImage::frameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
84 {
85     if (frameHasInvalidNativeImageAtIndex(index, subsamplingLevel)) {
86         LOG(Images, "BitmapImage %p frameImageAtIndex - subsamplingLevel was %d, resampling", this, static_cast<int>(frameSubsamplingLevelAtIndex(index)));
87         invalidatePlatformData();
88     }
89
90     return m_source.frameImageAtIndex(index, subsamplingLevel, targetContext);
91 }
92
93 NativeImagePtr BitmapImage::nativeImage(const GraphicsContext* targetContext)
94 {
95     return frameImageAtIndex(0, SubsamplingLevel::Default, targetContext);
96 }
97
98 NativeImagePtr BitmapImage::nativeImageForCurrentFrame(const GraphicsContext* targetContext)
99 {
100     return frameImageAtIndex(m_currentFrame, SubsamplingLevel::Default, targetContext);
101 }
102
103 #if USE(CG)
104 NativeImagePtr BitmapImage::nativeImageOfSize(const IntSize& size, const GraphicsContext* targetContext)
105 {
106     size_t count = frameCount();
107
108     for (size_t i = 0; i < count; ++i) {
109         auto image = frameImageAtIndex(i, SubsamplingLevel::Default, targetContext);
110         if (image && nativeImageSize(image) == size)
111             return image;
112     }
113
114     // Fallback to the first frame image if we can't find the right size
115     return frameImageAtIndex(0, SubsamplingLevel::Default, targetContext);
116 }
117
118 Vector<NativeImagePtr> BitmapImage::framesNativeImages()
119 {
120     Vector<NativeImagePtr> images;
121     size_t count = frameCount();
122
123     for (size_t i = 0; i < count; ++i) {
124         if (auto image = frameImageAtIndex(i))
125             images.append(image);
126     }
127
128     return images;
129 }
130 #endif
131
132 #if !ASSERT_DISABLED
133 bool BitmapImage::notSolidColor()
134 {
135     return size().width() != 1 || size().height() != 1 || frameCount() > 1;
136 }
137 #endif
138
139 void BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode mode, ImageOrientationDescription description)
140 {
141     if (destRect.isEmpty() || srcRect.isEmpty())
142         return;
143
144 #if PLATFORM(IOS)
145     startAnimation(DoNotCatchUp);
146 #else
147     startAnimation();
148 #endif
149
150     Color color = singlePixelSolidColor();
151     if (color.isValid()) {
152         fillWithSolidColor(context, destRect, color, op);
153         return;
154     }
155
156     float scale = subsamplingScale(context, destRect, srcRect);
157     SubsamplingLevel subsamplingLevel = m_source.subsamplingLevelForScale(scale);
158     LOG(Images, "BitmapImage %p draw - subsamplingLevel %d at scale %.4f", this, static_cast<int>(subsamplingLevel), scale);
159
160     auto image = frameImageAtIndex(m_currentFrame, subsamplingLevel, &context);
161     if (!image) // If it's too early we won't have an image yet.
162         return;
163
164     ImageOrientation orientation(description.imageOrientation());
165     if (description.respectImageOrientation() == RespectImageOrientation)
166         orientation = frameOrientationAtIndex(m_currentFrame);
167
168     drawNativeImage(image, context, destRect, srcRect, IntSize(size()), op, mode, orientation);
169
170     if (imageObserver())
171         imageObserver()->didDraw(this);
172 }
173
174 void BitmapImage::drawPattern(GraphicsContext& ctxt, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& transform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode)
175 {
176     if (tileRect.isEmpty())
177         return;
178
179     if (!ctxt.drawLuminanceMask()) {
180         Image::drawPattern(ctxt, destRect, tileRect, transform, phase, spacing, op, blendMode);
181         return;
182     }
183
184     if (!m_cachedImage) {
185         auto buffer = ImageBuffer::createCompatibleBuffer(expandedIntSize(tileRect.size()), ColorSpaceSRGB, ctxt);
186         if (!buffer)
187             return;
188
189         ImageObserver* observer = imageObserver();
190
191         // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout.
192         setImageObserver(nullptr);
193
194         draw(buffer->context(), tileRect, tileRect, op, blendMode, ImageOrientationDescription());
195
196         setImageObserver(observer);
197         buffer->convertToLuminanceMask();
198
199         m_cachedImage = buffer->copyImage(DontCopyBackingStore, Unscaled);
200         if (!m_cachedImage)
201             return;
202     }
203
204     ctxt.setDrawLuminanceMask(false);
205     m_cachedImage->drawPattern(ctxt, destRect, tileRect, transform, phase, spacing, op, blendMode);
206 }
207
208 bool BitmapImage::shouldAnimate()
209 {
210     return repetitionCount() && !m_animationFinished && imageObserver();
211 }
212
213 bool BitmapImage::canAnimate()
214 {
215     return shouldAnimate() && frameCount() > 1;
216 }
217
218 void BitmapImage::clearTimer()
219 {
220     m_frameTimer = nullptr;
221 }
222
223 void BitmapImage::startTimer(double delay)
224 {
225     ASSERT(!m_frameTimer);
226     m_frameTimer = std::make_unique<Timer>(*this, &BitmapImage::advanceAnimation);
227     m_frameTimer->startOneShot(delay);
228 }
229
230 void BitmapImage::startAnimation(CatchUpAnimation catchUpIfNecessary)
231 {
232     if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
233         return;
234
235     // If we aren't already animating, set now as the animation start time.
236     const double time = monotonicallyIncreasingTime();
237     if (!m_desiredFrameStartTime)
238         m_desiredFrameStartTime = time;
239
240     // Don't advance the animation to an incomplete frame.
241     size_t nextFrame = (m_currentFrame + 1) % frameCount();
242     if (!m_source.isAllDataReceived() && !frameIsCompleteAtIndex(nextFrame))
243         return;
244
245     // Don't advance past the last frame if we haven't decoded the whole image
246     // yet and our repetition count is potentially unset. The repetition count
247     // in a GIF can potentially come after all the rest of the image data, so
248     // wait on it.
249     if (!m_source.isAllDataReceived() && repetitionCount() == RepetitionCountOnce && m_currentFrame >= (frameCount() - 1))
250         return;
251
252     // Determine time for next frame to start. By ignoring paint and timer lag
253     // in this calculation, we make the animation appear to run at its desired
254     // rate regardless of how fast it's being repainted.
255     const double currentDuration = frameDurationAtIndex(m_currentFrame);
256     m_desiredFrameStartTime += currentDuration;
257
258 #if !PLATFORM(IOS)
259     // When an animated image is more than five minutes out of date, the
260     // user probably doesn't care about resyncing and we could burn a lot of
261     // time looping through frames below. Just reset the timings.
262     const double cAnimationResyncCutoff = 5 * 60;
263     if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff)
264         m_desiredFrameStartTime = time + currentDuration;
265 #else
266     // Maintaining frame-to-frame delays is more important than
267     // maintaining absolute animation timing, so reset the timings each frame.
268     m_desiredFrameStartTime = time + currentDuration;
269 #endif
270
271     // The image may load more slowly than it's supposed to animate, so that by
272     // the time we reach the end of the first repetition, we're well behind.
273     // Clamp the desired frame start time in this case, so that we don't skip
274     // frames (or whole iterations) trying to "catch up". This is a tradeoff:
275     // It guarantees users see the whole animation the second time through and
276     // don't miss any repetitions, and is closer to what other browsers do; on
277     // the other hand, it makes animations "less accurate" for pages that try to
278     // sync an image and some other resource (e.g. audio), especially if users
279     // switch tabs (and thus stop drawing the animation, which will pause it)
280     // during that initial loop, then switch back later.
281     if (nextFrame == 0 && m_repetitionsComplete == 0 && m_desiredFrameStartTime < time)
282         m_desiredFrameStartTime = time;
283
284     if (catchUpIfNecessary == DoNotCatchUp || time < m_desiredFrameStartTime) {
285         // Haven't yet reached time for next frame to start; delay until then.
286         startTimer(std::max<double>(m_desiredFrameStartTime - time, 0));
287         return;
288     }
289
290     ASSERT(!m_frameTimer);
291
292     // We've already reached or passed the time for the next frame to start.
293     // See if we've also passed the time for frames after that to start, in
294     // case we need to skip some frames entirely. Remember not to advance
295     // to an incomplete frame.
296
297 #if !LOG_DISABLED
298     size_t startCatchupFrameIndex = nextFrame;
299 #endif
300
301     for (size_t frameAfterNext = (nextFrame + 1) % frameCount(); frameIsCompleteAtIndex(frameAfterNext); frameAfterNext = (nextFrame + 1) % frameCount()) {
302         // Should we skip the next frame?
303         double frameAfterNextStartTime = m_desiredFrameStartTime + frameDurationAtIndex(nextFrame);
304         if (time < frameAfterNextStartTime)
305             break;
306
307         // Yes; skip over it without notifying our observers. If we hit the end while catching up,
308         // tell the observer asynchronously.
309         if (!internalAdvanceAnimation(SkippingFramesToCatchUp)) {
310             m_animationFinishedWhenCatchingUp = true;
311             startTimer(0);
312             LOG(Images, "BitmapImage %p startAnimation catching up from frame %lu, ended", this, startCatchupFrameIndex);
313             return;
314         }
315         m_desiredFrameStartTime = frameAfterNextStartTime;
316         nextFrame = frameAfterNext;
317     }
318
319     LOG(Images, "BitmapImage %p startAnimation catching up jumped from from frame %lu to %d", this, startCatchupFrameIndex, (int)nextFrame - 1);
320
321     // Draw the next frame as soon as possible. Note that m_desiredFrameStartTime
322     // may be in the past, meaning the next time through this function we'll
323     // kick off the next advancement sooner than this frame's duration would suggest.
324     startTimer(0);
325 }
326
327 void BitmapImage::advanceAnimation()
328 {
329     internalAdvanceAnimation();
330     // At this point the image region has been marked dirty, and if it's
331     // onscreen, we'll soon make a call to draw(), which will call
332     // startAnimation() again to keep the animation moving.
333 }
334
335 bool BitmapImage::internalAdvanceAnimation(AnimationAdvancement advancement)
336 {
337     clearTimer();
338
339     if (m_animationFinishedWhenCatchingUp) {
340         imageObserver()->animationAdvanced(this);
341         m_animationFinishedWhenCatchingUp = false;
342         return false;
343     }
344
345     ++m_currentFrame;
346     bool advancedAnimation = true;
347     bool destroyAll = false;
348     if (m_currentFrame >= frameCount()) {
349         ++m_repetitionsComplete;
350
351         // Get the repetition count again. If we weren't able to get a
352         // repetition count before, we should have decoded the whole image by
353         // now, so it should now be available.
354         if (repetitionCount() != RepetitionCountInfinite && m_repetitionsComplete > repetitionCount()) {
355             m_animationFinished = true;
356             m_desiredFrameStartTime = 0;
357             --m_currentFrame;
358             advancedAnimation = false;
359         } else {
360             m_currentFrame = 0;
361             destroyAll = true;
362         }
363     }
364     destroyDecodedDataIfNecessary(destroyAll);
365
366     // We need to draw this frame if we advanced to it while not skipping, or if
367     // while trying to skip frames we hit the last frame and thus had to stop.
368     if (advancement == Normal && advancedAnimation)
369         imageObserver()->animationAdvanced(this);
370
371     return advancedAnimation;
372 }
373
374 void BitmapImage::stopAnimation()
375 {
376     // This timer is used to animate all occurrences of this image. Don't invalidate
377     // the timer unless all renderers have stopped drawing.
378     clearTimer();
379 }
380
381 void BitmapImage::resetAnimation()
382 {
383     stopAnimation();
384     m_currentFrame = 0;
385     m_repetitionsComplete = 0;
386     m_desiredFrameStartTime = 0;
387     m_animationFinished = false;
388
389     // For extremely large animations, when the animation is reset, we just throw everything away.
390     destroyDecodedDataIfNecessary(true);
391 }
392
393 void BitmapImage::dump(TextStream& ts) const
394 {
395     Image::dump(ts);
396     
397     if (isAnimated())
398         ts.dumpProperty("current-frame", m_currentFrame);
399     
400     m_source.dump(ts);
401 }
402
403 }