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