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 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 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 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 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 } 105 106 SkBitmap* ImageTexture::convertBitmap(SkBitmap* bitmap) 107 { 108 SkBitmap* img = new SkBitmap(); 109 int w = bitmap->width(); 110 int h = bitmap->height(); 111 112 // Create a copy of the image 113 img->setConfig(SkBitmap::kARGB_8888_Config, w, h); 114 img->allocPixels(); 115 SkDevice* device = new SkDevice(*img); 116 SkCanvas canvas; 117 canvas.setDevice(device); 118 device->unref(); 119 SkRect dest; 120 dest.set(0, 0, w, h); 121 img->setIsOpaque(false); 122 img->eraseARGB(0, 0, 0, 0); 123 canvas.drawBitmapRect(*bitmap, 0, dest); 124 125 return img; 126 } 127 128 unsigned ImageTexture::computeCRC(const SkBitmap* bitmap) 129 { 130 if (!bitmap) 131 return 0; 132 bitmap->lockPixels(); 133 uint8_t* img = static_cast<uint8_t*>(bitmap->getPixels()); 134 unsigned crc = 0; 135 if (img) 136 crc = computeCrc(img, bitmap->getSize()); 137 bitmap->unlockPixels(); 138 return crc; 139 } 140 141 bool ImageTexture::equalsCRC(unsigned crc) 142 { 143 return m_crc == crc; 144 } 145 146 // Return 0 if the image does not meet the repeatable criteria. 147 unsigned int ImageTexture::getImageTextureId() 148 { 149 return m_tileGrid ? m_tileGrid->getImageTextureId() : 0; 150 } 151 152 int ImageTexture::nbTextures() 153 { 154 if (!hasContentToShow()) 155 return 0; 156 if (!m_tileGrid) 157 return 0; 158 159 // TODO: take in account the visible clip (need to maintain 160 // a list of the clients layer, etc.) 161 IntRect visibleContentArea(0, 0, m_image->width(), m_image->height()); 162 int nbTextures = m_tileGrid->nbTextures(visibleContentArea, 1.0); 163 ALOGV("ImageTexture %p, %d x %d needs %d textures", 164 this, m_image->width(), m_image->height(), 165 nbTextures); 166 return nbTextures; 167 } 168 169 bool ImageTexture::hasContentToShow() 170 { 171 // Don't display 1x1 image -- no need to allocate a full texture for this 172 if (!m_image) 173 return false; 174 if (m_image->width() == 1 && m_image->height() == 1) 175 return false; 176 return true; 177 } 178 179 bool ImageTexture::prepareGL(GLWebViewState* state) 180 { 181 if (!hasContentToShow()) 182 return false; 183 184 if (!m_tileGrid && m_picture) { 185 bool isBaseSurface = false; 186 m_tileGrid = new TileGrid(isBaseSurface); 187 SkRegion region; 188 region.setRect(0, 0, m_image->width(), m_image->height()); 189 m_tileGrid->markAsDirty(region); 190 } 191 192 if (!m_tileGrid) 193 return false; 194 195 IntRect fullContentArea(0, 0, m_image->width(), m_image->height()); 196 m_tileGrid->prepareGL(state, 1.0, fullContentArea, fullContentArea, this); 197 if (m_tileGrid->isReady()) { 198 m_tileGrid->swapTiles(); 199 return false; 200 } 201 return true; 202 } 203 204 const TransformationMatrix* ImageTexture::transform() 205 { 206 if (!m_layer) 207 return 0; 208 209 TransformationMatrix d = *(m_layer->drawTransform()); 210 TransformationMatrix m; 211 float scaleW = 1.0f; 212 float scaleH = 1.0f; 213 getImageToLayerScale(&scaleW, &scaleH); 214 215 m.scaleNonUniform(scaleW, scaleH); 216 m_layerMatrix = d.multiply(m); 217 return &m_layerMatrix; 218 } 219 220 float ImageTexture::opacity() 221 { 222 if (!m_layer) 223 return 1.0; 224 return m_layer->drawOpacity(); 225 } 226 227 bool ImageTexture::paint(SkCanvas* canvas) 228 { 229 if (!m_picture) { 230 ALOGV("IT %p COULDNT PAINT, NO PICTURE", this); 231 return false; 232 } 233 234 ALOGV("IT %p painting with picture %p", this, m_picture); 235 canvas->drawPicture(*m_picture); 236 237 return true; 238 } 239 240 void ImageTexture::getImageToLayerScale(float* scaleW, float* scaleH) const 241 { 242 if (!scaleW || !scaleH) 243 return; 244 245 246 IntRect layerArea = m_layer->fullContentArea(); 247 248 if (layerArea.width() == 0 || layerArea.height() == 0) 249 return; 250 251 // calculate X, Y scale difference between image pixel coordinates and layer 252 // content coordinates 253 254 *scaleW = static_cast<float>(layerArea.width()) / static_cast<float>(m_image->width()); 255 *scaleH = static_cast<float>(layerArea.height()) / static_cast<float>(m_image->height()); 256 } 257 258 void ImageTexture::drawGL(LayerAndroid* layer, 259 float opacity, FloatPoint* offset) 260 { 261 if (!layer) 262 return; 263 if (!hasContentToShow()) 264 return; 265 266 // TileGrid::draw() will call us back to know the 267 // transform and opacity, so we need to set m_layer 268 m_layer = layer; 269 if (m_tileGrid) { 270 bool force3dContentVisible = true; 271 IntRect visibleContentArea = m_layer->visibleContentArea(force3dContentVisible); 272 273 // transform visibleContentArea size to image size 274 float scaleW = 1.0f; 275 float scaleH = 1.0f; 276 getImageToLayerScale(&scaleW, &scaleH); 277 visibleContentArea.setX(visibleContentArea.x() / scaleW); 278 visibleContentArea.setWidth(visibleContentArea.width() / scaleW); 279 visibleContentArea.setY(visibleContentArea.y() / scaleH); 280 visibleContentArea.setHeight(visibleContentArea.height() / scaleH); 281 282 const TransformationMatrix* transformation = transform(); 283 if (offset) 284 m_layerMatrix.translate(offset->x(), offset->y()); 285 m_tileGrid->drawGL(visibleContentArea, opacity, transformation); 286 } 287 m_layer = 0; 288 } 289 290 void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect) 291 { 292 if (canvas && m_image) 293 canvas->drawBitmapRect(*m_image, 0, rect); 294 } 295 296 } // namespace WebCore 297