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