• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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