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 "LayerChromium.h" 36 37#include "cc/CCLayerImpl.h" 38#include "GraphicsContext3D.h" 39#include "LayerRendererChromium.h" 40#if USE(SKIA) 41#include "NativeImageSkia.h" 42#include "PlatformContextSkia.h" 43#endif 44#include "RenderLayerBacking.h" 45#include "TextStream.h" 46#include "skia/ext/platform_canvas.h" 47 48namespace WebCore { 49 50using namespace std; 51 52#ifndef NDEBUG 53static int s_nextLayerDebugID = 1; 54#endif 55 56PassRefPtr<LayerChromium> LayerChromium::create(GraphicsLayerChromium* owner) 57{ 58 return adoptRef(new LayerChromium(owner)); 59} 60 61LayerChromium::LayerChromium(GraphicsLayerChromium* owner) 62 : m_owner(owner) 63 , m_contentsDirty(false) 64 , m_maskLayer(0) 65 , m_ccLayerImpl(0) 66 , m_superlayer(0) 67#ifndef NDEBUG 68 , m_debugID(s_nextLayerDebugID++) 69#endif 70 , m_anchorPoint(0.5, 0.5) 71 , m_backgroundColor(0, 0, 0, 0) 72 , m_opacity(1.0) 73 , m_zPosition(0.0) 74 , m_anchorPointZ(0) 75 , m_clearsContext(false) 76 , m_hidden(false) 77 , m_masksToBounds(false) 78 , m_opaque(true) 79 , m_geometryFlipped(false) 80 , m_needsDisplayOnBoundsChange(false) 81 , m_doubleSided(true) 82 , m_replicaLayer(0) 83{ 84} 85 86LayerChromium::~LayerChromium() 87{ 88 // Our superlayer should be holding a reference to us so there should be no 89 // way for us to be destroyed while we still have a superlayer. 90 ASSERT(!superlayer()); 91 92 if (m_ccLayerImpl) 93 m_ccLayerImpl->resetOwner(); 94 95 // Remove the superlayer reference from all sublayers. 96 removeAllSublayers(); 97} 98 99void LayerChromium::cleanupResources() 100{ 101 if (m_ccLayerImpl) 102 m_ccLayerImpl->cleanupResources(); 103} 104 105void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer) 106{ 107 // If we're changing layer renderers then we need to free up any resources 108 // allocated by the old renderer. 109 if (layerRenderer() && layerRenderer() != renderer) { 110 cleanupResources(); 111 setNeedsDisplay(); 112 } 113 m_layerRenderer = renderer; 114} 115 116void LayerChromium::setNeedsCommit() 117{ 118 // Call notifySyncRequired(), which for non-root layers plumbs through to 119 // call setRootLayerNeedsDisplay() on the WebView, which will cause LayerRendererChromium 120 // to render a frame. 121 // This function has no effect on root layers. 122 if (m_owner) 123 m_owner->notifySyncRequired(); 124} 125 126void LayerChromium::addSublayer(PassRefPtr<LayerChromium> sublayer) 127{ 128 insertSublayer(sublayer, numSublayers()); 129} 130 131void LayerChromium::insertSublayer(PassRefPtr<LayerChromium> sublayer, size_t index) 132{ 133 index = min(index, m_sublayers.size()); 134 sublayer->removeFromSuperlayer(); 135 sublayer->setSuperlayer(this); 136 m_sublayers.insert(index, sublayer); 137 setNeedsCommit(); 138} 139 140void LayerChromium::removeFromSuperlayer() 141{ 142 if (m_superlayer) 143 m_superlayer->removeSublayer(this); 144} 145 146void LayerChromium::removeSublayer(LayerChromium* sublayer) 147{ 148 int foundIndex = indexOfSublayer(sublayer); 149 if (foundIndex == -1) 150 return; 151 152 sublayer->setSuperlayer(0); 153 m_sublayers.remove(foundIndex); 154 setNeedsCommit(); 155} 156 157void LayerChromium::replaceSublayer(LayerChromium* reference, PassRefPtr<LayerChromium> newLayer) 158{ 159 ASSERT_ARG(reference, reference); 160 ASSERT_ARG(reference, reference->superlayer() == this); 161 162 if (reference == newLayer) 163 return; 164 165 int referenceIndex = indexOfSublayer(reference); 166 if (referenceIndex == -1) { 167 ASSERT_NOT_REACHED(); 168 return; 169 } 170 171 reference->removeFromSuperlayer(); 172 173 if (newLayer) { 174 newLayer->removeFromSuperlayer(); 175 insertSublayer(newLayer, referenceIndex); 176 } 177} 178 179int LayerChromium::indexOfSublayer(const LayerChromium* reference) 180{ 181 for (size_t i = 0; i < m_sublayers.size(); i++) { 182 if (m_sublayers[i] == reference) 183 return i; 184 } 185 return -1; 186} 187 188void LayerChromium::setBounds(const IntSize& size) 189{ 190 if (bounds() == size) 191 return; 192 193 bool firstResize = !bounds().width() && !bounds().height() && size.width() && size.height(); 194 195 m_bounds = size; 196 197 if (firstResize) 198 setNeedsDisplay(FloatRect(0, 0, bounds().width(), bounds().height())); 199 else 200 setNeedsCommit(); 201} 202 203void LayerChromium::setFrame(const FloatRect& rect) 204{ 205 if (rect == m_frame) 206 return; 207 208 m_frame = rect; 209 setNeedsDisplay(FloatRect(0, 0, bounds().width(), bounds().height())); 210} 211 212const LayerChromium* LayerChromium::rootLayer() const 213{ 214 const LayerChromium* layer = this; 215 for (LayerChromium* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { } 216 return layer; 217} 218 219void LayerChromium::removeAllSublayers() 220{ 221 while (m_sublayers.size()) { 222 LayerChromium* layer = m_sublayers[0].get(); 223 ASSERT(layer->superlayer()); 224 layer->removeFromSuperlayer(); 225 } 226} 227 228void LayerChromium::setSublayers(const Vector<RefPtr<LayerChromium> >& sublayers) 229{ 230 if (sublayers == m_sublayers) 231 return; 232 233 removeAllSublayers(); 234 size_t listSize = sublayers.size(); 235 for (size_t i = 0; i < listSize; i++) 236 addSublayer(sublayers[i]); 237} 238 239LayerChromium* LayerChromium::superlayer() const 240{ 241 return m_superlayer; 242} 243 244void LayerChromium::setName(const String& name) 245{ 246 m_name = name; 247} 248 249void LayerChromium::setNeedsDisplay(const FloatRect& dirtyRect) 250{ 251 // Simply mark the contents as dirty. For non-root layers, the call to 252 // setNeedsCommit will schedule a fresh compositing pass. 253 // For the root layer, setNeedsCommit has no effect. 254 m_contentsDirty = true; 255 256 m_dirtyRect.unite(dirtyRect); 257 setNeedsCommit(); 258} 259 260void LayerChromium::setNeedsDisplay() 261{ 262 m_dirtyRect.setLocation(FloatPoint()); 263 m_dirtyRect.setSize(bounds()); 264 m_contentsDirty = true; 265 setNeedsCommit(); 266} 267 268void LayerChromium::resetNeedsDisplay() 269{ 270 m_dirtyRect = FloatRect(); 271 m_contentsDirty = false; 272} 273 274void LayerChromium::toGLMatrix(float* flattened, const TransformationMatrix& m) 275{ 276 flattened[0] = m.m11(); 277 flattened[1] = m.m12(); 278 flattened[2] = m.m13(); 279 flattened[3] = m.m14(); 280 flattened[4] = m.m21(); 281 flattened[5] = m.m22(); 282 flattened[6] = m.m23(); 283 flattened[7] = m.m24(); 284 flattened[8] = m.m31(); 285 flattened[9] = m.m32(); 286 flattened[10] = m.m33(); 287 flattened[11] = m.m34(); 288 flattened[12] = m.m41(); 289 flattened[13] = m.m42(); 290 flattened[14] = m.m43(); 291 flattened[15] = m.m44(); 292} 293 294void LayerChromium::pushPropertiesTo(CCLayerImpl* layer) 295{ 296 layer->setAnchorPoint(m_anchorPoint); 297 layer->setAnchorPointZ(m_anchorPointZ); 298 layer->setBounds(m_bounds); 299 layer->setDebugBorderColor(m_debugBorderColor); 300 layer->setDebugBorderWidth(m_debugBorderWidth); 301 layer->setDoubleSided(m_doubleSided); 302 layer->setLayerRenderer(m_layerRenderer.get()); 303 layer->setMasksToBounds(m_masksToBounds); 304 layer->setName(m_name); 305 layer->setOpacity(m_opacity); 306 layer->setPosition(m_position); 307 layer->setPreserves3D(preserves3D()); 308 layer->setSublayerTransform(m_sublayerTransform); 309 layer->setTransform(m_transform); 310 311 if (maskLayer()) 312 maskLayer()->pushPropertiesTo(layer->maskLayer()); 313 if (replicaLayer()) 314 replicaLayer()->pushPropertiesTo(layer->replicaLayer()); 315} 316 317GraphicsContext3D* LayerChromium::layerRendererContext() const 318{ 319 ASSERT(layerRenderer()); 320 return layerRenderer()->context(); 321} 322 323void LayerChromium::drawTexturedQuad(GraphicsContext3D* context, const TransformationMatrix& projectionMatrix, const TransformationMatrix& drawMatrix, 324 float width, float height, float opacity, 325 int matrixLocation, int alphaLocation) 326{ 327 static float glMatrix[16]; 328 329 TransformationMatrix renderMatrix = drawMatrix; 330 331 // Apply a scaling factor to size the quad from 1x1 to its intended size. 332 renderMatrix.scale3d(width, height, 1); 333 334 // Apply the projection matrix before sending the transform over to the shader. 335 toGLMatrix(&glMatrix[0], projectionMatrix * renderMatrix); 336 337 GLC(context, context->uniformMatrix4fv(matrixLocation, false, &glMatrix[0], 1)); 338 339 if (alphaLocation != -1) 340 GLC(context, context->uniform1f(alphaLocation, opacity)); 341 342 GLC(context, context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0)); 343} 344 345String LayerChromium::layerTreeAsText() const 346{ 347 TextStream ts; 348 dumpLayer(ts, 0); 349 return ts.release(); 350} 351 352static void writeIndent(TextStream& ts, int indent) 353{ 354 for (int i = 0; i != indent; ++i) 355 ts << " "; 356} 357 358void LayerChromium::dumpLayer(TextStream& ts, int indent) const 359{ 360 writeIndent(ts, indent); 361 ts << layerTypeAsString() << "(" << m_name << ")\n"; 362 dumpLayerProperties(ts, indent+2); 363 if (m_ccLayerImpl) 364 m_ccLayerImpl->dumpLayerProperties(ts, indent+2); 365 if (m_replicaLayer) { 366 writeIndent(ts, indent+2); 367 ts << "Replica:\n"; 368 m_replicaLayer->dumpLayer(ts, indent+3); 369 } 370 if (m_maskLayer) { 371 writeIndent(ts, indent+2); 372 ts << "Mask:\n"; 373 m_maskLayer->dumpLayer(ts, indent+3); 374 } 375 for (size_t i = 0; i < m_sublayers.size(); ++i) 376 m_sublayers[i]->dumpLayer(ts, indent+1); 377} 378 379void LayerChromium::dumpLayerProperties(TextStream& ts, int indent) const 380{ 381 writeIndent(ts, indent); 382#ifndef NDEBUG 383 ts << "debugID: " << debugID() << ", "; 384#else 385#endif 386 ts << "drawsContent: " << drawsContent() << "\n"; 387 388} 389 390PassRefPtr<CCLayerImpl> LayerChromium::createCCLayerImpl() 391{ 392 return CCLayerImpl::create(this); 393} 394 395void LayerChromium::createCCLayerImplIfNeeded() 396{ 397 if (!m_ccLayerImpl) 398 m_ccLayerImpl = createCCLayerImpl(); 399} 400 401CCLayerImpl* LayerChromium::ccLayerImpl() 402{ 403 return m_ccLayerImpl.get(); 404} 405 406void LayerChromium::setBorderColor(const Color& color) 407{ 408 m_debugBorderColor = color; 409 setNeedsCommit(); 410} 411 412void LayerChromium::setBorderWidth(float width) 413{ 414 m_debugBorderWidth = width; 415 setNeedsCommit(); 416} 417 418LayerRendererChromium* LayerChromium::layerRenderer() const 419{ 420 return m_layerRenderer.get(); 421} 422 423} 424#endif // USE(ACCELERATED_COMPOSITING) 425