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