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 APPLE COMPUTER, INC. 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
ImageBufferData(const IntSize &)45 ImageBufferData::ImageBufferData(const IntSize&)
46 {
47 }
48
ImageBuffer(const IntSize & size,bool grayScale,bool & success)49 ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, 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
~ImageBuffer()57 ImageBuffer::~ImageBuffer()
58 {
59 }
60
context() const61 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 */
image() const71 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
getImageData(const IntRect & rect) const89 PassRefPtr<ImageData> ImageBuffer::getImageData(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
putImageData(ImageData * source,const IntRect & sourceRect,const IntPoint & destPoint)152 void ImageBuffer::putImageData(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
toDataURL(const String &) const210 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