Passing alpha to DeferredImageDecoder once decoding completes
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / ImageFrameGenerator.cpp
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
28 #include "ImageFrameGenerator.h"
29
30 #include "ImageDecoder.h"
31 #include "ImageDecodingStore.h"
32 #include "ScaledImageFragment.h"
33 #include "SharedBuffer.h"
34
35 #include "skia/ext/image_operations.h"
36
37 namespace WebCore {
38
39 namespace {
40
41 skia::ImageOperations::ResizeMethod resizeMethod()
42 {
43     return skia::ImageOperations::RESIZE_LANCZOS3;
44 }
45
46 } // namespace
47
48 ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived)
49     : m_fullSize(fullSize)
50     , m_decodeFailedAndEmpty(false)
51     , m_hasAlpha(true)
52 {
53     setData(data.get(), allDataReceived);
54 }
55
56 ImageFrameGenerator::~ImageFrameGenerator()
57 {
58     // FIXME: This check is not really thread-safe. This should be changed to:
59     // ImageDecodingStore::removeCacheFromInstance(this);
60     // Which uses a lock internally.
61     if (ImageDecodingStore::instance())
62         ImageDecodingStore::instance()->removeCacheIndexedByGenerator(this);
63 }
64
65 void ImageFrameGenerator::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived)
66 {
67     m_data.setData(data.get(), allDataReceived);
68 }
69
70 const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& scaledSize)
71 {
72     // Prevents concurrent decode or scale operations on the same image data.
73     // Multiple LazyDecodingPixelRefs can call this method at the same time.
74     MutexLocker lock(m_decodeMutex);
75     if (m_decodeFailedAndEmpty)
76         return 0;
77
78     const ScaledImageFragment* cachedImage = 0;
79
80     cachedImage = tryToLockCompleteCache(scaledSize);
81     if (cachedImage)
82         return cachedImage;
83
84     cachedImage = tryToScale(0, scaledSize);
85     if (cachedImage)
86         return cachedImage;
87
88     cachedImage = tryToResumeDecodeAndScale(scaledSize);
89     if (cachedImage)
90         return cachedImage;
91
92     cachedImage = tryToDecodeAndScale(scaledSize);
93     if (cachedImage)
94         return cachedImage;
95     return 0;
96 }
97
98 const ScaledImageFragment* ImageFrameGenerator::tryToLockCompleteCache(const SkISize& scaledSize)
99 {
100     const ScaledImageFragment* cachedImage = 0;
101     if (ImageDecodingStore::instance()->lockCache(this, scaledSize, ImageDecodingStore::CacheMustBeComplete, &cachedImage))
102         return cachedImage;
103     return 0;
104 }
105
106 const ScaledImageFragment* ImageFrameGenerator::tryToScale(const ScaledImageFragment* fullSizeImage, const SkISize& scaledSize)
107 {
108     // If the requested scaled size is the same as the full size then exit
109     // early. This saves a cache lookup.
110     if (scaledSize == m_fullSize)
111         return 0;
112
113     if (!fullSizeImage && !ImageDecodingStore::instance()->lockCache(this, m_fullSize, ImageDecodingStore::CacheMustBeComplete, &fullSizeImage))
114         return 0;
115
116     DiscardablePixelRefAllocator allocator;
117     // This call allocates the DiscardablePixelRef and lock/unlocks it
118     // afterwards. So the memory allocated to the scaledBitmap can be
119     // discarded after this call. Need to lock the scaledBitmap and
120     // check the pixels before using it next time.
121     SkBitmap scaledBitmap = skia::ImageOperations::Resize(fullSizeImage->bitmap(), resizeMethod(), scaledSize.width(), scaledSize.height(), &allocator);
122
123     OwnPtr<ScaledImageFragment> scaledImage = ScaledImageFragment::create(scaledSize, scaledBitmap, fullSizeImage->isComplete());
124
125     ImageDecodingStore::instance()->unlockCache(this, fullSizeImage);
126
127     const ScaledImageFragment* cachedImage = 0;
128
129     // If a cache lookup is successful then the cache entry must be incomplete
130     // therefore it is safe to overwrite.
131     if (ImageDecodingStore::instance()->lockCache(this, scaledSize, ImageDecodingStore::CacheCanBeIncomplete, &cachedImage))
132         return ImageDecodingStore::instance()->overwriteAndLockCache(this, cachedImage, scaledImage.release());
133     return ImageDecodingStore::instance()->insertAndLockCache(this, scaledImage.release());
134 }
135
136 const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const SkISize& scaledSize)
137 {
138     const ScaledImageFragment* cachedImage = 0;
139     ImageDecoder* cachedDecoder = 0;
140     if (!ImageDecodingStore::instance()->lockCache(this, m_fullSize, ImageDecodingStore::CacheCanBeIncomplete, &cachedImage, &cachedDecoder))
141         return 0;
142     ASSERT(cachedDecoder);
143
144     if (m_data.hasNewData()) {
145         // Only do decoding if there is new data.
146         OwnPtr<ScaledImageFragment> fullSizeImage = decode(&cachedDecoder);
147         cachedImage = ImageDecodingStore::instance()->overwriteAndLockCache(this, cachedImage, fullSizeImage.release());
148     }
149
150     if (m_fullSize == scaledSize)
151         return cachedImage;
152     return tryToScale(cachedImage, scaledSize);
153 }
154
155 const ScaledImageFragment* ImageFrameGenerator::tryToDecodeAndScale(const SkISize& scaledSize)
156 {
157     ImageDecoder* decoder = 0;
158     OwnPtr<ScaledImageFragment> fullSizeImage = decode(&decoder);
159
160     if (!decoder)
161         return 0;
162
163     OwnPtr<ImageDecoder> decoderContainer = adoptPtr(decoder);
164
165     if (!fullSizeImage) {
166         // If decode has failed and resulted an empty image we need to make
167         // sure we don't do wasted work in the future.
168         m_decodeFailedAndEmpty = decoderContainer->failed();
169         return 0;
170     }
171
172     const ScaledImageFragment* cachedFullSizeImage = ImageDecodingStore::instance()->insertAndLockCache(
173         this, fullSizeImage.release(), decoderContainer.release());
174
175     if (m_fullSize == scaledSize)
176         return cachedFullSizeImage;
177     return tryToScale(cachedFullSizeImage, scaledSize);
178 }
179
180 PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(ImageDecoder** decoder)
181 {
182     ASSERT(decoder);
183     SharedBuffer* data = 0;
184     bool allDataReceived = false;
185     m_data.data(&data, &allDataReceived);
186
187     // Try to create an ImageDecoder if we are not given one.
188     if (!*decoder) {
189         *decoder = ImageDecoder::create(*data, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileApplied);
190
191         if (!*decoder && m_imageDecoderFactory)
192             *decoder = m_imageDecoderFactory->create().leakPtr();
193
194         if (!*decoder)
195             return nullptr;
196     }
197
198     // TODO: this is very ugly. We need to refactor the way how we can pass a
199     // memory allocator to image decoders.
200     (*decoder)->setMemoryAllocator(&m_allocator);
201     (*decoder)->setData(data, allDataReceived);
202     // If this call returns a newly allocated DiscardablePixelRef, then
203     // ImageFrame::m_bitmap and the contained DiscardablePixelRef are locked.
204     // They will be unlocked when ImageDecoder is destroyed since ImageDecoder
205     // owns the ImageFrame. Partially decoded SkBitmap is thus inserted into the
206     // ImageDecodingStore while locked.
207     ImageFrame* frame = (*decoder)->frameBufferAtIndex(0);
208     (*decoder)->setData(0, false); // Unref SharedBuffer from ImageDecoder.
209
210     if (!frame || frame->status() == ImageFrame::FrameEmpty)
211         return nullptr;
212
213     bool isComplete = frame->status() == ImageFrame::FrameComplete;
214     SkBitmap fullSizeBitmap = frame->getSkBitmap();
215     {
216         MutexLocker lock(m_alphaMutex);
217         m_hasAlpha = !fullSizeBitmap.isOpaque();
218     }
219     ASSERT(fullSizeBitmap.width() == m_fullSize.width() && fullSizeBitmap.height() == m_fullSize.height());
220
221     return ScaledImageFragment::create(m_fullSize, fullSizeBitmap, isComplete);
222 }
223
224 bool ImageFrameGenerator::hasAlpha()
225 {
226     MutexLocker lock(m_alphaMutex);
227     return m_hasAlpha;
228 }
229
230 } // namespace WebCore