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