1 /*
2 * Copyright 2011, 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 #define LOG_TAG "ImageTexture"
27 #define LOG_NDEBUG 1
28
29 #include "config.h"
30 #include "ImageTexture.h"
31
32 #include "AndroidLog.h"
33 #include "ClassTracker.h"
34 #include "ImagesManager.h"
35 #include "LayerAndroid.h"
36 #include "SkDevice.h"
37 #include "SkPicture.h"
38 #include "TileGrid.h"
39 #include "TilesManager.h"
40
41 namespace WebCore {
42
43 // CRC computation adapted from Tools/DumpRenderTree/CyclicRedundancyCheck.cpp
makeCrcTable(unsigned crcTable[256])44 static void makeCrcTable(unsigned crcTable[256])
45 {
46 for (unsigned i = 0; i < 256; i++) {
47 unsigned c = i;
48 for (int k = 0; k < 8; k++) {
49 if (c & 1)
50 c = -306674912 ^ ((c >> 1) & 0x7fffffff);
51 else
52 c = c >> 1;
53 }
54 crcTable[i] = c;
55 }
56 }
57
computeCrc(uint8_t * buffer,size_t size)58 unsigned computeCrc(uint8_t* buffer, size_t size)
59 {
60 static unsigned crcTable[256];
61 static bool crcTableComputed = false;
62 if (!crcTableComputed) {
63 makeCrcTable(crcTable);
64 crcTableComputed = true;
65 }
66
67 unsigned crc = 0xffffffffL;
68 for (size_t i = 0; i < size; ++i)
69 crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffL);
70 return crc ^ 0xffffffffL;
71 }
72
ImageTexture(SkBitmap * bmp,unsigned crc)73 ImageTexture::ImageTexture(SkBitmap* bmp, unsigned crc)
74 : m_image(bmp)
75 , m_tileGrid(0)
76 , m_layer(0)
77 , m_picture(0)
78 , m_crc(crc)
79 {
80 #ifdef DEBUG_COUNT
81 ClassTracker::instance()->increment("ImageTexture");
82 #endif
83 if (!m_image)
84 return;
85
86 // NOTE: This constructor is called on the webcore thread
87
88 // Create a picture containing the image (needed for TileGrid)
89 m_picture = new SkPicture();
90 SkCanvas* pcanvas = m_picture->beginRecording(m_image->width(), m_image->height());
91 pcanvas->clear(SkColorSetARGBInline(0, 0, 0, 0));
92 pcanvas->drawBitmap(*m_image, 0, 0);
93 m_picture->endRecording();
94 }
95
~ImageTexture()96 ImageTexture::~ImageTexture()
97 {
98 #ifdef DEBUG_COUNT
99 ClassTracker::instance()->decrement("ImageTexture");
100 #endif
101 delete m_image;
102 delete m_tileGrid;
103 SkSafeUnref(m_picture);
104 ImagesManager::instance()->onImageTextureDestroy(m_crc);
105 }
106
convertBitmap(SkBitmap * bitmap)107 SkBitmap* ImageTexture::convertBitmap(SkBitmap* bitmap)
108 {
109 SkBitmap* img = new SkBitmap();
110 int w = bitmap->width();
111 int h = bitmap->height();
112
113 // Create a copy of the image
114 img->setConfig(SkBitmap::kARGB_8888_Config, w, h);
115 img->allocPixels();
116 SkCanvas canvas(*img);
117 SkRect dest;
118 dest.set(0, 0, w, h);
119 img->setIsOpaque(false);
120 img->eraseARGB(0, 0, 0, 0);
121 canvas.drawBitmapRect(*bitmap, 0, dest);
122
123 return img;
124 }
125
computeCRC(const SkBitmap * bitmap)126 unsigned ImageTexture::computeCRC(const SkBitmap* bitmap)
127 {
128 if (!bitmap)
129 return 0;
130 bitmap->lockPixels();
131 uint8_t* img = static_cast<uint8_t*>(bitmap->getPixels());
132 unsigned crc = 0;
133 if (img)
134 crc = computeCrc(img, bitmap->getSize());
135 bitmap->unlockPixels();
136 return crc;
137 }
138
equalsCRC(unsigned crc)139 bool ImageTexture::equalsCRC(unsigned crc)
140 {
141 return m_crc == crc;
142 }
143
144 // Return 0 if the image does not meet the repeatable criteria.
getImageTextureId()145 unsigned int ImageTexture::getImageTextureId()
146 {
147 return m_tileGrid ? m_tileGrid->getImageTextureId() : 0;
148 }
149
nbTextures()150 int ImageTexture::nbTextures()
151 {
152 if (!hasContentToShow())
153 return 0;
154 if (!m_tileGrid)
155 return 0;
156
157 // TODO: take in account the visible clip (need to maintain
158 // a list of the clients layer, etc.)
159 IntRect visibleContentArea(0, 0, m_image->width(), m_image->height());
160 int nbTextures = m_tileGrid->nbTextures(visibleContentArea, 1.0);
161 ALOGV("ImageTexture %p, %d x %d needs %d textures",
162 this, m_image->width(), m_image->height(),
163 nbTextures);
164 return nbTextures;
165 }
166
hasContentToShow()167 bool ImageTexture::hasContentToShow()
168 {
169 // Don't display 1x1 image -- no need to allocate a full texture for this
170 if (!m_image)
171 return false;
172 if (m_image->width() == 1 && m_image->height() == 1)
173 return false;
174 return true;
175 }
176
prepareGL(GLWebViewState * state)177 bool ImageTexture::prepareGL(GLWebViewState* state)
178 {
179 if (!hasContentToShow())
180 return false;
181
182 if (!m_tileGrid && m_picture) {
183 bool isBaseSurface = false;
184 m_tileGrid = new TileGrid(isBaseSurface);
185 SkRegion region;
186 region.setRect(0, 0, m_image->width(), m_image->height());
187 m_tileGrid->markAsDirty(region);
188 }
189
190 if (!m_tileGrid)
191 return false;
192
193 IntRect fullContentArea(0, 0, m_image->width(), m_image->height());
194 m_tileGrid->prepareGL(state, 1.0, fullContentArea, fullContentArea, this);
195 if (m_tileGrid->isReady()) {
196 m_tileGrid->swapTiles();
197 return false;
198 }
199 return true;
200 }
201
transform()202 const TransformationMatrix* ImageTexture::transform()
203 {
204 if (!m_layer)
205 return 0;
206
207 TransformationMatrix d = *(m_layer->drawTransform());
208 TransformationMatrix m;
209 float scaleW = 1.0f;
210 float scaleH = 1.0f;
211 getImageToLayerScale(&scaleW, &scaleH);
212
213 m.scaleNonUniform(scaleW, scaleH);
214 m_layerMatrix = d.multiply(m);
215 return &m_layerMatrix;
216 }
217
opacity()218 float ImageTexture::opacity()
219 {
220 if (!m_layer)
221 return 1.0;
222 return m_layer->drawOpacity();
223 }
224
paint(SkCanvas * canvas)225 bool ImageTexture::paint(SkCanvas* canvas)
226 {
227 if (!m_picture) {
228 ALOGV("IT %p COULDNT PAINT, NO PICTURE", this);
229 return false;
230 }
231
232 ALOGV("IT %p painting with picture %p", this, m_picture);
233 canvas->drawPicture(*m_picture);
234
235 return true;
236 }
237
getImageToLayerScale(float * scaleW,float * scaleH) const238 void ImageTexture::getImageToLayerScale(float* scaleW, float* scaleH) const
239 {
240 if (!scaleW || !scaleH)
241 return;
242
243
244 IntRect layerArea = m_layer->fullContentArea();
245
246 if (layerArea.width() == 0 || layerArea.height() == 0)
247 return;
248
249 // calculate X, Y scale difference between image pixel coordinates and layer
250 // content coordinates
251
252 *scaleW = static_cast<float>(layerArea.width()) / static_cast<float>(m_image->width());
253 *scaleH = static_cast<float>(layerArea.height()) / static_cast<float>(m_image->height());
254 }
255
drawGL(LayerAndroid * layer,float opacity,FloatPoint * offset)256 void ImageTexture::drawGL(LayerAndroid* layer,
257 float opacity, FloatPoint* offset)
258 {
259 if (!layer)
260 return;
261 if (!hasContentToShow())
262 return;
263
264 // TileGrid::draw() will call us back to know the
265 // transform and opacity, so we need to set m_layer
266 m_layer = layer;
267 if (m_tileGrid) {
268 bool force3dContentVisible = true;
269 IntRect visibleContentArea = m_layer->visibleContentArea(force3dContentVisible);
270
271 // transform visibleContentArea size to image size
272 float scaleW = 1.0f;
273 float scaleH = 1.0f;
274 getImageToLayerScale(&scaleW, &scaleH);
275 visibleContentArea.setX(visibleContentArea.x() / scaleW);
276 visibleContentArea.setWidth(visibleContentArea.width() / scaleW);
277 visibleContentArea.setY(visibleContentArea.y() / scaleH);
278 visibleContentArea.setHeight(visibleContentArea.height() / scaleH);
279
280 const TransformationMatrix* transformation = transform();
281 if (offset)
282 m_layerMatrix.translate(offset->x(), offset->y());
283 m_tileGrid->drawGL(visibleContentArea, opacity, transformation);
284 }
285 m_layer = 0;
286 }
287
drawCanvas(SkCanvas * canvas,SkRect & rect)288 void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect)
289 {
290 if (canvas && m_image)
291 canvas->drawBitmapRect(*m_image, 0, rect);
292 }
293
294 } // namespace WebCore
295