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 48 namespace WebCore { 49 50 using namespace std; 51 52 #ifndef NDEBUG 53 static int s_nextLayerDebugID = 1; 54 #endif 55 56 PassRefPtr<LayerChromium> LayerChromium::create(GraphicsLayerChromium* owner) 57 { 58 return adoptRef(new LayerChromium(owner)); 59 } 60 61 LayerChromium::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 86 LayerChromium::~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 99 void LayerChromium::cleanupResources() 100 { 101 if (m_ccLayerImpl) 102 m_ccLayerImpl->cleanupResources(); 103 } 104 105 void 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 116 void 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 126 void LayerChromium::addSublayer(PassRefPtr<LayerChromium> sublayer) 127 { 128 insertSublayer(sublayer, numSublayers()); 129 } 130 131 void 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 140 void LayerChromium::removeFromSuperlayer() 141 { 142 if (m_superlayer) 143 m_superlayer->removeSublayer(this); 144 } 145 146 void 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 157 void 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 179 int 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 188 void 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 203 void 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 212 const 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 219 void 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 228 void 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 239 LayerChromium* LayerChromium::superlayer() const 240 { 241 return m_superlayer; 242 } 243 244 void LayerChromium::setName(const String& name) 245 { 246 m_name = name; 247 } 248 249 void 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 260 void LayerChromium::setNeedsDisplay() 261 { 262 m_dirtyRect.setLocation(FloatPoint()); 263 m_dirtyRect.setSize(bounds()); 264 m_contentsDirty = true; 265 setNeedsCommit(); 266 } 267 268 void LayerChromium::resetNeedsDisplay() 269 { 270 m_dirtyRect = FloatRect(); 271 m_contentsDirty = false; 272 } 273 274 void 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 294 void 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 317 GraphicsContext3D* LayerChromium::layerRendererContext() const 318 { 319 ASSERT(layerRenderer()); 320 return layerRenderer()->context(); 321 } 322 323 void 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 345 String LayerChromium::layerTreeAsText() const 346 { 347 TextStream ts; 348 dumpLayer(ts, 0); 349 return ts.release(); 350 } 351 352 static void writeIndent(TextStream& ts, int indent) 353 { 354 for (int i = 0; i != indent; ++i) 355 ts << " "; 356 } 357 358 void 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 379 void 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 390 PassRefPtr<CCLayerImpl> LayerChromium::createCCLayerImpl() 391 { 392 return CCLayerImpl::create(this); 393 } 394 395 void LayerChromium::createCCLayerImplIfNeeded() 396 { 397 if (!m_ccLayerImpl) 398 m_ccLayerImpl = createCCLayerImpl(); 399 } 400 401 CCLayerImpl* LayerChromium::ccLayerImpl() 402 { 403 return m_ccLayerImpl.get(); 404 } 405 406 void LayerChromium::setBorderColor(const Color& color) 407 { 408 m_debugBorderColor = color; 409 setNeedsCommit(); 410 } 411 412 void LayerChromium::setBorderWidth(float width) 413 { 414 m_debugBorderWidth = width; 415 setNeedsCommit(); 416 } 417 418 LayerRendererChromium* LayerChromium::layerRenderer() const 419 { 420 return m_layerRenderer.get(); 421 } 422 423 } 424 #endif // USE(ACCELERATED_COMPOSITING) 425