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