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 #include "config.h" 27 #include "ImageTexture.h" 28 29 #include "ImagesManager.h" 30 #include "LayerAndroid.h" 31 #include "SkDevice.h" 32 #include "SkPicture.h" 33 #include "TilesManager.h" 34 #include "TiledTexture.h" 35 36 #include <cutils/log.h> 37 #include <wtf/CurrentTime.h> 38 #include <wtf/text/CString.h> 39 40 #undef XLOGC 41 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "ImageTexture", __VA_ARGS__) 42 43 #ifdef DEBUG 44 45 #undef XLOG 46 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ImageTexture", __VA_ARGS__) 47 48 #else 49 50 #undef XLOG 51 #define XLOG(...) 52 53 #endif // DEBUG 54 55 namespace WebCore { 56 57 // CRC computation adapted from Tools/DumpRenderTree/CyclicRedundancyCheck.cpp 58 static void makeCrcTable(unsigned crcTable[256]) 59 { 60 for (unsigned i = 0; i < 256; i++) { 61 unsigned c = i; 62 for (int k = 0; k < 8; k++) { 63 if (c & 1) 64 c = -306674912 ^ ((c >> 1) & 0x7fffffff); 65 else 66 c = c >> 1; 67 } 68 crcTable[i] = c; 69 } 70 } 71 72 unsigned computeCrc(uint8_t* buffer, size_t size) 73 { 74 static unsigned crcTable[256]; 75 static bool crcTableComputed = false; 76 if (!crcTableComputed) { 77 makeCrcTable(crcTable); 78 crcTableComputed = true; 79 } 80 81 unsigned crc = 0xffffffffL; 82 for (size_t i = 0; i < size; ++i) 83 crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffL); 84 return crc ^ 0xffffffffL; 85 } 86 87 ImageTexture::ImageTexture(SkBitmap* bmp, unsigned crc) 88 : m_image(bmp) 89 , m_texture(0) 90 , m_layer(0) 91 , m_picture(0) 92 , m_crc(crc) 93 { 94 #ifdef DEBUG_COUNT 95 ClassTracker::instance()->increment("ImageTexture"); 96 #endif 97 if (!m_image) 98 return; 99 100 // NOTE: This constructor is called on the webcore thread 101 102 // Create a picture containing the image (needed for TiledTexture) 103 m_picture = new SkPicture(); 104 SkCanvas* pcanvas = m_picture->beginRecording(m_image->width(), m_image->height()); 105 pcanvas->clear(SkColorSetARGBInline(0, 0, 0, 0)); 106 pcanvas->drawBitmap(*m_image, 0, 0); 107 m_picture->endRecording(); 108 } 109 110 ImageTexture::~ImageTexture() 111 { 112 #ifdef DEBUG_COUNT 113 ClassTracker::instance()->decrement("ImageTexture"); 114 #endif 115 delete m_image; 116 delete m_texture; 117 SkSafeUnref(m_picture); 118 } 119 120 SkBitmap* ImageTexture::convertBitmap(SkBitmap* bitmap) 121 { 122 SkBitmap* img = new SkBitmap(); 123 int w = bitmap->width(); 124 int h = bitmap->height(); 125 126 // Create a copy of the image 127 img->setConfig(SkBitmap::kARGB_8888_Config, w, h); 128 img->allocPixels(); 129 SkDevice* device = new SkDevice(NULL, *img, false); 130 SkCanvas canvas; 131 canvas.setDevice(device); 132 device->unref(); 133 SkRect dest; 134 dest.set(0, 0, w, h); 135 img->setIsOpaque(false); 136 img->eraseARGB(0, 0, 0, 0); 137 canvas.drawBitmapRect(*bitmap, 0, dest); 138 139 return img; 140 } 141 142 unsigned ImageTexture::computeCRC(const SkBitmap* bitmap) 143 { 144 if (!bitmap) 145 return 0; 146 bitmap->lockPixels(); 147 uint8_t* img = static_cast<uint8_t*>(bitmap->getPixels()); 148 unsigned crc = computeCrc(img, bitmap->getSize()); 149 bitmap->unlockPixels(); 150 return crc; 151 } 152 153 bool ImageTexture::equalsCRC(unsigned crc) 154 { 155 return m_crc == crc; 156 } 157 158 int ImageTexture::nbTextures() 159 { 160 if (!hasContentToShow()) 161 return 0; 162 if (!m_texture) 163 return 0; 164 165 // TODO: take in account the visible clip (need to maintain 166 // a list of the clients layer, etc.) 167 IntRect visibleArea(0, 0, m_image->width(), m_image->height()); 168 int nbTextures = m_texture->nbTextures(visibleArea, 1.0); 169 XLOG("ImageTexture %p, %d x %d needs %d textures", 170 this, m_image->width(), m_image->height(), 171 nbTextures); 172 return nbTextures; 173 } 174 175 bool ImageTexture::hasContentToShow() 176 { 177 // Don't display 1x1 image -- no need to allocate a full texture for this 178 if (!m_image) 179 return false; 180 if (m_image->width() == 1 && m_image->height() == 1) 181 return false; 182 return true; 183 } 184 185 bool ImageTexture::prepareGL(GLWebViewState* state) 186 { 187 if (!hasContentToShow()) 188 return false; 189 190 if (!m_texture && m_picture) { 191 m_texture = new TiledTexture(this); 192 SkRegion region; 193 region.setRect(0, 0, m_image->width(), m_image->height()); 194 m_texture->update(region, m_picture); 195 } 196 197 if (!m_texture) 198 return false; 199 200 IntRect visibleArea(0, 0, m_image->width(), m_image->height()); 201 m_texture->prepare(state, 1.0, true, true, visibleArea); 202 if (m_texture->ready()) { 203 m_texture->swapTiles(); 204 return false; 205 } 206 return true; 207 } 208 209 const TransformationMatrix* ImageTexture::transform() 210 { 211 if (!m_layer) 212 return 0; 213 214 FloatPoint p(0, 0); 215 p = m_layer->drawTransform()->mapPoint(p); 216 IntRect layerArea = m_layer->unclippedArea(); 217 float scaleW = static_cast<float>(layerArea.width()) / static_cast<float>(m_image->width()); 218 float scaleH = static_cast<float>(layerArea.height()) / static_cast<float>(m_image->height()); 219 TransformationMatrix d = *(m_layer->drawTransform()); 220 TransformationMatrix m; 221 m.scaleNonUniform(scaleW, scaleH); 222 m_layerMatrix = d.multiply(m); 223 return &m_layerMatrix; 224 } 225 226 float ImageTexture::opacity() 227 { 228 if (!m_layer) 229 return 1.0; 230 return m_layer->drawOpacity(); 231 } 232 233 void ImageTexture::drawGL(LayerAndroid* layer) 234 { 235 if (!layer) 236 return; 237 if (!hasContentToShow()) 238 return; 239 240 // TiledTexture::draw() will call us back to know the 241 // transform and opacity, so we need to set m_layer 242 m_layer = layer; 243 if (m_texture) 244 m_texture->draw(); 245 m_layer = 0; 246 } 247 248 void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect) 249 { 250 if (canvas && m_image) 251 canvas->drawBitmapRect(*m_image, 0, rect); 252 } 253 254 } // namespace WebCore 255