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 "GraphicsContext.h" 25#include "Image.h" 26#include "ImageData.h" 27#include "NotImplemented.h" 28#include "SharedBitmap.h" 29 30namespace WebCore { 31 32class BufferedImage: public Image { 33 34public: 35 BufferedImage(const ImageBufferData* data) 36 : m_data(data) 37 { 38 } 39 40 virtual bool currentFrameKnownToBeOpaque() { return !m_data->m_bitmap->hasAlpha() ; } 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, ColorSpace styleColorSpace, CompositeOperator, BlendMode, ImageOrientationDescription); 45 virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform, 46 const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); 47 48 const ImageBufferData* m_data; 49}; 50 51void BufferedImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription) 52{ 53 IntRect intDstRect = enclosingIntRect(dstRect); 54 IntRect intSrcRect(srcRect); 55 m_data->m_bitmap->draw(ctxt, intDstRect, intSrcRect, styleColorSpace, compositeOp, blendMode); 56} 57 58void BufferedImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform, 59 const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, BlendMode) 60{ 61 m_data->m_bitmap->drawPattern(ctxt, tileRectIn, patternTransform, phase, styleColorSpace, op, destRect, size()); 62} 63 64ImageBufferData::ImageBufferData(const IntSize& size) 65 : m_bitmap(SharedBitmap::create(size, BitmapInfo::BitCount32, 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 73ImageBuffer::ImageBuffer(const IntSize& size, float resolutionScale, ColorSpace colorSpace, RenderingMode, bool& success) 74 : m_data(size) 75 , m_size(size) 76 , m_logicalSize(size) 77{ 78 // FIXME: Respect resoutionScale to support high-DPI canvas. 79 UNUSED_PARAM(resolutionScale); 80 // FIXME: colorSpace is not used 81 UNUSED_PARAM(colorSpace); 82 83 m_context = adoptPtr(new GraphicsContext(0)); 84 m_context->setBitmap(m_data.m_bitmap); 85 success = true; 86} 87 88ImageBuffer::~ImageBuffer() 89{ 90} 91 92GraphicsContext* ImageBuffer::context() const 93{ 94 return m_context.get(); 95} 96 97PassRefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior) const 98{ 99 ASSERT(copyBehavior == CopyBackingStore); 100 return adoptRef(new BufferedImage(&m_data)); 101} 102 103BackingStoreCopy ImageBuffer::fastCopyImageMode() 104{ 105 return CopyBackingStore; 106} 107 108void ImageBuffer::clip(GraphicsContext*, const FloatRect&) const 109{ 110 notImplemented(); 111} 112 113void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, 114 CompositeOperator op, BlendMode blendMode, bool useLowQualityScale) 115{ 116 RefPtr<Image> imageCopy = copyImage(CopyBackingStore); 117 context->drawImage(imageCopy.get(), styleColorSpace, destRect, srcRect, op, blendMode, ImageOrientationDescription(), useLowQualityScale); 118} 119 120void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, 121 const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) 122{ 123 RefPtr<Image> imageCopy = copyImage(CopyBackingStore); 124 imageCopy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); 125} 126 127template <bool premultiplied> 128static PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const SharedBitmap* bitmap) 129{ 130 RefPtr<Uint8ClampedArray> imageData = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4); 131 132 const unsigned char* src = static_cast<const unsigned char*>(bitmap->bytes()); 133 if (!src) 134 return imageData.release(); 135 136 IntRect sourceRect(0, 0, bitmap->width(), bitmap->height()); 137 sourceRect.intersect(rect); 138 if (sourceRect.isEmpty()) 139 return imageData.release(); 140 141 unsigned char* dst = imageData->data(); 142 imageData->zeroFill(); 143 src += (sourceRect.y() * bitmap->width() + sourceRect.x()) * 4; 144 dst += ((sourceRect.y() - rect.y()) * rect.width() + sourceRect.x() - rect.x()) * 4; 145 int bytesToCopy = sourceRect.width() * 4; 146 int srcSkip = (bitmap->width() - sourceRect.width()) * 4; 147 int dstSkip = (rect.width() - sourceRect.width()) * 4; 148 const unsigned char* dstEnd = dst + sourceRect.height() * rect.width() * 4; 149 while (dst < dstEnd) { 150 const unsigned char* dstRowEnd = dst + bytesToCopy; 151 while (dst < dstRowEnd) { 152 // Convert ARGB little endian to RGBA big endian 153 int blue = *src++; 154 int green = *src++; 155 int red = *src++; 156 int alpha = *src++; 157 if (premultiplied) { 158 *dst++ = static_cast<unsigned char>((red * alpha + 254) / 255); 159 *dst++ = static_cast<unsigned char>((green * alpha + 254) / 255); 160 *dst++ = static_cast<unsigned char>((blue * alpha + 254) / 255); 161 *dst++ = static_cast<unsigned char>(alpha); 162 } else { 163 *dst++ = static_cast<unsigned char>(red); 164 *dst++ = static_cast<unsigned char>(green); 165 *dst++ = static_cast<unsigned char>(blue); 166 *dst++ = static_cast<unsigned char>(alpha); 167 ++src; 168 } 169 } 170 src += srcSkip; 171 dst += dstSkip; 172 } 173 174 return imageData.release(); 175} 176 177PassRefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem) const 178{ 179 return getImageData<false>(rect, m_data.m_bitmap.get()); 180} 181 182PassRefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem) const 183{ 184 return getImageData<true>(rect, m_data.m_bitmap.get()); 185} 186 187void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem) 188{ 189 SharedBitmap* bitmap = m_data.m_bitmap.get(); 190 unsigned char* dst = (unsigned char*)bitmap->bytes(); 191 if (!dst) 192 return; 193 194 IntRect destRect(destPoint, sourceRect.size()); 195 destRect.intersect(IntRect(0, 0, bitmap->width(), bitmap->height())); 196 197 if (destRect.isEmpty()) 198 return; 199 200 const unsigned char* src = source->data(); 201 dst += (destRect.y() * bitmap->width() + destRect.x()) * 4; 202 src += (sourceRect.y() * sourceSize.width() + sourceRect.x()) * 4; 203 int bytesToCopy = destRect.width() * 4; 204 int dstSkip = (bitmap->width() - destRect.width()) * 4; 205 int srcSkip = (sourceSize.width() - destRect.width()) * 4; 206 const unsigned char* dstEnd = dst + destRect.height() * bitmap->width() * 4; 207 while (dst < dstEnd) { 208 const unsigned char* dstRowEnd = dst + bytesToCopy; 209 while (dst < dstRowEnd) { 210 // Convert RGBA big endian to ARGB little endian 211 int red = *src++; 212 int green = *src++; 213 int blue = *src++; 214 int alpha = *src++; 215 if (multiplied == Premultiplied) { 216 *dst++ = static_cast<unsigned char>(blue * 255 / alpha); 217 *dst++ = static_cast<unsigned char>(green * 255 / alpha); 218 *dst++ = static_cast<unsigned char>(red * 255 / alpha); 219 *dst++ = static_cast<unsigned char>(alpha); 220 } else { 221 *dst++ = static_cast<unsigned char>(blue); 222 *dst++ = static_cast<unsigned char>(green); 223 *dst++ = static_cast<unsigned char>(red); 224 *dst++ = static_cast<unsigned char>(alpha); 225 } 226 } 227 src += srcSkip; 228 dst += dstSkip; 229 } 230} 231 232void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) 233{ 234 UNUSED_PARAM(lookUpTable); 235 notImplemented(); 236} 237 238String ImageBuffer::toDataURL(const String& mimeType, const double*, CoordinateSystem) const 239{ 240 if (!m_data.m_bitmap->bytes()) 241 return "data:,"; 242 243 notImplemented(); 244 return String(); 245} 246 247} // namespace WebCore 248