• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009, The Android Open Source Project
3  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "TransformationMatrix.h"
29 #include "BitmapImage.h"
30 #include "Image.h"
31 #include "FloatRect.h"
32 #include "GraphicsContext.h"
33 #include "PlatformGraphicsContext.h"
34 #include "PlatformString.h"
35 #include "SharedBuffer.h"
36 
37 #include "android_graphics.h"
38 #include "SkBitmapRef.h"
39 #include "SkCanvas.h"
40 #include "SkColorPriv.h"
41 #include "SkImageDecoder.h"
42 #include "SkShader.h"
43 #include "SkString.h"
44 #include "SkTemplates.h"
45 #include "SkiaUtils.h"
46 
47 #include <androidfw/AssetManager.h>
48 
49 //#define TRACE_SUBSAMPLED_BITMAPS
50 //#define TRACE_SKIPPED_BITMAPS
51 
globalAssetManager()52 android::AssetManager* globalAssetManager() {
53     static android::AssetManager* gGlobalAssetMgr;
54     if (!gGlobalAssetMgr) {
55         gGlobalAssetMgr = new android::AssetManager();
56         gGlobalAssetMgr->addDefaultAssets();
57     }
58     return gGlobalAssetMgr;
59 }
60 
61 namespace WebCore {
62 
clear(bool clearMetadata)63 bool FrameData::clear(bool clearMetadata)
64 {
65     if (clearMetadata)
66         m_haveMetadata = false;
67 
68     if (m_frame) {
69         m_frame->unref();
70         m_frame = 0;
71         return true;
72     }
73     return false;
74 }
75 
BitmapImage(SkBitmapRef * ref,ImageObserver * observer)76 BitmapImage::BitmapImage(SkBitmapRef* ref, ImageObserver* observer)
77     : Image(observer)
78     , m_currentFrame(0)
79     , m_frames(0)
80     , m_frameTimer(0)
81     , m_repetitionCount(0)
82     , m_repetitionCountStatus(Unknown)
83     , m_repetitionsComplete(0)
84     , m_isSolidColor(false)
85     , m_animationFinished(true)
86     , m_allDataReceived(true)
87     , m_haveSize(true)
88     , m_sizeAvailable(true)
89     , m_decodedSize(0)
90     , m_haveFrameCount(true)
91     , m_frameCount(1)
92 {
93     initPlatformData();
94 
95     m_size = IntSize(ref->bitmap().width(), ref->bitmap().height());
96 
97     m_frames.grow(1);
98     m_frames[0].m_frame = ref;
99     m_frames[0].m_hasAlpha = !ref->bitmap().isOpaque();
100     checkForSolidColor();
101     ref->ref();
102 }
103 
104 
initPlatformData()105 void BitmapImage::initPlatformData()
106 {
107     m_source.clearURL();
108 }
109 
invalidatePlatformData()110 void BitmapImage::invalidatePlatformData()
111 {
112 }
113 
checkForSolidColor()114 void BitmapImage::checkForSolidColor()
115 {
116     m_checkedForSolidColor = true;
117     m_isSolidColor = false;
118     if (frameCount() == 1) {
119         SkBitmapRef* ref = frameAtIndex(0);
120         if (!ref) {
121             return; // keep solid == false
122         }
123 
124         const SkBitmap& bm = ref->bitmap();
125         if (bm.width() != 1 || bm.height() != 1) {
126             return;  // keep solid == false
127         }
128 
129         SkAutoLockPixels alp(bm);
130         if (!bm.readyToDraw()) {
131             return;  // keep solid == false
132         }
133 
134         SkPMColor color;
135         switch (bm.getConfig()) {
136             case SkBitmap::kARGB_8888_Config:
137                 color = *bm.getAddr32(0, 0);
138                 break;
139             case SkBitmap::kRGB_565_Config:
140                 color = SkPixel16ToPixel32(*bm.getAddr16(0, 0));
141                 break;
142             case SkBitmap::kIndex8_Config: {
143                 SkColorTable* ctable = bm.getColorTable();
144                 if (!ctable) {
145                 return;
146                 }
147                 color = (*ctable)[*bm.getAddr8(0, 0)];
148                 break;
149             }
150             default:
151                 return;  // keep solid == false
152         }
153         m_isSolidColor = true;
154         m_solidColor = SkPMColorToWebCoreColor(color);
155     }
156 }
157 
round(SkIRect * dst,const WebCore::FloatRect & src)158 static void round(SkIRect* dst, const WebCore::FloatRect& src)
159 {
160     dst->set(SkScalarRound(SkFloatToScalar(src.x())),
161              SkScalarRound(SkFloatToScalar(src.y())),
162              SkScalarRound(SkFloatToScalar((src.x() + src.width()))),
163              SkScalarRound(SkFloatToScalar((src.y() + src.height()))));
164 }
165 
round_scaled(SkIRect * dst,const WebCore::FloatRect & src,float sx,float sy)166 static void round_scaled(SkIRect* dst, const WebCore::FloatRect& src,
167                          float sx, float sy)
168 {
169     dst->set(SkScalarRound(SkFloatToScalar(src.x() * sx)),
170              SkScalarRound(SkFloatToScalar(src.y() * sy)),
171              SkScalarRound(SkFloatToScalar((src.x() + src.width()) * sx)),
172              SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
173 }
174 
draw(GraphicsContext * gc,const FloatRect & dstRect,const FloatRect & srcRect,ColorSpace,CompositeOperator compositeOp)175 void BitmapImage::draw(GraphicsContext* gc, const FloatRect& dstRect,
176                    const FloatRect& srcRect, ColorSpace,
177                    CompositeOperator compositeOp)
178 {
179     startAnimation();
180 
181     SkBitmapRef* image = this->nativeImageForCurrentFrame();
182     if (!image) { // If it's too early we won't have an image yet.
183         return;
184     }
185 
186     // in case we get called with an incomplete bitmap
187     const SkBitmap& bitmap = image->bitmap();
188     if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
189 #ifdef TRACE_SKIPPED_BITMAPS
190         SkDebugf("----- skip bitmapimage: [%d %d] pixels %p pixelref %p\n",
191                  bitmap.width(), bitmap.height(),
192                  bitmap.getPixels(), bitmap.pixelRef());
193 #endif
194         return;
195     }
196 
197     SkIRect srcR;
198     SkRect  dstR(dstRect);
199     float invScaleX = (float)bitmap.width() / image->origWidth();
200     float invScaleY = (float)bitmap.height() / image->origHeight();
201 
202     round_scaled(&srcR, srcRect, invScaleX, invScaleY);
203     if (srcR.isEmpty() || dstR.isEmpty()) {
204 #ifdef TRACE_SKIPPED_BITMAPS
205         SkDebugf("----- skip bitmapimage: [%d %d] src-empty %d dst-empty %d\n",
206                  bitmap.width(), bitmap.height(),
207                  srcR.isEmpty(), dstR.isEmpty());
208 #endif
209         return;
210     }
211 
212     gc->platformContext()->drawBitmapRect(bitmap, &srcR, dstR, compositeOp);
213 
214 #ifdef TRACE_SUBSAMPLED_BITMAPS
215     if (bitmap.width() != image->origWidth() ||
216         bitmap.height() != image->origHeight()) {
217         SkDebugf("--- BitmapImage::draw [%d %d] orig [%d %d]\n",
218                  bitmap.width(), bitmap.height(),
219                  image->origWidth(), image->origHeight());
220     }
221 #endif
222 }
223 
setURL(const String & str)224 void BitmapImage::setURL(const String& str)
225 {
226     m_source.setURL(str);
227 }
228 
229 ///////////////////////////////////////////////////////////////////////////////
230 
drawPattern(GraphicsContext * gc,const FloatRect & srcRect,const AffineTransform & patternTransform,const FloatPoint & phase,ColorSpace,CompositeOperator compositeOp,const FloatRect & destRect)231 void Image::drawPattern(GraphicsContext* gc, const FloatRect& srcRect,
232                         const AffineTransform& patternTransform,
233                         const FloatPoint& phase, ColorSpace,
234                         CompositeOperator compositeOp, const FloatRect& destRect)
235 {
236     SkBitmapRef* image = this->nativeImageForCurrentFrame();
237     if (!image || destRect.isEmpty())
238         return;
239 
240     // in case we get called with an incomplete bitmap
241     const SkBitmap& origBitmap = image->bitmap();
242     if (origBitmap.getPixels() == NULL && origBitmap.pixelRef() == NULL)
243         return;
244 
245     SkIRect srcR;
246     // we may have to scale if the image has been subsampled (so save RAM)
247     bool imageIsSubSampled = image->origWidth() != origBitmap.width() ||
248                              image->origHeight() != origBitmap.height();
249     float scaleX = 1;
250     float scaleY = 1;
251     if (imageIsSubSampled) {
252         scaleX = (float)image->origWidth() / origBitmap.width();
253         scaleY = (float)image->origHeight() / origBitmap.height();
254         round_scaled(&srcR, srcRect, 1 / scaleX, 1 / scaleY);
255     } else
256         round(&srcR, srcRect);
257 
258     // now extract the proper subset of the src image
259     SkBitmap bitmap;
260     if (!origBitmap.extractSubset(&bitmap, srcR)) {
261         SkDebugf("--- Image::drawPattern calling extractSubset failed\n");
262         return;
263     }
264 
265     SkMatrix matrix(patternTransform);
266 
267     if (imageIsSubSampled) {
268         matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY));
269     }
270     // We also need to translate it such that the origin of the pattern is the
271     // origin of the destination rect, which is what WebKit expects. Skia uses
272     // the coordinate system origin as the base for the patter. If WebKit wants
273     // a shifted image, it will shift it from there using the patternTransform.
274     float tx = phase.x() + srcRect.x() * patternTransform.a();
275     float ty = phase.y() + srcRect.y() * patternTransform.d();
276     matrix.postTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty));
277 
278     gc->platformContext()->drawBitmapPattern(bitmap, matrix, compositeOp, destRect);
279 }
280 
281 // missingImage, textAreaResizeCorner
loadPlatformResource(const char * name)282 PassRefPtr<Image> Image::loadPlatformResource(const char *name)
283 {
284     android::AssetManager* am = globalAssetManager();
285 
286     SkString path("webkit/");
287     path.append(name);
288     path.append(".png");
289 
290     android::Asset* a = am->open(path.c_str(),
291                                  android::Asset::ACCESS_BUFFER);
292     if (a == NULL) {
293         SkDebugf("---------------- failed to open image asset %s\n", name);
294         return NULL;
295     }
296 
297     SkAutoTDelete<android::Asset> ad(a);
298 
299     SkBitmap bm;
300     if (SkImageDecoder::DecodeMemory(a->getBuffer(false), a->getLength(), &bm)) {
301         SkBitmapRef* ref = new SkBitmapRef(bm);
302         // create will call ref(), so we need aur() to release ours upon return
303         SkAutoUnref aur(ref);
304         return BitmapImage::create(ref, 0);
305     }
306     return Image::nullImage();
307 }
308 
309 }   // namespace
310