Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 
     33 #if USE(ACCELERATED_COMPOSITING)
     34 
     35 #include "ContentLayerChromium.h"
     36 
     37 #include "cc/CCLayerImpl.h"
     38 #include "GraphicsContext3D.h"
     39 #include "LayerRendererChromium.h"
     40 #include "LayerTexture.h"
     41 #include "RenderLayerBacking.h"
     42 #include "TextStream.h"
     43 
     44 // Maximum size the width or height of this layer can be before enabling tiling
     45 // when m_tilingOption == AutoTile.
     46 static int maxUntiledSize = 512;
     47 // When tiling is enabled, use tiles of this dimension squared.
     48 static int defaultTileSize = 256;
     49 
     50 using namespace std;
     51 
     52 namespace WebCore {
     53 
     54 PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChromium* owner)
     55 {
     56     return adoptRef(new ContentLayerChromium(owner));
     57 }
     58 
     59 ContentLayerChromium::ContentLayerChromium(GraphicsLayerChromium* owner)
     60     : LayerChromium(owner)
     61     , m_tilingOption(ContentLayerChromium::AutoTile)
     62 {
     63 }
     64 
     65 ContentLayerChromium::~ContentLayerChromium()
     66 {
     67     m_tiler.clear();
     68     LayerChromium::cleanupResources();
     69 }
     70 
     71 class ContentLayerPainter : public TilePaintInterface {
     72 public:
     73     explicit ContentLayerPainter(GraphicsLayerChromium* owner)
     74         : m_owner(owner)
     75     {
     76     }
     77 
     78     virtual void paint(GraphicsContext& context, const IntRect& contentRect)
     79     {
     80         context.save();
     81         context.clearRect(contentRect);
     82         context.clip(contentRect);
     83         m_owner->paintGraphicsLayerContents(context, contentRect);
     84         context.restore();
     85     }
     86 private:
     87     GraphicsLayerChromium* m_owner;
     88 };
     89 
     90 void ContentLayerChromium::paintContentsIfDirty(const IntRect& targetSurfaceRect)
     91 {
     92     ASSERT(drawsContent());
     93     ASSERT(layerRenderer());
     94 
     95     createTilerIfNeeded();
     96 
     97     ContentLayerPainter painter(m_owner);
     98     updateLayerSize(layerBounds().size());
     99 
    100     IntRect layerRect = visibleLayerRect(targetSurfaceRect);
    101     if (layerRect.isEmpty())
    102         return;
    103 
    104     IntRect dirty = enclosingIntRect(m_dirtyRect);
    105     dirty.intersect(layerBounds());
    106     m_tiler->invalidateRect(dirty);
    107 
    108     m_tiler->update(painter, layerRect);
    109     m_dirtyRect = FloatRect();
    110 }
    111 
    112 void ContentLayerChromium::setLayerRenderer(LayerRendererChromium* layerRenderer)
    113 {
    114     LayerChromium::setLayerRenderer(layerRenderer);
    115     createTilerIfNeeded();
    116     m_tiler->setLayerRenderer(layerRenderer);
    117 }
    118 
    119 TransformationMatrix ContentLayerChromium::tilingTransform()
    120 {
    121     TransformationMatrix transform = ccLayerImpl()->drawTransform();
    122     // Tiler draws from the upper left corner. The draw transform
    123     // specifies the middle of the layer.
    124     IntSize size = bounds();
    125     transform.translate(-size.width() / 2.0, -size.height() / 2.0);
    126 
    127     return transform;
    128 }
    129 
    130 IntRect ContentLayerChromium::visibleLayerRect(const IntRect& targetSurfaceRect)
    131 {
    132     if (targetSurfaceRect.isEmpty())
    133         return targetSurfaceRect;
    134 
    135     const IntRect layerBoundRect = layerBounds();
    136     const TransformationMatrix transform = tilingTransform();
    137 
    138     // Is this layer fully contained within the target surface?
    139     IntRect layerInSurfaceSpace = transform.mapRect(layerBoundRect);
    140     if (targetSurfaceRect.contains(layerInSurfaceSpace))
    141         return layerBoundRect;
    142 
    143     // If the layer doesn't fill up the entire surface, then find the part of
    144     // the surface rect where the layer could be visible. This avoids trying to
    145     // project surface rect points that are behind the projection point.
    146     IntRect minimalSurfaceRect = targetSurfaceRect;
    147     minimalSurfaceRect.intersect(layerInSurfaceSpace);
    148 
    149     // Project the corners of the target surface rect into the layer space.
    150     // This bounding rectangle may be larger than it needs to be (being
    151     // axis-aligned), but is a reasonable filter on the space to consider.
    152     // Non-invertible transforms will create an empty rect here.
    153     const TransformationMatrix surfaceToLayer = transform.inverse();
    154     IntRect layerRect = surfaceToLayer.projectQuad(FloatQuad(FloatRect(minimalSurfaceRect))).enclosingBoundingBox();
    155     layerRect.intersect(layerBoundRect);
    156     return layerRect;
    157 }
    158 
    159 IntRect ContentLayerChromium::layerBounds() const
    160 {
    161     return IntRect(IntPoint(0, 0), bounds());
    162 }
    163 
    164 void ContentLayerChromium::updateLayerSize(const IntSize& layerSize)
    165 {
    166     if (!m_tiler)
    167         return;
    168 
    169     const IntSize tileSize(min(defaultTileSize, layerSize.width()), min(defaultTileSize, layerSize.height()));
    170     const bool autoTiled = layerSize.width() > maxUntiledSize || layerSize.height() > maxUntiledSize;
    171 
    172     bool isTiled;
    173     if (m_tilingOption == AlwaysTile)
    174         isTiled = true;
    175     else if (m_tilingOption == NeverTile)
    176         isTiled = false;
    177     else
    178         isTiled = autoTiled;
    179 
    180     m_tiler->setTileSize(isTiled ? tileSize : layerSize);
    181 }
    182 
    183 void ContentLayerChromium::draw(const IntRect& targetSurfaceRect)
    184 {
    185     const TransformationMatrix transform = tilingTransform();
    186     IntRect layerRect = visibleLayerRect(targetSurfaceRect);
    187     if (!layerRect.isEmpty())
    188         m_tiler->draw(layerRect, transform, ccLayerImpl()->drawOpacity());
    189 }
    190 
    191 void ContentLayerChromium::createTilerIfNeeded()
    192 {
    193     if (m_tiler)
    194         return;
    195     m_tiler = LayerTilerChromium::create(layerRenderer(), IntSize(defaultTileSize, defaultTileSize), LayerTilerChromium::HasBorderTexels);
    196 }
    197 
    198 void ContentLayerChromium::updateCompositorResources()
    199 {
    200     m_tiler->uploadCanvas();
    201 }
    202 
    203 void ContentLayerChromium::setTilingOption(TilingOption option)
    204 {
    205     m_tilingOption = option;
    206     updateLayerSize(bounds());
    207 }
    208 
    209 void ContentLayerChromium::bindContentsTexture()
    210 {
    211     // This function is only valid for single texture layers, e.g. masks.
    212     ASSERT(m_tilingOption == NeverTile);
    213     ASSERT(m_tiler);
    214 
    215     LayerTexture* texture = m_tiler->getSingleTexture();
    216     ASSERT(texture);
    217 
    218     texture->bindTexture();
    219 }
    220 
    221 void ContentLayerChromium::setIsMask(bool isMask)
    222 {
    223     setTilingOption(isMask ? NeverTile : AutoTile);
    224 }
    225 
    226 static void writeIndent(TextStream& ts, int indent)
    227 {
    228     for (int i = 0; i != indent; ++i)
    229         ts << "  ";
    230 }
    231 
    232 void ContentLayerChromium::dumpLayerProperties(TextStream& ts, int indent) const
    233 {
    234     LayerChromium::dumpLayerProperties(ts, indent);
    235     writeIndent(ts, indent);
    236     ts << "skipsDraw: " << m_tiler->skipsDraw() << "\n";
    237 }
    238 
    239 }
    240 #endif // USE(ACCELERATED_COMPOSITING)
    241