8256034782cb863af7491f0664c91bd5f91ada7f
[WebKit-https.git] / Source / WebCore / platform / graphics / ImageSource.cpp
1 /*
2  * Copyright (C) 2006, 2010, 2011, 2012, 2014, 2016 Apple Inc.  All rights reserved.
3  * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
4  * Copyright (C) 2008, Google Inc. All rights reserved.
5  * Copyright (C) 2007-2009 Torch Mobile, Inc
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "ImageSource.h"
31
32 #if USE(CG)
33 #include "ImageDecoderCG.h"
34 #elif USE(DIRECT2D)
35 #include "GraphicsContext.h"
36 #include "ImageDecoderDirect2D.h"
37 #include <WinCodec.h>
38 #else
39 #include "ImageDecoder.h"
40 #endif
41
42 #include "ImageOrientation.h"
43
44 #include <wtf/CurrentTime.h>
45
46 namespace WebCore {
47
48 ImageSource::ImageSource(NativeImagePtr&& nativeImage)
49     : m_frameCache(WTFMove(nativeImage))
50 {
51 }
52     
53 ImageSource::ImageSource(Image* image, AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
54     : m_frameCache(image)
55     , m_alphaOption(alphaOption)
56     , m_gammaAndColorProfileOption(gammaAndColorProfileOption)
57 {
58 }
59
60 ImageSource::~ImageSource()
61 {
62 }
63
64 void ImageSource::clearFrameBufferCache(size_t clearBeforeFrame)
65 {
66     if (!isDecoderAvailable())
67         return;
68     m_decoder->clearFrameBufferCache(clearBeforeFrame);
69 }
70
71 void ImageSource::clear(bool destroyAll, size_t count, SharedBuffer* data)
72 {
73     // There's no need to throw away the decoder unless we're explicitly asked
74     // to destroy all of the frames.
75     if (!destroyAll) {
76         clearFrameBufferCache(count);
77         return;
78     }
79
80     m_decoder = nullptr;
81     m_frameCache.setDecoder(nullptr);
82     setData(data, isAllDataReceived());
83 }
84
85 void ImageSource::destroyDecodedData(SharedBuffer* data, bool destroyAll, size_t count)
86 {
87     m_frameCache.destroyDecodedData(destroyAll, count);
88     clear(destroyAll, count, data);
89 }
90
91 bool ImageSource::destroyDecodedDataIfNecessary(SharedBuffer* data, bool destroyAll, size_t count)
92 {
93     // If we have decoded frames but there is no encoded data, we shouldn't destroy
94     // the decoded image since we won't be able to reconstruct it later.
95     if (!data && m_frameCache.frameCount())
96         return false;
97
98     if (!m_frameCache.destroyDecodedDataIfNecessary(destroyAll, count))
99         return false;
100
101     clear(destroyAll, count, data);
102     return true;
103 }
104
105 bool ImageSource::ensureDecoderAvailable(SharedBuffer* data)
106 {
107     if (!data || isDecoderAvailable())
108         return true;
109
110     m_decoder = ImageDecoder::create(*data, m_alphaOption, m_gammaAndColorProfileOption);
111     if (!isDecoderAvailable())
112         return false;
113
114     m_frameCache.setDecoder(m_decoder.get());
115     return true;
116 }
117
118 #if USE(DIRECT2D)
119 void ImageSource::setRenderTarget(GraphicsContext& context)
120 {
121     if (!isDecoderAvailable())
122         return;
123
124     m_decoder->setRenderTarget(context.platformContext());
125 }
126 #endif
127
128 void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
129 {
130     if (!data || !ensureDecoderAvailable(data))
131         return;
132
133     m_decoder->setData(*data, allDataReceived);
134 }
135
136 bool ImageSource::dataChanged(SharedBuffer* data, bool allDataReceived)
137 {
138     m_frameCache.destroyIncompleteDecodedData();
139
140 #if PLATFORM(IOS)
141     // FIXME: We should expose a setting to enable/disable progressive loading and make this
142     // code conditional on it. Then we can remove the PLATFORM(IOS)-guard.
143     static const double chunkLoadIntervals[] = {0, 1, 3, 6, 15};
144     double interval = chunkLoadIntervals[std::min(m_progressiveLoadChunkCount, static_cast<uint16_t>(4))];
145
146     bool needsUpdate = false;
147
148     // The first time through, the chunk time will be 0 and the image will get an update.
149     if (currentTime() - m_progressiveLoadChunkTime > interval) {
150         needsUpdate = true;
151         m_progressiveLoadChunkTime = currentTime();
152         ASSERT(m_progressiveLoadChunkCount <= std::numeric_limits<uint16_t>::max());
153         ++m_progressiveLoadChunkCount;
154     }
155
156     if (needsUpdate || allDataReceived)
157         setData(data, allDataReceived);
158 #else
159     setData(data, allDataReceived);
160 #endif
161
162     m_frameCache.clearMetadata();
163     if (!isSizeAvailable())
164         return false;
165
166     m_frameCache.growFrames();
167     return true;
168 }
169
170 bool ImageSource::isAllDataReceived()
171 {
172     return isDecoderAvailable() ? m_decoder->isAllDataReceived() : m_frameCache.frameCount();
173 }
174
175 SubsamplingLevel ImageSource::maximumSubsamplingLevel()
176 {
177     if (m_maximumSubsamplingLevel)
178         return m_maximumSubsamplingLevel.value();
179
180     if (!m_allowSubsampling || !isDecoderAvailable() || !m_decoder->frameAllowSubsamplingAtIndex(0))
181         return SubsamplingLevel::Default;
182
183     // FIXME: this value was chosen to be appropriate for iOS since the image
184     // subsampling is only enabled by default on iOS. Choose a different value
185     // if image subsampling is enabled on other platform.
186     const int maximumImageAreaBeforeSubsampling = 5 * 1024 * 1024;
187     SubsamplingLevel level = SubsamplingLevel::First;
188
189     for (; level < SubsamplingLevel::Last; ++level) {
190         if (frameSizeAtIndex(0, level).area() < maximumImageAreaBeforeSubsampling)
191             break;
192     }
193
194     m_maximumSubsamplingLevel = level;
195     return m_maximumSubsamplingLevel.value();
196 }
197
198 SubsamplingLevel ImageSource::subsamplingLevelForScale(float scale)
199 {
200     if (!(scale > 0 && scale <= 1))
201         return SubsamplingLevel::Default;
202
203     int result = std::ceil(std::log2(1 / scale));
204     return static_cast<SubsamplingLevel>(std::min(result, static_cast<int>(maximumSubsamplingLevel())));
205 }
206
207 NativeImagePtr ImageSource::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
208 {
209     return isDecoderAvailable() ? m_decoder->createFrameImageAtIndex(index, subsamplingLevel) : nullptr;
210 }
211
212 void ImageSource::dump(TextStream& ts)
213 {
214     ts.dumpProperty("type", filenameExtension());
215     ts.dumpProperty("frame-count", frameCount());
216     ts.dumpProperty("repetitions", repetitionCount());
217     ts.dumpProperty("solid-color", singlePixelSolidColor());
218
219     ImageOrientation orientation = frameOrientationAtIndex(0);
220     if (orientation != OriginTopLeft)
221         ts.dumpProperty("orientation", orientation);
222 }
223
224 }