Home | History | Annotate | Download | only in layers
      1 /*
      2  * Copyright 2012, 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 "BaseLayerAndroid"
     27 #define LOG_NDEBUG 1
     28 
     29 #include "config.h"
     30 #include "BaseLayerAndroid.h"
     31 
     32 #include "AndroidLog.h"
     33 #include "CachedImage.h"
     34 #include "ClassTracker.h"
     35 #include "DrawQuadData.h"
     36 #include "FixedPositioning.h"
     37 #include "GLWebViewState.h"
     38 #include "ImagesManager.h"
     39 #include "LayerContent.h"
     40 #include "RenderStyle.h"
     41 #include "StyleCachedImage.h"
     42 #include "TilesManager.h"
     43 
     44 namespace WebCore {
     45 
     46 // Note: this must match the use of ID 0 specifying the base layer in DrawExtra
     47 #define BASE_UNIQUE_ID 0
     48 
     49 BaseLayerAndroid::BaseLayerAndroid(LayerContent* content)
     50     : LayerAndroid((RenderLayer*)0)
     51     , m_color(Color::white)
     52     , m_positionsCalculated(false)
     53 {
     54     if (content) {
     55         setContent(content);
     56         setSize(content->width(), content->height());
     57     }
     58     m_uniqueId = BASE_UNIQUE_ID;
     59 }
     60 
     61 void BaseLayerAndroid::getLocalTransform(SkMatrix* matrix) const
     62 {
     63     matrix->reset();
     64     // base layer doesn't use size in transform calculation
     65     matrix->preConcat(getMatrix());
     66 }
     67 
     68 IFrameLayerAndroid* BaseLayerAndroid::updatePosition(SkRect viewport,
     69                                                      IFrameLayerAndroid* parentIframeLayer)
     70 {
     71     if (viewport.fRight > getWidth() || viewport.fBottom > getHeight()) {
     72         // To handle the viewport expanding past the layer's size with HW accel,
     73         // expand the size of the layer, so that tiles will cover the viewport.
     74         setSize(std::max(viewport.fRight, getWidth()),
     75                 std::max(viewport.fBottom, getHeight()));
     76     }
     77 
     78     return LayerAndroid::updatePosition(viewport, parentIframeLayer);
     79 }
     80 
     81 void BaseLayerAndroid::updatePositionsRecursive(const SkRect& visibleContentRect)
     82 {
     83     TRACE_METHOD();
     84 
     85     updateLayerPositions(visibleContentRect);
     86     TransformationMatrix ident;
     87 
     88     // Start with an unnecessarily large clip, since the base layer can
     89     // dynamically increase in size to cover the viewport, and we cache its draw
     90     // clip. This way the base layer will never have it's visible area clipped
     91     // by its m_clippingRect, only the viewport.
     92     // Note: values larger than this suffer from floating point rounding issues
     93     FloatRect clip(0, 0, 1e7, 1e7);
     94 
     95     bool forcePositionCalculation = !m_positionsCalculated;
     96     float scale = 1.0f;
     97     // To minimize tearing in single surface mode, don't update the fixed element
     98     // when scrolling. The fixed element will move incorrectly when scrolling,
     99     // but its position will be corrected after scrolling.
    100     bool disableFixedElemUpdate = false;
    101     GLWebViewState* webViewState = state();
    102     if (webViewState) {
    103         scale = webViewState->scale();
    104         disableFixedElemUpdate = webViewState->isScrolling()
    105                                  && webViewState->isSingleSurfaceRenderingMode();
    106     }
    107     updateGLPositionsAndScale(ident, clip, 1, scale, forcePositionCalculation,
    108                               disableFixedElemUpdate);
    109 
    110     m_positionsCalculated = true;
    111 }
    112 
    113 ForegroundBaseLayerAndroid::ForegroundBaseLayerAndroid(LayerContent* content)
    114     : LayerAndroid((RenderLayer*)0)
    115 {
    116     setIntrinsicallyComposited(true);
    117 }
    118 
    119 FixedBackgroundImageLayerAndroid::FixedBackgroundImageLayerAndroid(PassRefPtr<RenderStyle> aStyle,
    120                                                                    int w, int h)
    121     : LayerAndroid((RenderLayer*)0)
    122     , m_width(w)
    123     , m_height(h)
    124 {
    125     RefPtr<RenderStyle> style = aStyle;
    126     FillLayer* layers = style->accessBackgroundLayers();
    127     StyleImage* styleImage = layers->image();
    128     CachedImage* cachedImage = static_cast<StyleCachedImage*>(styleImage)->cachedImage();
    129     WebCore::Image* image = cachedImage->image();
    130     setContentsImage(image->nativeImageForCurrentFrame());
    131     setSize(image->width(), image->height());
    132 
    133     setIntrinsicallyComposited(true);
    134 
    135     SkLength left, top;
    136     left = SkLength::convertLength(style->backgroundXPosition());
    137     top = SkLength::convertLength(style->backgroundYPosition());
    138 
    139     BackgroundImagePositioning* position = new BackgroundImagePositioning(this);
    140     position->setRepeatX(style->backgroundRepeatX() != WebCore::NoRepeatFill);
    141     position->setRepeatY(style->backgroundRepeatY() != WebCore::NoRepeatFill);
    142 
    143     setFixedPosition(position);
    144     position->setPosition(left, top);
    145 
    146 #ifdef DEBUG_COUNT
    147     ClassTracker::instance()->increment("FixedBackgroundImageLayerAndroid");
    148 #endif
    149 }
    150 
    151 FixedBackgroundImageLayerAndroid::FixedBackgroundImageLayerAndroid(const FixedBackgroundImageLayerAndroid& layer)
    152     : LayerAndroid(layer)
    153     , m_width(layer.m_width)
    154     , m_height(layer.m_height)
    155 {
    156 #ifdef DEBUG_COUNT
    157     ClassTracker::instance()->increment("FixedBackgroundImageLayerAndroid");
    158 #endif
    159 }
    160 
    161 FixedBackgroundImageLayerAndroid::~FixedBackgroundImageLayerAndroid()
    162 {
    163 #ifdef DEBUG_COUNT
    164     ClassTracker::instance()->decrement("FixedBackgroundImageLayerAndroid");
    165 #endif
    166 }
    167 
    168 static bool needToDisplayImage(bool repeatX, bool repeatY, float dx, float dy)
    169 {
    170     // handles the repeat attribute for the background image
    171     if (repeatX && repeatY)
    172         return true;
    173     if (repeatX && !repeatY && dy == 0)
    174         return true;
    175     if (!repeatX && repeatY && dx == 0)
    176         return true;
    177     if (dx == 0 && dy == 0)
    178         return true;
    179 
    180     return false;
    181 }
    182 
    183 // Return true when fast draw succeeds.
    184 // For the repeated image content, we just need to draw a single quad and use
    185 // the GL shader to repeat.
    186 bool FixedBackgroundImageLayerAndroid::drawSimpleQuad(ImageTexture* imageTexture,
    187                                                       BackgroundImagePositioning* position,
    188                                                       const IntPoint& repeatTimes,
    189                                                       const FloatPoint& startPoint,
    190                                                       const FloatPoint& origin,
    191                                                       const Color& backgroundColor)
    192 {
    193     // The limitation for current implementation is that we can only speed up
    194     // single tile size image.
    195     // TODO: add the fast path to imageTexture which contains >1 tiles.
    196     GLuint imageTextureId = imageTexture->getImageTextureId();
    197     if (!imageTextureId)
    198         return false;
    199 
    200     int nbX = repeatTimes.x();
    201     int nbY = repeatTimes.y();
    202     float startX = startPoint.x();
    203     float startY = startPoint.y();
    204     bool repeatX = position->repeatX();
    205     bool repeatY = position->repeatY();
    206 
    207     // Draw the entire background when repeat only in one direction or no repeat.
    208     if (!repeatX || !repeatY) {
    209         SkRect backgroundRect;
    210         backgroundRect.fLeft = origin.x() - startX;
    211         backgroundRect.fTop = origin.y() - startY;
    212         backgroundRect.fRight = backgroundRect.fLeft + getWidth() * nbX;
    213         backgroundRect.fBottom = backgroundRect.fTop + getHeight() * nbY;
    214         PureColorQuadData backgroundData(backgroundColor, BaseQuad,
    215                                          0, &backgroundRect, 1.0, true);
    216         TilesManager::instance()->shader()->drawQuad(&backgroundData);
    217     }
    218 
    219     // Now draw the repeated images.
    220     // We set the quad size as the image size, then imageRepeatRanges will
    221     // control how many times the image will be repeated by expanding the
    222     // quad and texture coordinates.
    223     // The image size can be smaller than a tile, so repeatScale will passed
    224     // into the shader to scale the texture coordinates.
    225     SkRect imageRect = SkRect::MakeXYWH(0, 0, getWidth(), getHeight());
    226     FloatRect imageRepeatRanges(0, 0, repeatX ? nbX : 1, repeatY ? nbY : 1);
    227 
    228     FloatSize repeatScale(float(getWidth()) / TilesManager::tileWidth(),
    229                           float(getHeight()) / TilesManager::tileHeight());
    230 
    231     ALOGV("repeatedQuadData: startX %f, startY %f , getWidth() %f, getHeight() %f,"
    232           " nbX %d, nbY %d, repeatImageTimesX, repeatImageTimesY %d %d"
    233           " repeatScale width %f, height %f, origin x %f y %f",
    234           startX , startY  , getWidth(), getHeight(), nbX , nbY,
    235           imageRepeatRanges.width(), imageRepeatRanges.height(),
    236           repeatScale.width(), repeatScale.height(), origin.x(), origin.y());
    237 
    238     // Adding startX and startY into the transform can handle the fixed right /
    239     // fixed bottom case.
    240     TransformationMatrix matrix = *drawTransform();
    241     matrix.translate(repeatX ? -startX : 0, repeatY ? -startY : 0);
    242 
    243     TextureQuadData repeatedQuadData(imageTextureId, GL_TEXTURE_2D, GL_LINEAR,
    244                                      LayerQuad, &matrix, &imageRect, getOpacity(),
    245                                      true, imageRepeatRanges, repeatScale);
    246     TilesManager::instance()->shader()->drawQuad(&repeatedQuadData);
    247     return true;
    248 }
    249 
    250 void FixedBackgroundImageLayerAndroid::drawRepeatedGrid(ImageTexture* imageTexture,
    251                                                         BackgroundImagePositioning* position,
    252                                                         const IntPoint& repeatTimes,
    253                                                         const FloatPoint& startPoint,
    254                                                         const FloatPoint& origin,
    255                                                         const Color& backgroundColor)
    256 {
    257     // Cover the entire background
    258     int nbX = repeatTimes.x();
    259     int nbY = repeatTimes.y();
    260     float startX = startPoint.x();
    261     float startY = startPoint.y();
    262     for (int i = 0; i < nbY; i++) {
    263         float dy = (i * getHeight()) - startY;
    264         for (int j = 0; j < nbX; j++) {
    265             float dx = (j * getWidth()) - startX;
    266             if (needToDisplayImage(position->repeatX(),
    267                                    position->repeatY(),
    268                                    dx, dy)) {
    269                 FloatPoint p(dx, dy);
    270                 imageTexture->drawGL(this, getOpacity(), &p);
    271             } else {
    272                 // If the image is not displayed, we still need to fill
    273                 // with the background color
    274                 SkRect rect;
    275                 rect.fLeft = origin.x() + dx;
    276                 rect.fTop = origin.y() + dy;
    277                 rect.fRight = rect.fLeft + getWidth();
    278                 rect.fBottom = rect.fTop + getHeight();
    279                 PureColorQuadData backgroundData(backgroundColor, BaseQuad,
    280                                                  0, &rect, 1.0);
    281                 TilesManager::instance()->shader()->drawQuad(&backgroundData);
    282             }
    283         }
    284     }
    285 }
    286 
    287 bool FixedBackgroundImageLayerAndroid::drawGL(bool layerTilesDisabled)
    288 {
    289     if (layerTilesDisabled)
    290         return false;
    291     if (!m_imageCRC)
    292         return false;
    293 
    294     ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC);
    295     if (!imageTexture) {
    296         ImagesManager::instance()->releaseImage(m_imageCRC);
    297         return false;
    298     }
    299 
    300     // We have a fixed background image, let's draw it
    301     if (m_fixedPosition && m_fixedPosition->isBackgroundImagePositioning()) {
    302         BackgroundImagePositioning* position =
    303             static_cast<BackgroundImagePositioning*>(m_fixedPosition);
    304 
    305         IntPoint repeatTimes(position->nbRepeatX(), position->nbRepeatY());
    306         FloatPoint startPoint(position->offsetX() * getWidth(),
    307                               position->offsetY() * getHeight());
    308 
    309         FloatPoint origin;
    310         origin = drawTransform()->mapPoint(origin);
    311 
    312         Color backgroundColor = Color((int)SkColorGetR(m_backgroundColor),
    313                                       (int)SkColorGetG(m_backgroundColor),
    314                                       (int)SkColorGetB(m_backgroundColor),
    315                                       (int)SkColorGetA(m_backgroundColor));
    316 
    317         bool drawSimpleQuadSuccess = drawSimpleQuad(imageTexture, position,
    318                                                     repeatTimes, startPoint,
    319                                                     origin, backgroundColor);
    320 
    321         if (!drawSimpleQuadSuccess) {
    322             drawRepeatedGrid(imageTexture, position, repeatTimes, startPoint,
    323                              origin, backgroundColor);
    324         }
    325     } else
    326         imageTexture->drawGL(this, getOpacity());
    327 
    328     ImagesManager::instance()->releaseImage(m_imageCRC);
    329 
    330     return false;
    331 }
    332 
    333 Image* FixedBackgroundImageLayerAndroid::GetCachedImage(PassRefPtr<RenderStyle> aStyle)
    334 {
    335     RefPtr<RenderStyle> style = aStyle;
    336     if (!style)
    337         return 0;
    338 
    339     if (!style->hasFixedBackgroundImage())
    340         return 0;
    341 
    342     FillLayer* layers = style->accessBackgroundLayers();
    343     StyleImage* styleImage = layers->image();
    344 
    345     if (!styleImage)
    346         return 0;
    347 
    348     if (!styleImage->isLoaded())
    349         return 0;
    350 
    351     if (!styleImage->isCachedImage())
    352         return 0;
    353 
    354     CachedImage* cachedImage = static_cast<StyleCachedImage*>(styleImage)->cachedImage();
    355 
    356     Image* image = cachedImage->image();
    357 
    358     if (image && !image->nativeImageForCurrentFrame())
    359         return 0;
    360 
    361     if (image == Image::nullImage())
    362         return 0;
    363 
    364     return image;
    365 }
    366 
    367 } // namespace WebCore
    368