Home | History | Annotate | Download | only in rendering
      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