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 "BitmapImage.h" 28 #include "ImageBuffer.h" 29 #include "ImageData.h" 30 #include "NotImplemented.h" 31 32 #include "android_graphics.h" 33 #include "GraphicsContext.h" 34 #include "PlatformGraphicsContext.h" 35 #include "SkBitmapRef.h" 36 #include "SkCanvas.h" 37 #include "SkColorPriv.h" 38 #include "SkDevice.h" 39 #include "SkUnPreMultiply.h" 40 41 using namespace std; 42 43 namespace WebCore { 44 45 ImageBufferData::ImageBufferData(const IntSize&) 46 { 47 } 48 49 ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace colorSpace, bool& success) 50 : m_data(size) 51 , m_size(size) 52 { 53 m_context.set(GraphicsContext::createOffscreenContext(size.width(), size.height())); 54 success = true; 55 } 56 57 ImageBuffer::~ImageBuffer() 58 { 59 } 60 61 GraphicsContext* ImageBuffer::context() const 62 { 63 return m_context.get(); 64 } 65 66 /* This guy needs to make a deep copy of the bitmap, so that the returned 67 image doesn't reflect any subsequent changes to the canvas' backend. 68 e.g. this is called when <canvas> wants to make a Pattern, which needs 69 to snapshot the current pixels when it is created. 70 */ 71 Image* ImageBuffer::image() const 72 { 73 if (!m_image) { 74 ASSERT(context()); 75 SkCanvas* canvas = context()->platformContext()->mCanvas; 76 SkDevice* device = canvas->getDevice(); 77 const SkBitmap& orig = device->accessBitmap(false); 78 79 SkBitmap copy; 80 orig.copyTo(©, orig.config()); 81 82 SkBitmapRef* ref = new SkBitmapRef(copy); 83 m_image = BitmapImage::create(ref, 0); 84 ref->unref(); 85 } 86 return m_image.get(); 87 } 88 89 PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const 90 { 91 GraphicsContext* gc = this->context(); 92 if (!gc) { 93 return 0; 94 } 95 96 const SkBitmap& src = android_gc2canvas(gc)->getDevice()->accessBitmap(false); 97 SkAutoLockPixels alp(src); 98 if (!src.getPixels()) { 99 return 0; 100 } 101 102 // ! Can't use PassRefPtr<>, otherwise the second access will cause crash. 103 RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); 104 unsigned char* data = result->data()->data()->data(); 105 106 if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height()) 107 memset(data, 0, result->data()->length()); 108 109 int originx = rect.x(); 110 int destx = 0; 111 if (originx < 0) { 112 destx = -originx; 113 originx = 0; 114 } 115 int endx = rect.x() + rect.width(); 116 if (endx > m_size.width()) 117 endx = m_size.width(); 118 int numColumns = endx - originx; 119 120 int originy = rect.y(); 121 int desty = 0; 122 if (originy < 0) { 123 desty = -originy; 124 originy = 0; 125 } 126 int endy = rect.y() + rect.height(); 127 if (endy > m_size.height()) 128 endy = m_size.height(); 129 int numRows = endy - originy; 130 131 unsigned srcPixelsPerRow = src.rowBytesAsPixels(); 132 unsigned destBytesPerRow = 4 * rect.width(); 133 134 const SkPMColor* srcRows = src.getAddr32(originx, originy); 135 unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; 136 for (int y = 0; y < numRows; ++y) { 137 for (int x = 0; x < numColumns; x++) { 138 // ugh, it appears they want unpremultiplied pixels 139 SkColor c = SkUnPreMultiply::PMColorToColor(srcRows[x]); 140 int basex = x * 4; 141 destRows[basex + 0] = SkColorGetR(c); 142 destRows[basex + 1] = SkColorGetG(c); 143 destRows[basex + 2] = SkColorGetB(c); 144 destRows[basex + 3] = SkColorGetA(c); 145 } 146 srcRows += srcPixelsPerRow; 147 destRows += destBytesPerRow; 148 } 149 return result; 150 } 151 152 void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) 153 { 154 GraphicsContext* gc = this->context(); 155 if (!gc) { 156 return; 157 } 158 159 const SkBitmap& dst = android_gc2canvas(gc)->getDevice()->accessBitmap(true); 160 SkAutoLockPixels alp(dst); 161 if (!dst.getPixels()) { 162 return; 163 } 164 165 ASSERT(sourceRect.width() > 0); 166 ASSERT(sourceRect.height() > 0); 167 168 int originx = sourceRect.x(); 169 int destx = destPoint.x() + sourceRect.x(); 170 ASSERT(destx >= 0); 171 ASSERT(destx < m_size.width()); 172 ASSERT(originx >= 0); 173 ASSERT(originx <= sourceRect.right()); 174 175 int endx = destPoint.x() + sourceRect.right(); 176 ASSERT(endx <= m_size.width()); 177 178 int numColumns = endx - destx; 179 180 int originy = sourceRect.y(); 181 int desty = destPoint.y() + sourceRect.y(); 182 ASSERT(desty >= 0); 183 ASSERT(desty < m_size.height()); 184 ASSERT(originy >= 0); 185 ASSERT(originy <= sourceRect.bottom()); 186 187 int endy = destPoint.y() + sourceRect.bottom(); 188 ASSERT(endy <= m_size.height()); 189 int numRows = endy - desty; 190 191 unsigned srcBytesPerRow = 4 * source->width(); 192 unsigned dstPixelsPerRow = dst.rowBytesAsPixels(); 193 194 unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; 195 SkPMColor* dstRows = dst.getAddr32(destx, desty); 196 for (int y = 0; y < numRows; ++y) { 197 for (int x = 0; x < numColumns; x++) { 198 int basex = x * 4; 199 dstRows[x] = SkPackARGB32(srcRows[basex + 3], 200 srcRows[basex + 0], 201 srcRows[basex + 1], 202 srcRows[basex + 2]); 203 } 204 dstRows += dstPixelsPerRow; 205 srcRows += srcBytesPerRow; 206 } 207 } 208 209 210 String ImageBuffer::toDataURL(const String&) const 211 { 212 // leaving this unimplemented, until I understand what its for (and what it 213 // really is). 214 return "data:,"; // I think this means we couldn't make the data url 215 } 216 217 } 218