Home | History | Annotate | Download | only in android
      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 "SkBitmapRef.h"
     38 #include "SkCanvas.h"
     39 #include "SkColorPriv.h"
     40 #include "SkImageDecoder.h"
     41 #include "SkShader.h"
     42 #include "SkString.h"
     43 #include "SkTemplates.h"
     44 #include "SkiaUtils.h"
     45 
     46 #include <androidfw/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_repetitionCountStatus(Unknown)
     82     , m_repetitionsComplete(0)
     83     , m_isSolidColor(false)
     84     , m_animationFinished(true)
     85     , m_allDataReceived(true)
     86     , m_haveSize(true)
     87     , m_sizeAvailable(true)
     88     , m_decodedSize(0)
     89     , m_haveFrameCount(true)
     90     , m_frameCount(1)
     91 {
     92     initPlatformData();
     93 
     94     m_size = IntSize(ref->bitmap().width(), ref->bitmap().height());
     95 
     96     m_frames.grow(1);
     97     m_frames[0].m_frame = ref;
     98     m_frames[0].m_hasAlpha = !ref->bitmap().isOpaque();
     99     checkForSolidColor();
    100     ref->ref();
    101 }
    102 
    103 
    104 void BitmapImage::initPlatformData()
    105 {
    106     m_source.clearURL();
    107 }
    108 
    109 void BitmapImage::invalidatePlatformData()
    110 {
    111 }
    112 
    113 void BitmapImage::checkForSolidColor()
    114 {
    115     m_checkedForSolidColor = true;
    116     m_isSolidColor = false;
    117     if (frameCount() == 1) {
    118         SkBitmapRef* ref = frameAtIndex(0);
    119         if (!ref) {
    120             return; // keep solid == false
    121         }
    122 
    123         const SkBitmap& bm = ref->bitmap();
    124         if (bm.width() != 1 || bm.height() != 1) {
    125             return;  // keep solid == false
    126         }
    127 
    128         SkAutoLockPixels alp(bm);
    129         if (!bm.readyToDraw()) {
    130             return;  // keep solid == false
    131         }
    132 
    133         SkPMColor color;
    134         switch (bm.getConfig()) {
    135             case SkBitmap::kARGB_8888_Config:
    136                 color = *bm.getAddr32(0, 0);
    137                 break;
    138             case SkBitmap::kRGB_565_Config:
    139                 color = SkPixel16ToPixel32(*bm.getAddr16(0, 0));
    140                 break;
    141             case SkBitmap::kIndex8_Config: {
    142                 SkColorTable* ctable = bm.getColorTable();
    143                 if (!ctable) {
    144                 return;
    145                 }
    146                 color = (*ctable)[*bm.getAddr8(0, 0)];
    147                 break;
    148             }
    149             default:
    150                 return;  // keep solid == false
    151         }
    152         m_isSolidColor = true;
    153         m_solidColor = SkPMColorToWebCoreColor(color);
    154     }
    155 }
    156 
    157 static void round(SkIRect* dst, const WebCore::FloatRect& src)
    158 {
    159     dst->set(SkScalarRound(SkFloatToScalar(src.x())),
    160              SkScalarRound(SkFloatToScalar(src.y())),
    161              SkScalarRound(SkFloatToScalar((src.x() + src.width()))),
    162              SkScalarRound(SkFloatToScalar((src.y() + src.height()))));
    163 }
    164 
    165 static void round_scaled(SkIRect* dst, const WebCore::FloatRect& src,
    166                          float sx, float sy)
    167 {
    168     dst->set(SkScalarRound(SkFloatToScalar(src.x() * sx)),
    169              SkScalarRound(SkFloatToScalar(src.y() * sy)),
    170              SkScalarRound(SkFloatToScalar((src.x() + src.width()) * sx)),
    171              SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
    172 }
    173 
    174 void BitmapImage::draw(GraphicsContext* gc, const FloatRect& dstRect,
    175                    const FloatRect& srcRect, ColorSpace,
    176                    CompositeOperator compositeOp)
    177 {
    178     startAnimation();
    179 
    180     SkBitmapRef* image = this->nativeImageForCurrentFrame();
    181     if (!image) { // If it's too early we won't have an image yet.
    182         return;
    183     }
    184 
    185     // in case we get called with an incomplete bitmap
    186     const SkBitmap& bitmap = image->bitmap();
    187     if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
    188 #ifdef TRACE_SKIPPED_BITMAPS
    189         SkDebugf("----- skip bitmapimage: [%d %d] pixels %p pixelref %p\n",
    190                  bitmap.width(), bitmap.height(),
    191                  bitmap.getPixels(), bitmap.pixelRef());
    192 #endif
    193         return;
    194     }
    195 
    196     SkIRect srcR;
    197     SkRect  dstR(dstRect);
    198     float invScaleX = (float)bitmap.width() / image->origWidth();
    199     float invScaleY = (float)bitmap.height() / image->origHeight();
    200 
    201     round_scaled(&srcR, srcRect, invScaleX, invScaleY);
    202     if (srcR.isEmpty() || dstR.isEmpty()) {
    203 #ifdef TRACE_SKIPPED_BITMAPS
    204         SkDebugf("----- skip bitmapimage: [%d %d] src-empty %d dst-empty %d\n",
    205                  bitmap.width(), bitmap.height(),
    206                  srcR.isEmpty(), dstR.isEmpty());
    207 #endif
    208         return;
    209     }
    210 
    211     gc->platformContext()->drawBitmapRect(bitmap, &srcR, dstR, compositeOp);
    212 
    213 #ifdef TRACE_SUBSAMPLED_BITMAPS
    214     if (bitmap.width() != image->origWidth() ||
    215         bitmap.height() != image->origHeight()) {
    216         SkDebugf("--- BitmapImage::draw [%d %d] orig [%d %d]\n",
    217                  bitmap.width(), bitmap.height(),
    218                  image->origWidth(), image->origHeight());
    219     }
    220 #endif
    221 }
    222 
    223 void BitmapImage::setURL(const String& str)
    224 {
    225     m_source.setURL(str);
    226 }
    227 
    228 ///////////////////////////////////////////////////////////////////////////////
    229 
    230 void Image::drawPattern(GraphicsContext* gc, const FloatRect& srcRect,
    231                         const AffineTransform& patternTransform,
    232                         const FloatPoint& phase, ColorSpace,
    233                         CompositeOperator compositeOp, const FloatRect& destRect)
    234 {
    235     SkBitmapRef* image = this->nativeImageForCurrentFrame();
    236     if (!image || destRect.isEmpty())
    237         return;
    238 
    239     // in case we get called with an incomplete bitmap
    240     const SkBitmap& origBitmap = image->bitmap();
    241     if (origBitmap.getPixels() == NULL && origBitmap.pixelRef() == NULL)
    242         return;
    243 
    244     SkIRect srcR;
    245     // we may have to scale if the image has been subsampled (so save RAM)
    246     bool imageIsSubSampled = image->origWidth() != origBitmap.width() ||
    247                              image->origHeight() != origBitmap.height();
    248     float scaleX = 1;
    249     float scaleY = 1;
    250     if (imageIsSubSampled) {
    251         scaleX = (float)image->origWidth() / origBitmap.width();
    252         scaleY = (float)image->origHeight() / origBitmap.height();
    253         round_scaled(&srcR, srcRect, 1 / scaleX, 1 / scaleY);
    254     } else
    255         round(&srcR, srcRect);
    256 
    257     // now extract the proper subset of the src image
    258     SkBitmap bitmap;
    259     if (!origBitmap.extractSubset(&bitmap, srcR)) {
    260         SkDebugf("--- Image::drawPattern calling extractSubset failed\n");
    261         return;
    262     }
    263 
    264     SkMatrix matrix(patternTransform);
    265 
    266     if (imageIsSubSampled) {
    267         matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY));
    268     }
    269     // We also need to translate it such that the origin of the pattern is the
    270     // origin of the destination rect, which is what WebKit expects. Skia uses
    271     // the coordinate system origin as the base for the patter. If WebKit wants
    272     // a shifted image, it will shift it from there using the patternTransform.
    273     float tx = phase.x() + srcRect.x() * patternTransform.a();
    274     float ty = phase.y() + srcRect.y() * patternTransform.d();
    275     matrix.postTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty));
    276 
    277     gc->platformContext()->drawBitmapPattern(bitmap, matrix, compositeOp, destRect);
    278 }
    279 
    280 // missingImage, textAreaResizeCorner
    281 PassRefPtr<Image> Image::loadPlatformResource(const char *name)
    282 {
    283     android::AssetManager* am = globalAssetManager();
    284 
    285     SkString path("webkit/");
    286     path.append(name);
    287     path.append(".png");
    288 
    289     android::Asset* a = am->open(path.c_str(),
    290                                  android::Asset::ACCESS_BUFFER);
    291     if (a == NULL) {
    292         SkDebugf("---------------- failed to open image asset %s\n", name);
    293         return NULL;
    294     }
    295 
    296     SkAutoTDelete<android::Asset> ad(a);
    297 
    298     SkBitmap bm;
    299     if (SkImageDecoder::DecodeMemory(a->getBuffer(false), a->getLength(), &bm)) {
    300         SkBitmapRef* ref = new SkBitmapRef(bm);
    301         // create will call ref(), so we need aur() to release ours upon return
    302         SkAutoUnref aur(ref);
    303         return BitmapImage::create(ref, 0);
    304     }
    305     return Image::nullImage();
    306 }
    307 
    308 }   // namespace
    309