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 ImagesManager::instance()->onImageTextureDestroy(m_crc); 105 } 106 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 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 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. 145 unsigned int ImageTexture::getImageTextureId() 146 { 147 return m_tileGrid ? m_tileGrid->getImageTextureId() : 0; 148 } 149 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 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 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 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 218 float ImageTexture::opacity() 219 { 220 if (!m_layer) 221 return 1.0; 222 return m_layer->drawOpacity(); 223 } 224 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 238 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 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 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