• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2007, The Android Open Source Project
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  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER 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 #define LOG_TAG "ImageSourceAndroid"
27 
28 #include "config.h"
29 
30 #include "AndroidLog.h"
31 #include "BitmapAllocatorAndroid.h"
32 #include "ImageSource.h"
33 #include "IntSize.h"
34 #include "NotImplemented.h"
35 #include "SharedBuffer.h"
36 #include "PlatformString.h"
37 
38 #include "SkBitmapRef.h"
39 #include "SkImageDecoder.h"
40 #include "SkImageRef.h"
41 #include "SkStream.h"
42 #include "SkTemplates.h"
43 
44 #ifdef ANDROID_ANIMATED_GIF
45     #include "EmojiFont.h"
46     #include "GIFImageDecoder.h"
47 
48     using namespace android;
49 #endif
50 
51 // TODO: We should make use of some of the common code in platform/graphics/ImageSource.cpp.
52 
53 //#define TRACE_SUBSAMPLE_BITMAPS
54 
55 
56 // flag to tell us when we're on a large-ram device (e.g. >= 256M)
57 #ifdef ANDROID_LARGE_MEMORY_DEVICE
58     // see dox for computeMaxBitmapSizeForCache()
59     #define MAX_SIZE_BEFORE_SUBSAMPLE   (32*1024*1024)
60 
61     // preserve quality for 24/32bit src
62     static const SkBitmap::Config gPrefConfigTable[6] = {
63         SkBitmap::kIndex8_Config,       // src: index, opaque
64         SkBitmap::kIndex8_Config,       // src: index, alpha
65         SkBitmap::kRGB_565_Config,      // src: 16bit, opaque
66         SkBitmap::kARGB_8888_Config,    // src: 16bit, alpha  (promote to 32bit)
67         SkBitmap::kARGB_8888_Config,    // src: 32bit, opaque
68         SkBitmap::kARGB_8888_Config,    // src: 32bit, alpha
69     };
70 #else
71     #define MAX_SIZE_BEFORE_SUBSAMPLE   (2*1024*1024)
72 
73     // tries to minimize memory usage (i.e. demote opaque 32bit -> 16bit)
74     static const SkBitmap::Config gPrefConfigTable[6] = {
75         SkBitmap::kIndex8_Config,       // src: index, opaque
76         SkBitmap::kIndex8_Config,       // src: index, alpha
77         SkBitmap::kRGB_565_Config,      // src: 16bit, opaque
78         SkBitmap::kARGB_8888_Config,    // src: 16bit, alpha  (promote to 32bit)
79         SkBitmap::kRGB_565_Config,      // src: 32bit, opaque (demote to 16bit)
80         SkBitmap::kARGB_8888_Config,    // src: 32bit, alpha
81     };
82 #endif
83 
84 /*  Images larger than this should be subsampled. Using ashmem, the decoded
85     pixels will be purged as needed, so this value can be pretty large. Making
86     it too small hurts image quality (e.g. abc.com background). 2Meg works for
87     the sites I've tested, but if we hit important sites that need more, we
88     should try increasing it and see if it has negative impact on performance
89     (i.e. we end up thrashing because we need to keep decoding images that have
90     been purged.
91 
92     Perhaps this value should be some fraction of the available RAM...
93 */
computeMaxBitmapSizeForCache()94 size_t computeMaxBitmapSizeForCache() {
95     return MAX_SIZE_BEFORE_SUBSAMPLE;
96 }
97 ///////////////////////////////////////////////////////////////////////////////
98 
99 class PrivateAndroidImageSourceRec : public SkBitmapRef {
100 public:
PrivateAndroidImageSourceRec(const SkBitmap & bm,int origWidth,int origHeight,int sampleSize)101     PrivateAndroidImageSourceRec(const SkBitmap& bm, int origWidth,
102                                  int origHeight, int sampleSize)
103             : SkBitmapRef(bm), fSampleSize(sampleSize), fAllDataReceived(false) {
104         this->setOrigSize(origWidth, origHeight);
105     }
106 
107     int  fSampleSize;
108     bool fAllDataReceived;
109 };
110 
111 namespace WebCore {
112 
ImageSource(AlphaOption alphaOption,GammaAndColorProfileOption gammaAndColorProfileOption)113 ImageSource::ImageSource(AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
114     : m_alphaOption(alphaOption)
115     , m_gammaAndColorProfileOption(gammaAndColorProfileOption)
116 {
117     m_decoder.m_image = NULL;
118 #ifdef ANDROID_ANIMATED_GIF
119     m_decoder.m_gifDecoder = 0;
120 #endif
121 }
122 
~ImageSource()123 ImageSource::~ImageSource() {
124     delete m_decoder.m_image;
125 #ifdef ANDROID_ANIMATED_GIF
126     delete m_decoder.m_gifDecoder;
127 #endif
128 }
129 
initialized() const130 bool ImageSource::initialized() const {
131     return
132 #ifdef ANDROID_ANIMATED_GIF
133         m_decoder.m_gifDecoder ||
134 #endif
135         m_decoder.m_image != NULL;
136 }
137 
computeSampleSize(const SkBitmap & bitmap)138 static int computeSampleSize(const SkBitmap& bitmap) {
139     const size_t maxSize = computeMaxBitmapSizeForCache();
140     size_t size = bitmap.getSize();
141     int sampleSize = 1;
142 
143     while (size > maxSize) {
144         sampleSize <<= 1;
145         size >>= 2;
146     }
147 
148 #ifdef TRACE_SUBSAMPLE_BITMAPS
149     if (sampleSize > 1) {
150         ALOGD("------- bitmap [%d %d] config=%d origSize=%d predictSize=%d sampleSize=%d\n",
151                  bitmap.width(), bitmap.height(), bitmap.config(),
152                  bitmap.getSize(), size, sampleSize);
153     }
154 #endif
155     return sampleSize;
156 }
157 
clearURL()158 void ImageSource::clearURL()
159 {
160     m_decoder.m_url.reset();
161 }
162 
setURL(const String & url)163 void ImageSource::setURL(const String& url)
164 {
165     m_decoder.m_url.setUTF16(url.characters(), url.length());
166 }
167 
168 #ifdef ANDROID_ANIMATED_GIF
169 // we only animate small GIFs for now, to save memory
170 // also, we only support this in Japan, hence the Emoji check
should_use_animated_gif(int width,int height)171 static bool should_use_animated_gif(int width, int height) {
172 #ifdef ANDROID_LARGE_MEMORY_DEVICE
173     return true;
174 #else
175     return EmojiFont::IsAvailable() &&
176            width <= 32 && height <= 32;
177 #endif
178 }
179 #endif
180 
setData(SharedBuffer * data,bool allDataReceived)181 void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
182 {
183 #ifdef ANDROID_ANIMATED_GIF
184     // This is only necessary if we allow ourselves to partially decode GIF
185     bool disabledAnimatedGif = false;
186     if (m_decoder.m_gifDecoder
187             && !m_decoder.m_gifDecoder->failed()) {
188         m_decoder.m_gifDecoder->setData(data, allDataReceived);
189         if (!allDataReceived || m_decoder.m_gifDecoder->frameCount() != 1)
190             return;
191         disabledAnimatedGif = true;
192         delete m_decoder.m_gifDecoder;
193         m_decoder.m_gifDecoder = 0;
194     }
195 #endif
196     if (NULL == m_decoder.m_image
197 #ifdef ANDROID_ANIMATED_GIF
198           && !m_decoder.m_gifDecoder
199 #endif
200                                             ) {
201         SkBitmap tmp;
202 
203         SkMemoryStream stream(data->data(), data->size(), false);
204         SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
205         if (!codec)
206             return;
207 
208         SkAutoTDelete<SkImageDecoder> ad(codec);
209         codec->setPrefConfigTable(gPrefConfigTable);
210         if (!codec->decode(&stream, &tmp, SkImageDecoder::kDecodeBounds_Mode))
211             return;
212 
213         int origW = tmp.width();
214         int origH = tmp.height();
215 
216 #ifdef ANDROID_ANIMATED_GIF
217         // First, check to see if this is an animated GIF
218         const char* contents = data->data();
219         if (data->size() > 3 && strncmp(contents, "GIF8", 4) == 0
220                 && should_use_animated_gif(origW, origH)
221                 && !disabledAnimatedGif) {
222             // This means we are looking at a GIF, so create special
223             // GIF Decoder
224             // Need to wait for all data received if we are assigning an
225             // allocator (which we are not at the moment).
226             if (!m_decoder.m_gifDecoder /*&& allDataReceived*/)
227                 m_decoder.m_gifDecoder = new GIFImageDecoder(m_alphaOption, m_gammaAndColorProfileOption);
228             int frameCount = 0;
229             if (!m_decoder.m_gifDecoder->failed()) {
230                 m_decoder.m_gifDecoder->setData(data, allDataReceived);
231                 if (!allDataReceived)
232                     return;
233                 frameCount = m_decoder.m_gifDecoder->frameCount();
234             }
235             if (frameCount != 1)
236                 return;
237             delete m_decoder.m_gifDecoder;
238             m_decoder.m_gifDecoder = 0;
239         }
240 #endif
241 
242         int sampleSize = computeSampleSize(tmp);
243         if (sampleSize > 1) {
244             codec->setSampleSize(sampleSize);
245             stream.rewind();
246             if (!codec->decode(&stream, &tmp,
247                                SkImageDecoder::kDecodeBounds_Mode)) {
248                 return;
249             }
250         }
251 
252         m_decoder.m_image = new PrivateAndroidImageSourceRec(tmp, origW, origH,
253                                                      sampleSize);
254 
255 //        ALOGD("----- started: [%d %d] %s\n", origW, origH, m_decoder.m_url.c_str());
256     }
257 
258     PrivateAndroidImageSourceRec* decoder = m_decoder.m_image;
259     if (allDataReceived && decoder && !decoder->fAllDataReceived) {
260         decoder->fAllDataReceived = true;
261 
262         SkBitmap* bm = &decoder->bitmap();
263 
264         BitmapAllocatorAndroid alloc(data, decoder->fSampleSize);
265         if (!alloc.allocPixelRef(bm, NULL)) {
266             return;
267         }
268         SkPixelRef* ref = bm->pixelRef();
269 
270         // we promise to never change the pixels (makes picture recording fast)
271         ref->setImmutable();
272         // give it the URL if we have one
273         ref->setURI(m_decoder.m_url);
274     }
275 }
276 
isSizeAvailable()277 bool ImageSource::isSizeAvailable()
278 {
279     return
280 #ifdef ANDROID_ANIMATED_GIF
281             (m_decoder.m_gifDecoder
282                     && m_decoder.m_gifDecoder->isSizeAvailable()) ||
283 #endif
284             m_decoder.m_image != NULL;
285 }
286 
size() const287 IntSize ImageSource::size() const
288 {
289 #ifdef ANDROID_ANIMATED_GIF
290     if (m_decoder.m_gifDecoder)
291         return m_decoder.m_gifDecoder->size();
292 #endif
293     if (m_decoder.m_image) {
294         return IntSize(m_decoder.m_image->origWidth(), m_decoder.m_image->origHeight());
295     }
296     return IntSize(0, 0);
297 }
298 
repetitionCount()299 int ImageSource::repetitionCount()
300 {
301 #ifdef ANDROID_ANIMATED_GIF
302     if (m_decoder.m_gifDecoder)
303         return m_decoder.m_gifDecoder->repetitionCount();
304     if (!m_decoder.m_image) return 0;
305 #endif
306     return 1;
307     // A property with value 0 means loop forever.
308 }
309 
frameCount() const310 size_t ImageSource::frameCount() const
311 {
312 #ifdef ANDROID_ANIMATED_GIF
313     if (m_decoder.m_gifDecoder) {
314         return m_decoder.m_gifDecoder->failed() ? 0
315                 : m_decoder.m_gifDecoder->frameCount();
316     }
317 #endif
318     // i.e. 0 frames if we're not decoded, or 1 frame if we are
319     return m_decoder.m_image != NULL;
320 }
321 
createFrameAtIndex(size_t index)322 SkBitmapRef* ImageSource::createFrameAtIndex(size_t index)
323 {
324 #ifdef ANDROID_ANIMATED_GIF
325     if (m_decoder.m_gifDecoder) {
326         ImageFrame* buffer =
327                 m_decoder.m_gifDecoder->frameBufferAtIndex(index);
328         if (!buffer || buffer->status() == ImageFrame::FrameEmpty)
329             return 0;
330         SkBitmap& bitmap = buffer->bitmap();
331         SkPixelRef* pixelRef = bitmap.pixelRef();
332         if (pixelRef)
333             pixelRef->setURI(m_decoder.m_url);
334         return new SkBitmapRef(bitmap);
335     }
336 #else
337     SkASSERT(index == 0);
338 #endif
339     SkASSERT(m_decoder.m_image != NULL);
340     m_decoder.m_image->ref();
341     return m_decoder.m_image;
342 }
343 
frameDurationAtIndex(size_t index)344 float ImageSource::frameDurationAtIndex(size_t index)
345 {
346     float duration = 0;
347 #ifdef ANDROID_ANIMATED_GIF
348     if (m_decoder.m_gifDecoder) {
349         ImageFrame* buffer
350                 = m_decoder.m_gifDecoder->frameBufferAtIndex(index);
351         if (!buffer || buffer->status() == ImageFrame::FrameEmpty)
352             return 0;
353         duration = buffer->duration() / 1000.0f;
354     }
355 #else
356     SkASSERT(index == 0);
357 #endif
358 
359     // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
360     // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
361     // a duration of <= 10 ms. See gfxImageFrame::GetTimeout in Gecko or Radar 4051389 for more.
362     if (duration <= 0.010f)
363         duration = 0.100f;
364     return duration;
365 }
366 
frameHasAlphaAtIndex(size_t index)367 bool ImageSource::frameHasAlphaAtIndex(size_t index)
368 {
369 #ifdef ANDROID_ANIMATED_GIF
370     if (m_decoder.m_gifDecoder) {
371         ImageFrame* buffer =
372                 m_decoder.m_gifDecoder->frameBufferAtIndex(index);
373         if (!buffer || buffer->status() == ImageFrame::FrameEmpty)
374             return false;
375 
376         return buffer->hasAlpha();
377     }
378 #else
379     SkASSERT(0 == index);
380 #endif
381 
382     if (NULL == m_decoder.m_image)
383         return true;    // if we're not sure, assume the worse-case
384     const PrivateAndroidImageSourceRec& decoder = *m_decoder.m_image;
385     // if we're 16bit, we know even without all the data available
386     if (decoder.bitmap().getConfig() == SkBitmap::kRGB_565_Config)
387         return false;
388 
389     if (!decoder.fAllDataReceived)
390         return true;    // if we're not sure, assume the worse-case
391 
392     return !decoder.bitmap().isOpaque();
393 }
394 
frameIsCompleteAtIndex(size_t index)395 bool ImageSource::frameIsCompleteAtIndex(size_t index)
396 {
397 #ifdef ANDROID_ANIMATED_GIF
398     if (m_decoder.m_gifDecoder) {
399         ImageFrame* buffer =
400                 m_decoder.m_gifDecoder->frameBufferAtIndex(index);
401         return buffer && buffer->status() == ImageFrame::FrameComplete;
402     }
403 #else
404     SkASSERT(0 == index);
405 #endif
406 	return m_decoder.m_image && m_decoder.m_image->fAllDataReceived;
407 }
408 
clear(bool destroyAll,size_t clearBeforeFrame,SharedBuffer * data,bool allDataReceived)409 void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
410 {
411 #ifdef ANDROID_ANIMATED_GIF
412     if (!destroyAll) {
413         if (m_decoder.m_gifDecoder)
414             m_decoder.m_gifDecoder->clearFrameBufferCache(clearBeforeFrame);
415         return;
416     }
417 
418     delete m_decoder.m_gifDecoder;
419     m_decoder.m_gifDecoder = 0;
420     if (data)
421         setData(data, allDataReceived);
422 #endif
423     // do nothing, since the cache is managed elsewhere
424 }
425 
frameSizeAtIndex(size_t index) const426 IntSize ImageSource::frameSizeAtIndex(size_t index) const
427 {
428     // for now, all (1) of our frames are the same size
429     return this->size();
430 }
431 
filenameExtension() const432 String ImageSource::filenameExtension() const
433 {
434     // FIXME: need to add virtual to our decoders to return "jpg/png/gif/..."
435 #ifdef ANDROID_ANIMATED_GIF
436     if (m_decoder.m_gifDecoder)
437         return m_decoder.m_gifDecoder->filenameExtension();
438 #endif
439     return String();
440 }
441 
getHotSpot(IntPoint &) const442 bool ImageSource::getHotSpot(IntPoint&) const
443 {
444     return false;
445 }
446 
bytesDecodedToDetermineProperties() const447 size_t ImageSource::bytesDecodedToDetermineProperties() const
448 {
449     return 0;
450 }
451 
452 }
453