Home | History | Annotate | Download | only in wince
      1 /*
      2  * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
      3  *
      4  *  This library is free software; you can redistribute it and/or
      5  *  modify it under the terms of the GNU Library General Public
      6  *  License as published by the Free Software Foundation; either
      7  *  version 2 of the License, or (at your option) any later version.
      8  *
      9  *  This library is distributed in the hope that it will be useful,
     10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  *  Library General Public License for more details.
     13  *
     14  *  You should have received a copy of the GNU Library General Public License
     15  *  along with this library; see the file COPYING.LIB.  If not, write to
     16  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  *  Boston, MA 02110-1301, USA.
     18  */
     19 
     20 #include "config.h"
     21 #include "ImageBuffer.h"
     22 
     23 #include "Base64.h"
     24 #include "GraphicsContext.h"
     25 #include "Image.h"
     26 #include "ImageData.h"
     27 #include "JPEGEncoder.h"
     28 #include "PNGEncoder.h"
     29 #include "SharedBitmap.h"
     30 
     31 namespace WebCore {
     32 
     33 class BufferedImage: public Image {
     34 
     35 public:
     36     BufferedImage(const ImageBufferData* data)
     37         : m_data(data)
     38     {
     39     }
     40 
     41     virtual IntSize size() const { return IntSize(m_data->m_bitmap->width(), m_data->m_bitmap->height()); }
     42     virtual void destroyDecodedData(bool destroyAll = true) {}
     43     virtual unsigned decodedSize() const { return 0; }
     44     virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
     45     virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
     46                              const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
     47 
     48     const ImageBufferData* m_data;
     49 };
     50 
     51 void BufferedImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp)
     52 {
     53     IntRect intDstRect = enclosingIntRect(dstRect);
     54     IntRect intSrcRect(srcRect);
     55     m_data->m_bitmap->draw(ctxt, intDstRect, intSrcRect, compositeOp);
     56 }
     57 
     58 void BufferedImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
     59                              const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
     60 {
     61     m_data->m_bitmap->drawPattern(ctxt, tileRectIn, patternTransform, phase, op, destRect, size());
     62 }
     63 
     64 ImageBufferData::ImageBufferData(const IntSize& size)
     65 : m_bitmap(SharedBitmap::createInstance(false, size.width(), size.height(), false))
     66 {
     67     // http://www.w3.org/TR/2009/WD-html5-20090212/the-canvas-element.html#canvaspixelarray
     68     // "When the canvas is initialized it must be set to fully transparent black."
     69     m_bitmap->resetPixels(true);
     70     m_bitmap->setHasAlpha(true);
     71 }
     72 
     73 ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace colorSpace, bool& success)
     74     : m_data(size)
     75     , m_size(size)
     76 {
     77     // FIXME: colorSpace is not used
     78     UNUSED_PARAM(colorSpace);
     79 
     80     m_context.set(new GraphicsContext(0));
     81     m_context->setBitmap(m_data.m_bitmap);
     82     success = true;
     83 }
     84 
     85 ImageBuffer::~ImageBuffer()
     86 {
     87 }
     88 
     89 GraphicsContext* ImageBuffer::context() const
     90 {
     91     return m_context.get();
     92 }
     93 
     94 Image* ImageBuffer::image() const
     95 {
     96     if (!m_image)
     97         m_image = adoptRef(new BufferedImage(&m_data));
     98 
     99     return m_image.get();
    100 }
    101 
    102 template <bool premultiplied> PassRefPtr<ImageData>
    103 static getImageData(const IntRect& rect, const SharedBitmap* bitmap)
    104 {
    105     PassRefPtr<ImageData> imageData = ImageData::create(rect.width(), rect.height());
    106 
    107     const unsigned char* src = static_cast<const unsigned char*>(bitmap->bytes());
    108     if (!src)
    109         return imageData;
    110 
    111     IntRect sourceRect(0, 0, bitmap->width(), bitmap->height());
    112     sourceRect.intersect(rect);
    113     if (sourceRect.isEmpty())
    114         return imageData;
    115 
    116     unsigned char* dst = imageData->data()->data()->data();
    117     memset(dst, 0, imageData->data()->data()->length());
    118     src += (sourceRect.y() * bitmap->width() + sourceRect.x()) * 4;
    119     dst += ((sourceRect.y() - rect.y()) * imageData->width() + sourceRect.x() - rect.x()) * 4;
    120     int bytesToCopy = sourceRect.width() * 4;
    121     int srcSkip = (bitmap->width() - sourceRect.width()) * 4;
    122     int dstSkip = (imageData->width() - sourceRect.width()) * 4;
    123     const unsigned char* dstEnd = dst + sourceRect.height() * imageData->width() * 4;
    124     while (dst < dstEnd) {
    125         const unsigned char* dstRowEnd = dst + bytesToCopy;
    126         while (dst < dstRowEnd) {
    127             // Convert ARGB little endian to RGBA big endian
    128             int blue = *src++;
    129             int green = *src++;
    130             int red = *src++;
    131             int alpha = *src++;
    132             if (premultiplied) {
    133                 *dst++ = static_cast<unsigned char>((red * alpha + 254) / 255);
    134                 *dst++ = static_cast<unsigned char>((green * alpha + 254) / 255);
    135                 *dst++ = static_cast<unsigned char>((blue * alpha + 254) / 255);
    136                 *dst++ = static_cast<unsigned char>(alpha);
    137             } else {
    138                 *dst++ = static_cast<unsigned char>(red);
    139                 *dst++ = static_cast<unsigned char>(green);
    140                 *dst++ = static_cast<unsigned char>(blue);
    141                 *dst++ = static_cast<unsigned char>(alpha);
    142                 ++src;
    143             }
    144         }
    145         src += srcSkip;
    146         dst += dstSkip;
    147     }
    148 
    149     return imageData;
    150 }
    151 
    152 PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
    153 {
    154     return getImageData<false>(rect, m_data.m_bitmap.get());
    155 }
    156 
    157 PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
    158 {
    159     return getImageData<true>(rect, m_data.m_bitmap.get());
    160 }
    161 
    162 template <bool premultiplied>
    163 static void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint, SharedBitmap* bitmap)
    164 {
    165     unsigned char* dst = (unsigned char*)bitmap->bytes();
    166     if (!dst)
    167         return;
    168 
    169     IntRect destRect(destPoint, sourceRect.size());
    170     destRect.intersect(IntRect(0, 0, bitmap->width(), bitmap->height()));
    171 
    172     if (destRect.isEmpty())
    173         return;
    174 
    175     const unsigned char* src = source->data()->data()->data();
    176     dst += (destRect.y() * bitmap->width() + destRect.x()) * 4;
    177     src += (sourceRect.y() * source->width() + sourceRect.x()) * 4;
    178     int bytesToCopy = destRect.width() * 4;
    179     int dstSkip = (bitmap->width() - destRect.width()) * 4;
    180     int srcSkip = (source->width() - destRect.width()) * 4;
    181     const unsigned char* dstEnd = dst + destRect.height() * bitmap->width() * 4;
    182     while (dst < dstEnd) {
    183         const unsigned char* dstRowEnd = dst + bytesToCopy;
    184         while (dst < dstRowEnd) {
    185             // Convert RGBA big endian to ARGB little endian
    186             int red = *src++;
    187             int green = *src++;
    188             int blue = *src++;
    189             int alpha = *src++;
    190             if (premultiplied) {
    191                 *dst++ = static_cast<unsigned char>(blue * 255 / alpha);
    192                 *dst++ = static_cast<unsigned char>(green * 255 / alpha);
    193                 *dst++ = static_cast<unsigned char>(red * 255 / alpha);
    194                 *dst++ = static_cast<unsigned char>(alpha);
    195             } else {
    196                 *dst++ = static_cast<unsigned char>(blue);
    197                 *dst++ = static_cast<unsigned char>(green);
    198                 *dst++ = static_cast<unsigned char>(red);
    199                 *dst++ = static_cast<unsigned char>(alpha);
    200             }
    201         }
    202         src += srcSkip;
    203         dst += dstSkip;
    204     }
    205 }
    206 
    207 void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
    208 {
    209     putImageData<false>(source, sourceRect, destPoint, m_data.m_bitmap.get());
    210 }
    211 
    212 void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
    213 {
    214     putImageData<true>(source, sourceRect, destPoint, m_data.m_bitmap.get());
    215 }
    216 
    217 String ImageBuffer::toDataURL(const String& mimeType) const
    218 {
    219     if (!m_data.m_bitmap->bytes())
    220         return "data:,";
    221 
    222     Vector<char> output;
    223     const char* header;
    224     if (mimeType.lower() == "image/png") {
    225         if (!compressBitmapToPng(m_data.m_bitmap.get(), output))
    226             return "data:,";
    227         header = "data:image/png;base64,";
    228     } else {
    229         if (!compressBitmapToJpeg(m_data.m_bitmap.get(), output))
    230             return "data:,";
    231         header = "data:image/jpeg;base64,";
    232     }
    233 
    234     Vector<char> base64;
    235     base64Encode(output, base64);
    236 
    237     output.clear();
    238 
    239     Vector<char> url;
    240     url.append(header, strlen(header));
    241     url.append(base64);
    242 
    243     return String(url.data(), url.size());
    244 }
    245 
    246 }
    247