• 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  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 <utils/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 
fixPaintForBitmapsThatMaySeam(SkPaint * paint)175 static inline void fixPaintForBitmapsThatMaySeam(SkPaint* paint) {
176     /*  Bitmaps may be drawn to seem next to other images. If we are drawn
177         zoomed, or at fractional coordinates, we may see cracks/edges if
178         we antialias, because that will cause us to draw the same pixels
179         more than once (e.g. from the left and right bitmaps that share
180         an edge).
181 
182         Disabling antialiasing fixes this, and since so far we are never
183         rotated at non-multiple-of-90 angles, this seems to do no harm
184      */
185     paint->setAntiAlias(false);
186 }
187 
draw(GraphicsContext * ctxt,const FloatRect & dstRect,const FloatRect & srcRect,CompositeOperator compositeOp)188 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
189                    const FloatRect& srcRect, CompositeOperator compositeOp)
190 {
191     startAnimation();
192 
193     SkBitmapRef* image = this->nativeImageForCurrentFrame();
194     if (!image) { // If it's too early we won't have an image yet.
195         return;
196     }
197 
198     // in case we get called with an incomplete bitmap
199     const SkBitmap& bitmap = image->bitmap();
200     if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
201 #ifdef TRACE_SKIPPED_BITMAPS
202         SkDebugf("----- skip bitmapimage: [%d %d] pixels %p pixelref %p\n",
203                  bitmap.width(), bitmap.height(),
204                  bitmap.getPixels(), bitmap.pixelRef());
205 #endif
206         return;
207     }
208 
209     SkIRect srcR;
210     SkRect  dstR(dstRect);
211     float invScaleX = (float)bitmap.width() / image->origWidth();
212     float invScaleY = (float)bitmap.height() / image->origHeight();
213 
214     round_scaled(&srcR, srcRect, invScaleX, invScaleY);
215     if (srcR.isEmpty() || dstR.isEmpty()) {
216 #ifdef TRACE_SKIPPED_BITMAPS
217         SkDebugf("----- skip bitmapimage: [%d %d] src-empty %d dst-empty %d\n",
218                  bitmap.width(), bitmap.height(),
219                  srcR.isEmpty(), dstR.isEmpty());
220 #endif
221         return;
222     }
223 
224     SkCanvas*   canvas = ctxt->platformContext()->mCanvas;
225     SkPaint     paint;
226 
227     ctxt->setupFillPaint(&paint);   // need global alpha among other things
228     paint.setFilterBitmap(true);
229     paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
230     fixPaintForBitmapsThatMaySeam(&paint);
231     canvas->drawBitmapRect(bitmap, &srcR, dstR, &paint);
232 
233 #ifdef TRACE_SUBSAMPLED_BITMAPS
234     if (bitmap.width() != image->origWidth() ||
235         bitmap.height() != image->origHeight()) {
236         SkDebugf("--- BitmapImage::draw [%d %d] orig [%d %d]\n",
237                  bitmap.width(), bitmap.height(),
238                  image->origWidth(), image->origHeight());
239     }
240 #endif
241 }
242 
setURL(const String & str)243 void BitmapImage::setURL(const String& str)
244 {
245     m_source.setURL(str);
246 }
247 
248 ///////////////////////////////////////////////////////////////////////////////
249 
drawPattern(GraphicsContext * ctxt,const FloatRect & srcRect,const TransformationMatrix & patternTransform,const FloatPoint & phase,CompositeOperator compositeOp,const FloatRect & destRect)250 void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect,
251                         const TransformationMatrix& patternTransform,
252                         const FloatPoint& phase, CompositeOperator compositeOp,
253                         const FloatRect& destRect)
254 {
255     SkBitmapRef* image = this->nativeImageForCurrentFrame();
256     if (!image) { // If it's too early we won't have an image yet.
257         return;
258     }
259 
260     // in case we get called with an incomplete bitmap
261     const SkBitmap& origBitmap = image->bitmap();
262     if (origBitmap.getPixels() == NULL && origBitmap.pixelRef() == NULL) {
263         return;
264     }
265 
266     SkRect  dstR(destRect);
267     if (dstR.isEmpty()) {
268         return;
269     }
270 
271     SkIRect srcR;
272     // we may have to scale if the image has been subsampled (so save RAM)
273     bool imageIsSubSampled = image->origWidth() != origBitmap.width() ||
274                              image->origHeight() != origBitmap.height();
275     float scaleX = 1;
276     float scaleY = 1;
277     if (imageIsSubSampled) {
278         scaleX = (float)image->origWidth() / origBitmap.width();
279         scaleY = (float)image->origHeight() / origBitmap.height();
280 //        SkDebugf("----- subsampled %g %g\n", scaleX, scaleY);
281         round_scaled(&srcR, srcRect, 1 / scaleX, 1 / scaleY);
282     } else {
283         round(&srcR, srcRect);
284     }
285 
286     // now extract the proper subset of the src image
287     SkBitmap bitmap;
288     if (!origBitmap.extractSubset(&bitmap, srcR)) {
289         SkDebugf("--- Image::drawPattern calling extractSubset failed\n");
290         return;
291     }
292 
293     SkCanvas*   canvas = ctxt->platformContext()->mCanvas;
294     SkPaint     paint;
295     ctxt->setupFillPaint(&paint);   // need global alpha among other things
296 
297     SkShader* shader = SkShader::CreateBitmapShader(bitmap,
298                                                     SkShader::kRepeat_TileMode,
299                                                     SkShader::kRepeat_TileMode);
300     paint.setShader(shader)->unref();
301     // now paint is the only owner of shader
302     paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
303     paint.setFilterBitmap(true);
304     fixPaintForBitmapsThatMaySeam(&paint);
305 
306     SkMatrix matrix(patternTransform);
307 
308     if (imageIsSubSampled) {
309         matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY));
310     }
311     // We also need to translate it such that the origin of the pattern is the
312     // origin of the destination rect, which is what WebKit expects. Skia uses
313     // the coordinate system origin as the base for the patter. If WebKit wants
314     // a shifted image, it will shift it from there using the patternTransform.
315     float tx = phase.x() + srcRect.x() * patternTransform.a();
316     float ty = phase.y() + srcRect.y() * patternTransform.d();
317     matrix.postTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty));
318     shader->setLocalMatrix(matrix);
319 #if 0
320     SkDebugf("--- drawPattern: src [%g %g %g %g] dst [%g %g %g %g] transform [%g %g %g %g %g %g] matrix [%g %g %g %g %g %g]\n",
321              srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(),
322              destRect.x(), destRect.y(), destRect.width(), destRect.height(),
323              patternTransform.a(), patternTransform.b(), patternTransform.c(),
324              patternTransform.d(), patternTransform.e(), patternTransform.f(),
325              matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
326 #endif
327     canvas->drawRect(dstR, paint);
328 
329 #ifdef TRACE_SUBSAMPLED_BITMAPS
330     if (bitmap.width() != image->origWidth() ||
331         bitmap.height() != image->origHeight()) {
332         SkDebugf("--- Image::drawPattern [%d %d] orig [%d %d] dst [%g %g]\n",
333                  bitmap.width(), bitmap.height(),
334                  image->origWidth(), image->origHeight(),
335                  SkScalarToFloat(dstR.width()), SkScalarToFloat(dstR.height()));
336     }
337 #endif
338 }
339 
340 // missingImage, textAreaResizeCorner
loadPlatformResource(const char * name)341 PassRefPtr<Image> Image::loadPlatformResource(const char *name)
342 {
343     android::AssetManager* am = globalAssetManager();
344 
345     SkString path("webkit/");
346     path.append(name);
347     path.append(".png");
348 
349     android::Asset* a = am->open(path.c_str(),
350                                  android::Asset::ACCESS_BUFFER);
351     if (a == NULL) {
352         SkDebugf("---------------- failed to open image asset %s\n", name);
353         return NULL;
354     }
355 
356     SkAutoTDelete<android::Asset> ad(a);
357 
358     SkBitmap bm;
359     if (SkImageDecoder::DecodeMemory(a->getBuffer(false), a->getLength(), &bm)) {
360         SkBitmapRef* ref = new SkBitmapRef(bm);
361         // create will call ref(), so we need aur() to release ours upon return
362         SkAutoUnref aur(ref);
363         return BitmapImage::create(ref, 0);
364     }
365     return Image::nullImage();
366 }
367 
368 }   // namespace
369 
370