OSDN Git Service

AI 143477: respect the srcRect parameter in drawPattern, so we can correctly show...
[android-x86/external-webkit.git] / WebCore / platform / graphics / android / ImageAndroid.cpp
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
46 #include <utils/AssetManager.h>
47
48 //#define TRACE_SUBSAMPLED_BITMAPS
49 //#define TRACE_SKIPPED_BITMAPS
50
51 android::AssetManager* globalAssetManager() {
52     static android::AssetManager* gGlobalAssetMgr;
53     if (!gGlobalAssetMgr) {
54         gGlobalAssetMgr = new android::AssetManager();
55         gGlobalAssetMgr->addDefaultAssets();
56     }
57     return gGlobalAssetMgr;
58 }
59
60 namespace WebCore {
61     
62 bool FrameData::clear(bool clearMetadata)
63 {
64     if (clearMetadata)
65         m_haveMetadata = false;
66
67     if (m_frame) {
68         m_frame->unref();
69         m_frame = 0;
70         return true;
71     }
72     return false;
73 }
74
75 BitmapImage::BitmapImage(SkBitmapRef* ref, ImageObserver* observer)
76     : Image(observer)
77     , m_currentFrame(0)
78     , m_frames(0)
79     , m_frameTimer(0)
80     , m_repetitionCount(0)
81     , m_repetitionsComplete(0)
82     , m_isSolidColor(false)
83     , m_animationFinished(true)
84     , m_allDataReceived(true)
85     , m_haveSize(true)
86     , m_sizeAvailable(true)
87     , m_decodedSize(0)
88     , m_haveFrameCount(true)
89     , m_frameCount(1)
90 {
91     initPlatformData();
92     
93     m_size = IntSize(ref->bitmap().width(), ref->bitmap().height());
94     
95     m_frames.grow(1);
96     m_frames[0].m_frame = ref;
97     m_frames[0].m_hasAlpha = !ref->bitmap().isOpaque();
98     checkForSolidColor();
99     ref->ref();
100 }
101
102
103 void BitmapImage::initPlatformData()
104 {
105     m_source.clearURL();
106 }
107
108 void BitmapImage::invalidatePlatformData()
109 {
110 }
111
112 void BitmapImage::checkForSolidColor()
113 {
114     m_isSolidColor = false;
115     if (frameCount() == 1) {
116         SkBitmapRef* ref = frameAtIndex(0);
117         if (!ref) {
118             return; // keep solid == false
119         }
120         
121         const SkBitmap& bm = ref->bitmap();
122         if (bm.width() != 1 || bm.height() != 1) {
123             return;  // keep solid == false
124         }
125         
126         SkAutoLockPixels alp(bm);
127         if (!bm.readyToDraw()) {
128             return;  // keep solid == false
129         }
130
131         SkPMColor color;
132         switch (bm.getConfig()) {
133             case SkBitmap::kARGB_8888_Config:
134                 color = *bm.getAddr32(0, 0);
135                 break;
136             case SkBitmap::kRGB_565_Config:
137                 color = SkPixel16ToPixel32(*bm.getAddr16(0, 0));
138                 break;
139             case SkBitmap::kIndex8_Config: {
140                 SkColorTable* ctable = bm.getColorTable();
141                 if (!ctable) {
142                 return;
143                 }
144                 color = (*ctable)[*bm.getAddr8(0, 0)];
145                 break;
146             }
147             default:
148                 return;  // keep solid == false
149         }
150         m_isSolidColor = true;
151         m_solidColor = android_SkPMColorToWebCoreColor(color);
152     }
153 }
154
155 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
156                        const FloatRect& srcRect, CompositeOperator compositeOp)
157 {
158     startAnimation();
159
160     SkBitmapRef* image = this->nativeImageForCurrentFrame();
161     if (!image) { // If it's too early we won't have an image yet.
162         return;
163     }
164
165     // in case we get called with an incomplete bitmap
166     const SkBitmap& bitmap = image->bitmap();
167     if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
168 #ifdef TRACE_SKIPPED_BITMAPS
169         SkDebugf("----- skip bitmapimage: [%d %d] pixels %p pixelref %p\n",
170                  bitmap.width(), bitmap.height(),
171                  bitmap.getPixels(), bitmap.pixelRef());
172 #endif
173         return;
174     }
175
176     SkIRect srcR;
177     SkRect  dstR;    
178     float invScaleX = (float)bitmap.width() / image->origWidth();
179     float invScaleY = (float)bitmap.height() / image->origHeight();
180
181     android_setrect(&dstR, dstRect);
182     android_setrect_scaled(&srcR, srcRect, invScaleX, invScaleY);
183     if (srcR.isEmpty() || dstR.isEmpty()) {
184 #ifdef TRACE_SKIPPED_BITMAPS
185         SkDebugf("----- skip bitmapimage: [%d %d] src-empty %d dst-empty %d\n",
186                  bitmap.width(), bitmap.height(),
187                  srcR.isEmpty(), dstR.isEmpty());
188 #endif
189         return;
190     }
191
192     SkCanvas*   canvas = ctxt->platformContext()->mCanvas;
193     SkPaint     paint;
194
195     paint.setFilterBitmap(true);
196     paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
197     canvas->drawBitmapRect(bitmap, &srcR, dstR, &paint);
198
199 #ifdef TRACE_SUBSAMPLED_BITMAPS
200     if (bitmap.width() != image->origWidth() ||
201         bitmap.height() != image->origHeight()) {
202         SkDebugf("--- BitmapImage::draw [%d %d] orig [%d %d]\n",
203                  bitmap.width(), bitmap.height(),
204                  image->origWidth(), image->origHeight());
205     }
206 #endif
207 }
208
209 void BitmapImage::setURL(const String& str) 
210 {
211     m_source.setURL(str);
212 }
213
214 ///////////////////////////////////////////////////////////////////////////////
215
216 void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect,
217                         const TransformationMatrix& patternTransform,
218                         const FloatPoint& phase, CompositeOperator compositeOp,
219                         const FloatRect& destRect)
220 {
221     SkBitmapRef* image = this->nativeImageForCurrentFrame();
222     if (!image) { // If it's too early we won't have an image yet.
223         return;
224     }
225     
226     // in case we get called with an incomplete bitmap
227     const SkBitmap& origBitmap = image->bitmap();
228     if (origBitmap.getPixels() == NULL && origBitmap.pixelRef() == NULL) {
229         return;
230     }
231     
232     SkRect  dstR;    
233     android_setrect(&dstR, destRect);
234     if (dstR.isEmpty()) {
235         return;
236     }
237
238     // now extract the proper subset of the src image
239     SkBitmap bitmap;
240     SkIRect srcR;
241     if (!origBitmap.extractSubset(&bitmap, *android_setrect(&srcR, srcRect))) {
242         SkDebugf("--- Image::drawPattern calling extractSubset failed\n");
243         return;
244     }
245
246     SkCanvas*   canvas = ctxt->platformContext()->mCanvas;
247     SkPaint     paint;
248     
249     SkShader* shader = SkShader::CreateBitmapShader(bitmap,
250                                                     SkShader::kRepeat_TileMode,
251                                                     SkShader::kRepeat_TileMode);
252     paint.setShader(shader)->unref();
253     // now paint is the only owner of shader
254     paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
255     paint.setFilterBitmap(true);
256     
257     SkMatrix matrix(patternTransform);
258     
259     float scaleX = (float)image->origWidth() / bitmap.width();
260     float scaleY = (float)image->origHeight() / bitmap.height();
261     matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY));
262     
263     matrix.postTranslate(SkFloatToScalar(phase.x()),
264                          SkFloatToScalar(phase.y()));
265     shader->setLocalMatrix(matrix);
266     canvas->drawRect(dstR, paint);
267     
268 #ifdef TRACE_SUBSAMPLED_BITMAPS
269     if (bitmap.width() != image->origWidth() ||
270         bitmap.height() != image->origHeight()) {
271         SkDebugf("--- Image::drawPattern [%d %d] orig [%d %d] dst [%g %g]\n",
272                  bitmap.width(), bitmap.height(),
273                  image->origWidth(), image->origHeight(),
274                  SkScalarToFloat(dstR.width()), SkScalarToFloat(dstR.height()));
275     }
276 #endif
277 }
278
279 // missingImage, textAreaResizeCorner
280 PassRefPtr<Image> Image::loadPlatformResource(const char *name)
281 {
282     android::AssetManager* am = globalAssetManager();
283     
284     SkString path("webkit/");
285     path.append(name);
286     path.append(".png");
287     
288     android::Asset* a = am->open(path.c_str(),
289                                  android::Asset::ACCESS_BUFFER);
290     if (a == NULL) {
291         SkDebugf("---------------- failed to open image asset %s\n", name);
292         return NULL;
293     }
294     
295     SkAutoTDelete<android::Asset> ad(a);
296
297     SkBitmap bm;
298     if (SkImageDecoder::DecodeMemory(a->getBuffer(false), a->getLength(), &bm)) {
299         SkBitmapRef* ref = new SkBitmapRef(bm);
300         // create will call ref(), so we need aur() to release ours upon return
301         SkAutoUnref aur(ref);
302         return BitmapImage::create(ref, 0);
303     }
304     return Image::nullImage();
305 }
306
307 }   // namespace
308