Home | History | Annotate | Download | only in android
      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 THE COPYRIGHT OWNER 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 "BitmapImage.h"
     28 #include "ImageBuffer.h"
     29 #include "ImageData.h"
     30 #include "NotImplemented.h"
     31 
     32 #include "android_graphics.h"
     33 #include "GraphicsContext.h"
     34 #include "PlatformGraphicsContext.h"
     35 #include "SkBitmapRef.h"
     36 #include "SkCanvas.h"
     37 #include "SkColorPriv.h"
     38 #include "SkDevice.h"
     39 #include "SkUnPreMultiply.h"
     40 
     41 using namespace std;
     42 
     43 namespace WebCore {
     44 
     45 ImageBufferData::ImageBufferData(const IntSize&)
     46 {
     47 }
     48 
     49 ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace colorSpace, bool& success)
     50     : m_data(size)
     51     , m_size(size)
     52 {
     53     m_context.set(GraphicsContext::createOffscreenContext(size.width(), size.height()));
     54     success = true;
     55 }
     56 
     57 ImageBuffer::~ImageBuffer()
     58 {
     59 }
     60 
     61 GraphicsContext* ImageBuffer::context() const
     62 {
     63     return m_context.get();
     64 }
     65 
     66 /*  This guy needs to make a deep copy of the bitmap, so that the returned
     67     image doesn't reflect any subsequent changes to the canvas' backend.
     68     e.g. this is called when <canvas> wants to make a Pattern, which needs
     69     to snapshot the current pixels when it is created.
     70  */
     71 Image* ImageBuffer::image() const
     72 {
     73     if (!m_image) {
     74         ASSERT(context());
     75         SkCanvas* canvas = context()->platformContext()->mCanvas;
     76         SkDevice* device = canvas->getDevice();
     77         const SkBitmap& orig = device->accessBitmap(false);
     78 
     79         SkBitmap copy;
     80         orig.copyTo(&copy, orig.config());
     81 
     82         SkBitmapRef* ref = new SkBitmapRef(copy);
     83         m_image = BitmapImage::create(ref, 0);
     84         ref->unref();
     85     }
     86     return m_image.get();
     87 }
     88 
     89 PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
     90 {
     91     GraphicsContext* gc = this->context();
     92     if (!gc) {
     93         return 0;
     94     }
     95 
     96     const SkBitmap& src = android_gc2canvas(gc)->getDevice()->accessBitmap(false);
     97     SkAutoLockPixels alp(src);
     98     if (!src.getPixels()) {
     99         return 0;
    100     }
    101 
    102     // ! Can't use PassRefPtr<>, otherwise the second access will cause crash.
    103     RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
    104     unsigned char* data = result->data()->data()->data();
    105 
    106     if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height())
    107         memset(data, 0, result->data()->length());
    108 
    109     int originx = rect.x();
    110     int destx = 0;
    111     if (originx < 0) {
    112         destx = -originx;
    113         originx = 0;
    114     }
    115     int endx = rect.x() + rect.width();
    116     if (endx > m_size.width())
    117         endx = m_size.width();
    118     int numColumns = endx - originx;
    119 
    120     int originy = rect.y();
    121     int desty = 0;
    122     if (originy < 0) {
    123         desty = -originy;
    124         originy = 0;
    125     }
    126     int endy = rect.y() + rect.height();
    127     if (endy > m_size.height())
    128         endy = m_size.height();
    129     int numRows = endy - originy;
    130 
    131     unsigned srcPixelsPerRow = src.rowBytesAsPixels();
    132     unsigned destBytesPerRow = 4 * rect.width();
    133 
    134     const SkPMColor* srcRows = src.getAddr32(originx, originy);
    135     unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
    136     for (int y = 0; y < numRows; ++y) {
    137         for (int x = 0; x < numColumns; x++) {
    138             // ugh, it appears they want unpremultiplied pixels
    139             SkColor c = SkUnPreMultiply::PMColorToColor(srcRows[x]);
    140             int basex = x * 4;
    141             destRows[basex + 0] = SkColorGetR(c);
    142             destRows[basex + 1] = SkColorGetG(c);
    143             destRows[basex + 2] = SkColorGetB(c);
    144             destRows[basex + 3] = SkColorGetA(c);
    145         }
    146         srcRows += srcPixelsPerRow;
    147         destRows += destBytesPerRow;
    148     }
    149     return result;
    150 }
    151 
    152 void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
    153 {
    154     GraphicsContext* gc = this->context();
    155     if (!gc) {
    156         return;
    157     }
    158 
    159     const SkBitmap& dst = android_gc2canvas(gc)->getDevice()->accessBitmap(true);
    160     SkAutoLockPixels alp(dst);
    161     if (!dst.getPixels()) {
    162         return;
    163     }
    164 
    165     ASSERT(sourceRect.width() > 0);
    166     ASSERT(sourceRect.height() > 0);
    167 
    168     int originx = sourceRect.x();
    169     int destx = destPoint.x() + sourceRect.x();
    170     ASSERT(destx >= 0);
    171     ASSERT(destx < m_size.width());
    172     ASSERT(originx >= 0);
    173     ASSERT(originx <= sourceRect.right());
    174 
    175     int endx = destPoint.x() + sourceRect.right();
    176     ASSERT(endx <= m_size.width());
    177 
    178     int numColumns = endx - destx;
    179 
    180     int originy = sourceRect.y();
    181     int desty = destPoint.y() + sourceRect.y();
    182     ASSERT(desty >= 0);
    183     ASSERT(desty < m_size.height());
    184     ASSERT(originy >= 0);
    185     ASSERT(originy <= sourceRect.bottom());
    186 
    187     int endy = destPoint.y() + sourceRect.bottom();
    188     ASSERT(endy <= m_size.height());
    189     int numRows = endy - desty;
    190 
    191     unsigned srcBytesPerRow = 4 * source->width();
    192     unsigned dstPixelsPerRow = dst.rowBytesAsPixels();
    193 
    194     unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
    195     SkPMColor* dstRows = dst.getAddr32(destx, desty);
    196     for (int y = 0; y < numRows; ++y) {
    197         for (int x = 0; x < numColumns; x++) {
    198             int basex = x * 4;
    199             dstRows[x] = SkPackARGB32(srcRows[basex + 3],
    200                                       srcRows[basex + 0],
    201                                       srcRows[basex + 1],
    202                                       srcRows[basex + 2]);
    203         }
    204         dstRows += dstPixelsPerRow;
    205         srcRows += srcBytesPerRow;
    206     }
    207 }
    208 
    209 
    210 String ImageBuffer::toDataURL(const String&) const
    211 {
    212     // leaving this unimplemented, until I understand what its for (and what it
    213     // really is).
    214     return "data:,";    // I think this means we couldn't make the data url
    215 }
    216 
    217 }
    218