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 "ImageBuffer.h"
     28 
     29 #include "Base64.h"
     30 #include "BitmapImage.h"
     31 #include "ColorSpace.h"
     32 #include "GraphicsContext.h"
     33 #include "NotImplemented.h"
     34 #include "PlatformBridge.h"
     35 #include "PlatformGraphicsContext.h"
     36 #include "PlatformGraphicsContextSkia.h"
     37 #include "SkBitmapRef.h"
     38 #include "SkCanvas.h"
     39 #include "SkColorPriv.h"
     40 #include "SkData.h"
     41 #include "SkDevice.h"
     42 #include "SkImageEncoder.h"
     43 #include "SkStream.h"
     44 #include "SkUnPreMultiply.h"
     45 
     46 using namespace std;
     47 
     48 namespace WebCore {
     49 
     50 SkCanvas* imageBufferCanvas(const ImageBuffer* buffer)
     51 {
     52     // We know that our PlatformGraphicsContext is a PlatformGraphicsContextSkia
     53     // because that is what we create in GraphicsContext::createOffscreenContext
     54     if (!buffer || !buffer->context())
     55         return 0;
     56     PlatformGraphicsContext* pc = buffer->context()->platformContext();
     57     return static_cast<PlatformGraphicsContextSkia*>(pc)->canvas();
     58 }
     59 
     60 ImageBufferData::ImageBufferData(const IntSize&)
     61 {
     62 }
     63 
     64 ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success)
     65     : m_data(size)
     66     , m_size(size)
     67 {
     68     // GraphicsContext creates a 32bpp SkBitmap, so 4 bytes per pixel.
     69     if (!PlatformBridge::canSatisfyMemoryAllocation(size.width() * size.height() * 4))
     70         success = false;
     71     else {
     72         m_context.set(GraphicsContext::createOffscreenContext(size.width(), size.height()));
     73         success = true;
     74     }
     75 }
     76 
     77 ImageBuffer::~ImageBuffer()
     78 {
     79 }
     80 
     81 GraphicsContext* ImageBuffer::context() const
     82 {
     83     return m_context.get();
     84 }
     85 
     86 bool ImageBuffer::drawsUsingCopy() const
     87 {
     88     return true;
     89 }
     90 
     91 PassRefPtr<Image> ImageBuffer::copyImage() const
     92 {
     93     ASSERT(context());
     94 
     95     SkCanvas* canvas = imageBufferCanvas(this);
     96     if (!canvas)
     97       return 0;
     98 
     99     SkDevice* device = canvas->getDevice();
    100     const SkBitmap& orig = device->accessBitmap(false);
    101 
    102     SkBitmap copy;
    103     if (PlatformBridge::canSatisfyMemoryAllocation(orig.getSize()))
    104         orig.copyTo(&copy, orig.config());
    105 
    106     SkBitmapRef* ref = new SkBitmapRef(copy);
    107     RefPtr<Image> image = BitmapImage::create(ref, 0);
    108     ref->unref();
    109     return image;
    110 }
    111 
    112 void ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const
    113 {
    114     SkDebugf("xxxxxxxxxxxxxxxxxx clip not implemented\n");
    115 }
    116 
    117 void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, bool useLowQualityScale)
    118 {
    119     RefPtr<Image> imageCopy = copyImage();
    120     context->drawImage(imageCopy.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
    121 }
    122 
    123 void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
    124 {
    125     RefPtr<Image> imageCopy = copyImage();
    126     imageCopy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
    127 }
    128 
    129 PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
    130 {
    131     GraphicsContext* gc = this->context();
    132     if (!gc) {
    133         return 0;
    134     }
    135 
    136     const SkBitmap& src = imageBufferCanvas(this)->getDevice()->accessBitmap(false);
    137     SkAutoLockPixels alp(src);
    138     if (!src.getPixels()) {
    139         return 0;
    140     }
    141 
    142     RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4);
    143     unsigned char* data = result->data();
    144 
    145     if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > m_size.width() || rect.maxY() > m_size.height())
    146         memset(data, 0, result->length());
    147 
    148     int originx = rect.x();
    149     int destx = 0;
    150     if (originx < 0) {
    151         destx = -originx;
    152         originx = 0;
    153     }
    154     int endx = rect.x() + rect.width();
    155     if (endx > m_size.width())
    156         endx = m_size.width();
    157     int numColumns = endx - originx;
    158 
    159     int originy = rect.y();
    160     int desty = 0;
    161     if (originy < 0) {
    162         desty = -originy;
    163         originy = 0;
    164     }
    165     int endy = rect.y() + rect.height();
    166     if (endy > m_size.height())
    167         endy = m_size.height();
    168     int numRows = endy - originy;
    169 
    170     unsigned srcPixelsPerRow = src.rowBytesAsPixels();
    171     unsigned destBytesPerRow = 4 * rect.width();
    172 
    173     const SkPMColor* srcRows = src.getAddr32(originx, originy);
    174     unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
    175     for (int y = 0; y < numRows; ++y) {
    176         for (int x = 0; x < numColumns; x++) {
    177             // ugh, it appears they want unpremultiplied pixels
    178             SkColor c = SkUnPreMultiply::PMColorToColor(srcRows[x]);
    179             int basex = x * 4;
    180             destRows[basex + 0] = SkColorGetR(c);
    181             destRows[basex + 1] = SkColorGetG(c);
    182             destRows[basex + 2] = SkColorGetB(c);
    183             destRows[basex + 3] = SkColorGetA(c);
    184         }
    185         srcRows += srcPixelsPerRow;
    186         destRows += destBytesPerRow;
    187     }
    188     return result.release();
    189 }
    190 
    191 void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
    192 {
    193     GraphicsContext* gc = this->context();
    194     if (!gc) {
    195         return;
    196     }
    197 
    198     const SkBitmap& dst = imageBufferCanvas(this)->getDevice()->accessBitmap(true);
    199     SkAutoLockPixels alp(dst);
    200     if (!dst.getPixels()) {
    201         return;
    202     }
    203 
    204     ASSERT(sourceRect.width() > 0);
    205     ASSERT(sourceRect.height() > 0);
    206 
    207     int originx = sourceRect.x();
    208     int destx = destPoint.x() + sourceRect.x();
    209     ASSERT(destx >= 0);
    210     ASSERT(destx < m_size.width());
    211     ASSERT(originx >= 0);
    212     ASSERT(originx <= sourceRect.maxX());
    213 
    214     int endx = destPoint.x() + sourceRect.maxX();
    215     ASSERT(endx <= m_size.width());
    216 
    217     int numColumns = endx - destx;
    218 
    219     int originy = sourceRect.y();
    220     int desty = destPoint.y() + sourceRect.y();
    221     ASSERT(desty >= 0);
    222     ASSERT(desty < m_size.height());
    223     ASSERT(originy >= 0);
    224     ASSERT(originy <= sourceRect.maxY());
    225 
    226     int endy = destPoint.y() + sourceRect.maxY();
    227     ASSERT(endy <= m_size.height());
    228     int numRows = endy - desty;
    229 
    230     unsigned srcBytesPerRow = 4 * sourceSize.width();
    231     unsigned dstPixelsPerRow = dst.rowBytesAsPixels();
    232 
    233     unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4;
    234     SkPMColor* dstRows = dst.getAddr32(destx, desty);
    235     for (int y = 0; y < numRows; ++y) {
    236         for (int x = 0; x < numColumns; x++) {
    237             int basex = x * 4;
    238             dstRows[x] = SkPackARGB32(srcRows[basex + 3],
    239                                       srcRows[basex + 0],
    240                                       srcRows[basex + 1],
    241                                       srcRows[basex + 2]);
    242         }
    243         dstRows += dstPixelsPerRow;
    244         srcRows += srcBytesPerRow;
    245     }
    246 }
    247 
    248 
    249 String ImageBuffer::toDataURL(const String&, const double*) const
    250 {
    251     // Encode the image into a vector.
    252     SkDynamicMemoryWStream pngStream;
    253     const SkBitmap& dst = imageBufferCanvas(this)->getDevice()->accessBitmap(true);
    254     SkImageEncoder::EncodeStream(&pngStream, dst, SkImageEncoder::kPNG_Type, 100);
    255 
    256     // Convert it into base64.
    257     Vector<char> pngEncodedData;
    258     SkData* streamData = pngStream.copyToData();
    259     pngEncodedData.append((char*)streamData->data(), streamData->size());
    260     streamData->unref();
    261     Vector<char> base64EncodedData;
    262     base64Encode(pngEncodedData, base64EncodedData);
    263     // Append with a \0 so that it's a valid string.
    264     base64EncodedData.append('\0');
    265 
    266     // And the resulting string.
    267     return String::format("data:image/png;base64,%s", base64EncodedData.data());
    268 }
    269 
    270 void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookupTable)
    271 {
    272     notImplemented();
    273 }
    274 
    275 size_t ImageBuffer::dataSize() const
    276 {
    277     return m_size.width() * m_size.height() * 4;
    278 }
    279 
    280 }
    281