• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "platform/graphics/DeferredImageDecoder.h"
28 
29 #include "platform/graphics/DecodingImageGenerator.h"
30 #include "platform/graphics/ImageDecodingStore.h"
31 #include "platform/graphics/LazyDecodingPixelRef.h"
32 #include "third_party/skia/include/core/SkImageInfo.h"
33 #include "wtf/PassOwnPtr.h"
34 
35 namespace WebCore {
36 
37 namespace {
38 
39 // URI label for SkDiscardablePixelRef.
40 const char labelDiscardable[] = "discardable";
41 
42 } // namespace
43 
44 bool DeferredImageDecoder::s_enabled = false;
45 
DeferredImageDecoder(PassOwnPtr<ImageDecoder> actualDecoder)46 DeferredImageDecoder::DeferredImageDecoder(PassOwnPtr<ImageDecoder> actualDecoder)
47     : m_allDataReceived(false)
48     , m_lastDataSize(0)
49     , m_dataChanged(false)
50     , m_actualDecoder(actualDecoder)
51     , m_orientation(DefaultImageOrientation)
52     , m_repetitionCount(cAnimationNone)
53     , m_hasColorProfile(false)
54 {
55 }
56 
~DeferredImageDecoder()57 DeferredImageDecoder::~DeferredImageDecoder()
58 {
59 }
60 
create(const SharedBuffer & data,ImageSource::AlphaOption alphaOption,ImageSource::GammaAndColorProfileOption gammaAndColorOption)61 PassOwnPtr<DeferredImageDecoder> DeferredImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorOption)
62 {
63     OwnPtr<ImageDecoder> actualDecoder = ImageDecoder::create(data, alphaOption, gammaAndColorOption);
64     return actualDecoder ? adoptPtr(new DeferredImageDecoder(actualDecoder.release())) : nullptr;
65 }
66 
createForTesting(PassOwnPtr<ImageDecoder> decoder)67 PassOwnPtr<DeferredImageDecoder> DeferredImageDecoder::createForTesting(PassOwnPtr<ImageDecoder> decoder)
68 {
69     return adoptPtr(new DeferredImageDecoder(decoder));
70 }
71 
isLazyDecoded(const SkBitmap & bitmap)72 bool DeferredImageDecoder::isLazyDecoded(const SkBitmap& bitmap)
73 {
74     return bitmap.pixelRef()
75         && bitmap.pixelRef()->getURI()
76         && !memcmp(bitmap.pixelRef()->getURI(), labelDiscardable, sizeof(labelDiscardable));
77 }
78 
setEnabled(bool enabled)79 void DeferredImageDecoder::setEnabled(bool enabled)
80 {
81     s_enabled = enabled;
82     if (enabled)
83         ImageDecodingStore::setImageCachingEnabled(false);
84 }
85 
enabled()86 bool DeferredImageDecoder::enabled()
87 {
88     return s_enabled;
89 }
90 
filenameExtension() const91 String DeferredImageDecoder::filenameExtension() const
92 {
93     return m_actualDecoder ? m_actualDecoder->filenameExtension() : m_filenameExtension;
94 }
95 
frameBufferAtIndex(size_t index)96 ImageFrame* DeferredImageDecoder::frameBufferAtIndex(size_t index)
97 {
98     prepareLazyDecodedFrames();
99     if (index < m_lazyDecodedFrames.size()) {
100         // ImageFrameGenerator has the latest known alpha state. There will
101         // be a performance boost if this frame is opaque.
102         m_lazyDecodedFrames[index]->setHasAlpha(m_frameGenerator->hasAlpha(index));
103         return m_lazyDecodedFrames[index].get();
104     }
105     if (m_actualDecoder)
106         return m_actualDecoder->frameBufferAtIndex(index);
107     return 0;
108 }
109 
setData(SharedBuffer & data,bool allDataReceived)110 void DeferredImageDecoder::setData(SharedBuffer& data, bool allDataReceived)
111 {
112     if (m_actualDecoder) {
113         const bool firstData = !m_data;
114         const bool moreData = data.size() > m_lastDataSize;
115         m_dataChanged = firstData || moreData;
116         m_data = RefPtr<SharedBuffer>(data);
117         m_lastDataSize = data.size();
118         m_allDataReceived = allDataReceived;
119         m_actualDecoder->setData(&data, allDataReceived);
120         prepareLazyDecodedFrames();
121     }
122 
123     if (m_frameGenerator)
124         m_frameGenerator->setData(&data, allDataReceived);
125 }
126 
isSizeAvailable()127 bool DeferredImageDecoder::isSizeAvailable()
128 {
129     // m_actualDecoder is 0 only if image decoding is deferred and that
130     // means image header decoded successfully and size is available.
131     return m_actualDecoder ? m_actualDecoder->isSizeAvailable() : true;
132 }
133 
hasColorProfile() const134 bool DeferredImageDecoder::hasColorProfile() const
135 {
136     return m_actualDecoder ? m_actualDecoder->hasColorProfile() : m_hasColorProfile;
137 }
138 
size() const139 IntSize DeferredImageDecoder::size() const
140 {
141     return m_actualDecoder ? m_actualDecoder->size() : m_size;
142 }
143 
frameSizeAtIndex(size_t index) const144 IntSize DeferredImageDecoder::frameSizeAtIndex(size_t index) const
145 {
146     // FIXME: LocalFrame size is assumed to be uniform. This might not be true for
147     // future supported codecs.
148     return m_actualDecoder ? m_actualDecoder->frameSizeAtIndex(index) : m_size;
149 }
150 
frameCount()151 size_t DeferredImageDecoder::frameCount()
152 {
153     return m_actualDecoder ? m_actualDecoder->frameCount() : m_lazyDecodedFrames.size();
154 }
155 
repetitionCount() const156 int DeferredImageDecoder::repetitionCount() const
157 {
158     return m_actualDecoder ? m_actualDecoder->repetitionCount() : m_repetitionCount;
159 }
160 
clearCacheExceptFrame(size_t clearExceptFrame)161 size_t DeferredImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame)
162 {
163     // If image decoding is deferred then frame buffer cache is managed by
164     // the compositor and this call is ignored.
165     return m_actualDecoder ? m_actualDecoder->clearCacheExceptFrame(clearExceptFrame) : 0;
166 }
167 
frameHasAlphaAtIndex(size_t index) const168 bool DeferredImageDecoder::frameHasAlphaAtIndex(size_t index) const
169 {
170     if (m_actualDecoder)
171         return m_actualDecoder->frameHasAlphaAtIndex(index);
172     if (!m_frameGenerator->isMultiFrame())
173         return m_frameGenerator->hasAlpha(index);
174     return true;
175 }
176 
frameIsCompleteAtIndex(size_t index) const177 bool DeferredImageDecoder::frameIsCompleteAtIndex(size_t index) const
178 {
179     if (m_actualDecoder)
180         return m_actualDecoder->frameIsCompleteAtIndex(index);
181     if (index < m_lazyDecodedFrames.size())
182         return m_lazyDecodedFrames[index]->status() == ImageFrame::FrameComplete;
183     return false;
184 }
185 
frameDurationAtIndex(size_t index) const186 float DeferredImageDecoder::frameDurationAtIndex(size_t index) const
187 {
188     if (m_actualDecoder)
189         return m_actualDecoder->frameDurationAtIndex(index);
190     if (index < m_lazyDecodedFrames.size())
191         return m_lazyDecodedFrames[index]->duration();
192     return 0;
193 }
194 
frameBytesAtIndex(size_t index) const195 unsigned DeferredImageDecoder::frameBytesAtIndex(size_t index) const
196 {
197     // If frame decoding is deferred then it is not managed by MemoryCache
198     // so return 0 here.
199     return m_frameGenerator ? 0 : m_actualDecoder->frameBytesAtIndex(index);
200 }
201 
orientation() const202 ImageOrientation DeferredImageDecoder::orientation() const
203 {
204     return m_actualDecoder ? m_actualDecoder->orientation() : m_orientation;
205 }
206 
activateLazyDecoding()207 void DeferredImageDecoder::activateLazyDecoding()
208 {
209     if (m_frameGenerator)
210         return;
211     m_size = m_actualDecoder->size();
212     m_orientation = m_actualDecoder->orientation();
213     m_filenameExtension = m_actualDecoder->filenameExtension();
214     m_hasColorProfile = m_actualDecoder->hasColorProfile();
215     const bool isSingleFrame = m_actualDecoder->repetitionCount() == cAnimationNone || (m_allDataReceived && m_actualDecoder->frameCount() == 1u);
216     m_frameGenerator = ImageFrameGenerator::create(SkISize::Make(m_actualDecoder->decodedSize().width(), m_actualDecoder->decodedSize().height()), m_data, m_allDataReceived, !isSingleFrame);
217 }
218 
prepareLazyDecodedFrames()219 void DeferredImageDecoder::prepareLazyDecodedFrames()
220 {
221     if (!s_enabled
222         || !m_actualDecoder
223         || !m_actualDecoder->isSizeAvailable()
224         || m_actualDecoder->filenameExtension() == "ico")
225         return;
226 
227     activateLazyDecoding();
228 
229     const size_t previousSize = m_lazyDecodedFrames.size();
230     m_lazyDecodedFrames.resize(m_actualDecoder->frameCount());
231 
232     // We have encountered a broken image file. Simply bail.
233     if (m_lazyDecodedFrames.size() < previousSize)
234         return;
235 
236     for (size_t i = previousSize; i < m_lazyDecodedFrames.size(); ++i) {
237         OwnPtr<ImageFrame> frame(adoptPtr(new ImageFrame()));
238         frame->setSkBitmap(createBitmap(i));
239         frame->setDuration(m_actualDecoder->frameDurationAtIndex(i));
240         frame->setStatus(m_actualDecoder->frameIsCompleteAtIndex(i) ? ImageFrame::FrameComplete : ImageFrame::FramePartial);
241         m_lazyDecodedFrames[i] = frame.release();
242     }
243 
244     // The last lazy decoded frame created from previous call might be
245     // incomplete so update its state.
246     if (previousSize) {
247         const size_t lastFrame = previousSize - 1;
248         m_lazyDecodedFrames[lastFrame]->setStatus(m_actualDecoder->frameIsCompleteAtIndex(lastFrame) ? ImageFrame::FrameComplete : ImageFrame::FramePartial);
249 
250         // If data has changed then create a new bitmap. This forces
251         // Skia to decode again.
252         if (m_dataChanged) {
253             m_dataChanged = false;
254             m_lazyDecodedFrames[lastFrame]->setSkBitmap(createBitmap(lastFrame));
255         }
256     }
257 
258     if (m_allDataReceived) {
259         m_repetitionCount = m_actualDecoder->repetitionCount();
260         m_actualDecoder.clear();
261         m_data = nullptr;
262     }
263 }
264 
265 // Creates a SkBitmap that is backed by SkDiscardablePixelRef.
createBitmap(size_t index)266 SkBitmap DeferredImageDecoder::createBitmap(size_t index)
267 {
268     IntSize decodedSize = m_actualDecoder->decodedSize();
269     ASSERT(decodedSize.width() > 0);
270     ASSERT(decodedSize.height() > 0);
271 
272     SkImageInfo info;
273     info.fWidth = decodedSize.width();
274     info.fHeight = decodedSize.height();
275 #if SK_B32_SHIFT // Little-endian RGBA pixels. (Android)
276     info.fColorType = kRGBA_8888_SkColorType;
277 #else
278     info.fColorType = kBGRA_8888_SkColorType;
279 #endif
280     info.fAlphaType = kPremul_SkAlphaType;
281 
282     SkBitmap bitmap;
283     DecodingImageGenerator* generator = new DecodingImageGenerator(m_frameGenerator, info, index);
284     bool installed = SkInstallDiscardablePixelRef(generator, &bitmap);
285     ASSERT_UNUSED(installed, installed);
286     bitmap.pixelRef()->setURI(labelDiscardable);
287     generator->setGenerationId(bitmap.getGenerationID());
288     return bitmap;
289 }
290 
hotSpot(IntPoint & hotSpot) const291 bool DeferredImageDecoder::hotSpot(IntPoint& hotSpot) const
292 {
293     // TODO: Implement.
294     return m_actualDecoder ? m_actualDecoder->hotSpot(hotSpot) : false;
295 }
296 
297 } // namespace WebCore
298