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 }
    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