|
Line 0
a/WebCore/rendering/RenderLayerBacking.cpp_sec1
|
|
|
1 |
/* |
| 2 |
* Copyright (C) 2009 Apple 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 |
| 6 |
* are met: |
| 7 |
* |
| 8 |
* 1. Redistributions of source code must retain the above copyright |
| 9 |
* notice, this list of conditions and the following disclaimer. |
| 10 |
* 2. Redistributions in binary form must reproduce the above copyright |
| 11 |
* notice, this list of conditions and the following disclaimer in the |
| 12 |
* documentation and/or other materials provided with the distribution. |
| 13 |
* 3. Neither the name of Apple Inc. ("Apple") nor the names of |
| 14 |
* its contributors may be used to endorse or promote products derived |
| 15 |
* from this software without specific prior written permission. |
| 16 |
* |
| 17 |
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| 18 |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 19 |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 20 |
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| 21 |
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 22 |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 23 |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 24 |
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 26 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
*/ |
| 28 |
|
| 29 |
#include "config.h" |
| 30 |
|
| 31 |
#if USE(ACCELERATED_COMPOSITING) |
| 32 |
|
| 33 |
#include "AnimationController.h" |
| 34 |
#include "CSSStyleSelector.h" |
| 35 |
#include "FrameView.h" |
| 36 |
#include "GraphicsContext.h" |
| 37 |
#include "GraphicsLayer.h" |
| 38 |
#include "HitTestRequest.h" |
| 39 |
#include "HitTestResult.h" |
| 40 |
#include "HTMLNames.h" |
| 41 |
#include "RenderImage.h" |
| 42 |
#include "RenderLayerCompositor.h" |
| 43 |
#include "RenderVideo.h" |
| 44 |
#include "RenderView.h" |
| 45 |
|
| 46 |
#include "RenderLayerBacking.h" |
| 47 |
|
| 48 |
using namespace std; |
| 49 |
|
| 50 |
namespace WebCore { |
| 51 |
|
| 52 |
struct LayerHitTestData { |
| 53 |
LayerHitTestData(RenderLayer* inRootLayer, const HitTestRequest& inRequest, HitTestResult& inResult, const IntRect& hitTestRect) |
| 54 |
: m_rootLayer(inRootLayer) |
| 55 |
, m_request(inRequest) |
| 56 |
, m_hitTestRect(hitTestRect) |
| 57 |
, m_result(inResult) |
| 58 |
{ |
| 59 |
} |
| 60 |
|
| 61 |
RenderLayer* m_rootLayer; |
| 62 |
const HitTestRequest& m_request; |
| 63 |
const IntRect& m_hitTestRect; |
| 64 |
HitTestResult& m_result; |
| 65 |
}; |
| 66 |
|
| 67 |
|
| 68 |
RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) |
| 69 |
: m_owningLayer(layer) |
| 70 |
, m_ancestorClippingLayer(0) |
| 71 |
, m_graphicsLayer(0) |
| 72 |
, m_contentsLayer(0) |
| 73 |
, m_clippingLayer(0) |
| 74 |
, m_forceCompositingLayer(false) |
| 75 |
, m_isSimpleContainerCompositingLayer(false) |
| 76 |
, m_simpleCompositingLayerStatusDirty(true) |
| 77 |
, m_compositingContentOffsetDirty(true) |
| 78 |
{ |
| 79 |
createGraphicsLayer(); |
| 80 |
} |
| 81 |
|
| 82 |
RenderLayerBacking::~RenderLayerBacking() |
| 83 |
{ |
| 84 |
updateClippingLayers(false, false); |
| 85 |
updateContentsLayer(false); |
| 86 |
destroyGraphicsLayer(); |
| 87 |
} |
| 88 |
|
| 89 |
void RenderLayerBacking::createGraphicsLayer() |
| 90 |
{ |
| 91 |
m_graphicsLayer = GraphicsLayer::createGraphicsLayer(this); |
| 92 |
|
| 93 |
#ifndef NDEBUG |
| 94 |
if (renderer()->node()->isDocumentNode()) |
| 95 |
m_graphicsLayer->setName("Document Node"); |
| 96 |
else { |
| 97 |
if (renderer()->node()->isHTMLElement() && renderer()->node()->hasID()) |
| 98 |
m_graphicsLayer->setName(renderer()->renderName() + String(" ") + ((HTMLElement*)renderer()->node())->id()); |
| 99 |
else |
| 100 |
m_graphicsLayer->setName(renderer()->renderName()); |
| 101 |
} |
| 102 |
#endif // NDEBUG |
| 103 |
|
| 104 |
updateLayerOpacity(); |
| 105 |
updateLayerTransform(); |
| 106 |
} |
| 107 |
|
| 108 |
void RenderLayerBacking::destroyGraphicsLayer() |
| 109 |
{ |
| 110 |
if (m_graphicsLayer) |
| 111 |
m_graphicsLayer->removeFromParent(); |
| 112 |
|
| 113 |
delete m_graphicsLayer; |
| 114 |
m_graphicsLayer = 0; |
| 115 |
|
| 116 |
delete m_contentsLayer; |
| 117 |
m_contentsLayer = 0; |
| 118 |
|
| 119 |
delete m_clippingLayer; |
| 120 |
m_clippingLayer = 0; |
| 121 |
} |
| 122 |
|
| 123 |
void RenderLayerBacking::updateLayerOpacity() |
| 124 |
{ |
| 125 |
m_graphicsLayer->setOpacity(compositingOpacity(renderer()->opacity()), 0, 0); |
| 126 |
} |
| 127 |
|
| 128 |
void RenderLayerBacking::updateLayerTransform() |
| 129 |
{ |
| 130 |
RenderStyle* style = renderer()->style(); |
| 131 |
const IntRect borderBox = renderer()->borderBox(); |
| 132 |
|
| 133 |
// FIXME: This should use m_owningLayer->transform(), but that currently has transform-origin |
| 134 |
// baked into it, and we don't want that. |
| 135 |
TransformationMatrix t; |
| 136 |
style->applyTransform(t, borderBox.size(), false); |
| 137 |
|
| 138 |
m_graphicsLayer->setTransform(t); |
| 139 |
} |
| 140 |
|
| 141 |
void RenderLayerBacking::updateAfterLayout() |
| 142 |
{ |
| 143 |
invalidateDrawingOptimizations(); |
| 144 |
detectDrawingOptimizations(); |
| 145 |
|
| 146 |
updateGraphicsLayerGeometry(); |
| 147 |
} |
| 148 |
|
| 149 |
bool RenderLayerBacking::updateGraphicsLayers(bool needsContentsLayer, bool needsUpperClippingLayer, bool needsLowerClippingLayer, bool needsRepaint) |
| 150 |
{ |
| 151 |
bool layerConfigChanged = false; |
| 152 |
if (updateContentsLayer(needsContentsLayer)) |
| 153 |
layerConfigChanged = true; |
| 154 |
|
| 155 |
if (updateClippingLayers(needsUpperClippingLayer, needsLowerClippingLayer)) |
| 156 |
layerConfigChanged = true; |
| 157 |
|
| 158 |
// See if we can now use any drawing optimizations. |
| 159 |
bool didDrawContent = graphicsLayer()->drawsContent(); |
| 160 |
invalidateDrawingOptimizations(); |
| 161 |
detectDrawingOptimizations(); |
| 162 |
if (!didDrawContent && graphicsLayer()->drawsContent()) |
| 163 |
needsRepaint = true; |
| 164 |
|
| 165 |
// Set opacity, if it is not animating. |
| 166 |
if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyOpacity)) |
| 167 |
updateLayerOpacity(); |
| 168 |
|
| 169 |
// Set transform property, if it is not animating. |
| 170 |
if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyWebkitTransform)) |
| 171 |
updateLayerTransform(); |
| 172 |
|
| 173 |
updateGraphicsLayerGeometry(); |
| 174 |
|
| 175 |
m_graphicsLayer->updateContentsRect(); |
| 176 |
|
| 177 |
if (needsRepaint) { |
| 178 |
m_graphicsLayer->setNeedsDisplay(); |
| 179 |
if (m_contentsLayer) |
| 180 |
m_contentsLayer->setNeedsDisplay(); |
| 181 |
} |
| 182 |
|
| 183 |
return layerConfigChanged; |
| 184 |
} |
| 185 |
|
| 186 |
void RenderLayerBacking::updateGraphicsLayerGeometry() |
| 187 |
{ |
| 188 |
// If we haven't built z-order lists yet, wait until later. |
| 189 |
if (m_owningLayer->isStackingContext() && m_owningLayer->m_zOrderListsDirty) |
| 190 |
return; |
| 191 |
|
| 192 |
m_compositingContentOffsetDirty = true; |
| 193 |
|
| 194 |
RenderLayer* compAncestor = compositor()->enclosingCompositingLayer(m_owningLayer, false); |
| 195 |
IntRect ancestorCompositingBounds; |
| 196 |
|
| 197 |
const RenderLayer* rootLayer = m_owningLayer->root(); |
| 198 |
|
| 199 |
// FIXME: optimize calculateCompositedBounds calls. Too many coord conversions in this code. |
| 200 |
if (compAncestor) |
| 201 |
ancestorCompositingBounds = compositor()->calculateCompositedBounds(compAncestor, rootLayer); |
| 202 |
|
| 203 |
IntRect compositingBounds = compositor()->calculateCompositedBounds(m_owningLayer, rootLayer); |
| 204 |
|
| 205 |
if (compAncestor && m_ancestorClippingLayer) { |
| 206 |
IntRect clippingLayerContentBox; |
| 207 |
// Call calculateRects to get the backgroundRect which is what is used to clip the contents of this |
| 208 |
// layer. Note that we call it with temporaryClipRects=true because normally when computing clip rects |
| 209 |
// for a compositing layer, rootLayer is the layer itself. |
| 210 |
IntRect infiniteRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX); |
| 211 |
IntRect layerBounds, backgroundRect, foregroundRect, outlineRect; |
| 212 |
m_owningLayer->calculateRects(compAncestor, infiniteRect, layerBounds, backgroundRect, foregroundRect, outlineRect, true); |
| 213 |
// FIXME: if the layer that is clipping has a transform, this does not work correctly. |
| 214 |
clippingLayerContentBox = backgroundRect; |
| 215 |
|
| 216 |
int absX = 0, absY = 0; |
| 217 |
compAncestor->convertToLayerCoords(rootLayer, absX, absY); |
| 218 |
clippingLayerContentBox.move(absX, absY); |
| 219 |
|
| 220 |
// Position relative to the compAncestor |
| 221 |
if (compAncestor->backing()->hasClippingLayer()) { |
| 222 |
IntRect parentClippingBox = compAncestor->renderer()->getOverflowClipRect(absX, absY); |
| 223 |
m_ancestorClippingLayer->setPosition(FloatPoint() + (clippingLayerContentBox.location() - parentClippingBox.location())); |
| 224 |
} else |
| 225 |
m_ancestorClippingLayer->setPosition(FloatPoint() + (clippingLayerContentBox.location() - ancestorCompositingBounds.location())); |
| 226 |
|
| 227 |
m_ancestorClippingLayer->setSize(clippingLayerContentBox.size()); |
| 228 |
|
| 229 |
m_graphicsLayer->setPosition(FloatPoint() + (compositingBounds.location() - clippingLayerContentBox.location())); |
| 230 |
} else if (compAncestor && compAncestor->backing()->hasClippingLayer()) { |
| 231 |
// The clipping layer is the size of the ancestor's overflowClipRect, so account for |
| 232 |
// its offset in its containing layer. |
| 233 |
int absX = 0, absY = 0; |
| 234 |
compAncestor->convertToLayerCoords(rootLayer, absX, absY); |
| 235 |
IntRect clippingLayerContentBox = compAncestor->renderer()->getOverflowClipRect(absX, absY); |
| 236 |
|
| 237 |
m_graphicsLayer->setPosition(FloatPoint() + (compositingBounds.location() - clippingLayerContentBox.location())); |
| 238 |
} else |
| 239 |
m_graphicsLayer->setPosition(FloatPoint() + (compositingBounds.location() - ancestorCompositingBounds.location())); |
| 240 |
|
| 241 |
FloatSize oldSize = m_graphicsLayer->size(); |
| 242 |
FloatSize newSize(compositingBounds.size()); |
| 243 |
if (oldSize != newSize) { |
| 244 |
m_graphicsLayer->setSize(newSize); |
| 245 |
// A bounds change will almost always require redisplay. Usually that redisplay |
| 246 |
// will happen because of a repaint elsewhere, but not always: |
| 247 |
// e.g. see RenderView::setMaximalOutlineSize() |
| 248 |
m_graphicsLayer->setNeedsDisplay(); |
| 249 |
} |
| 250 |
|
| 251 |
// If we have a layer that clips children, position it. |
| 252 |
if (m_clippingLayer) { |
| 253 |
int absX = 0, absY = 0; |
| 254 |
m_owningLayer->convertToLayerCoords(rootLayer, absX, absY); |
| 255 |
IntRect clippingLayerContentBox = renderer()->getOverflowClipRect(absX, absY); |
| 256 |
|
| 257 |
m_clippingLayer->setPosition(FloatPoint() + (clippingLayerContentBox.location() - compositingBounds.location())); |
| 258 |
m_clippingLayer->setSize(clippingLayerContentBox.size()); |
| 259 |
} |
| 260 |
|
| 261 |
IntRect layerBounds = IntRect(m_owningLayer->xPos(), m_owningLayer->yPos(), renderer()->width(), renderer()->height()); |
| 262 |
|
| 263 |
// Convert to absolute coords to match bbox. |
| 264 |
int absX = 0, absY = 0; |
| 265 |
m_owningLayer->convertToLayerCoords(rootLayer, absX, absY); |
| 266 |
layerBounds.move(absX - m_owningLayer->xPos(), absY - m_owningLayer->yPos()); |
| 267 |
|
| 268 |
// Update properties that depend on layer dimensions |
| 269 |
const IntRect borderBox = renderer()->borderBox(); |
| 270 |
|
| 271 |
FloatPoint3D transformOrigin = computeTransformOrigin(borderBox); |
| 272 |
// Compute the anchor point, which is in the center of the renderer box unless transform-origin is set. |
| 273 |
FloatPoint anchor(compositingBounds.width() != 0.0f ? ((layerBounds.x() - compositingBounds.x()) + transformOrigin.x()) / compositingBounds.width() : 0.5f, |
| 274 |
compositingBounds.height() != 0.0f ? ((layerBounds.y() - compositingBounds.y()) + transformOrigin.y()) / compositingBounds.height() : 0.5f); |
| 275 |
m_graphicsLayer->setAnchorPoint(anchor, transformOrigin.z()); |
| 276 |
|
| 277 |
if (m_contentsLayer) { |
| 278 |
m_contentsLayer->setPosition(IntPoint(0, 0)); |
| 279 |
m_contentsLayer->setSize(newSize); |
| 280 |
} |
| 281 |
|
| 282 |
m_graphicsLayer->updateContentsRect(); |
| 283 |
} |
| 284 |
|
| 285 |
void RenderLayerBacking::updateInternalHierarchy() |
| 286 |
{ |
| 287 |
// m_contentsLayer has to be inserted in the correct order with child layers, |
| 288 |
// so it's not inserted here. |
| 289 |
if (m_ancestorClippingLayer) { |
| 290 |
m_ancestorClippingLayer->removeAllChildren(); |
| 291 |
m_graphicsLayer->removeFromParent(); |
| 292 |
m_ancestorClippingLayer->addChild(m_graphicsLayer); |
| 293 |
} |
| 294 |
|
| 295 |
if (m_clippingLayer) { |
| 296 |
m_clippingLayer->removeFromParent(); |
| 297 |
m_graphicsLayer->addChild(m_clippingLayer); |
| 298 |
} |
| 299 |
} |
| 300 |
|
| 301 |
// Return true if the layers changed. |
| 302 |
bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip) |
| 303 |
{ |
| 304 |
bool layersChanged = false; |
| 305 |
|
| 306 |
if (needsAncestorClip) { |
| 307 |
if (!m_ancestorClippingLayer) { |
| 308 |
m_ancestorClippingLayer = GraphicsLayer::createGraphicsLayer(0); |
| 309 |
#ifndef NDEBUG |
| 310 |
m_ancestorClippingLayer->setName("Ancestor clipping Layer"); |
| 311 |
#endif |
| 312 |
m_ancestorClippingLayer->setMasksToBounds(true); |
| 313 |
layersChanged = true; |
| 314 |
} |
| 315 |
} else if (m_ancestorClippingLayer) { |
| 316 |
m_ancestorClippingLayer->removeFromParent(); |
| 317 |
delete m_ancestorClippingLayer; |
| 318 |
m_ancestorClippingLayer = 0; |
| 319 |
layersChanged = true; |
| 320 |
} |
| 321 |
|
| 322 |
if (needsDescendantClip) { |
| 323 |
if (!m_clippingLayer) { |
| 324 |
m_clippingLayer = GraphicsLayer::createGraphicsLayer(0); |
| 325 |
#ifndef NDEBUG |
| 326 |
m_clippingLayer->setName("Child clipping Layer"); |
| 327 |
#endif |
| 328 |
m_clippingLayer->setMasksToBounds(true); |
| 329 |
layersChanged = true; |
| 330 |
} |
| 331 |
} else if (m_clippingLayer) { |
| 332 |
m_clippingLayer->removeFromParent(); |
| 333 |
delete m_clippingLayer; |
| 334 |
m_clippingLayer = 0; |
| 335 |
layersChanged = true; |
| 336 |
} |
| 337 |
|
| 338 |
if (layersChanged) |
| 339 |
updateInternalHierarchy(); |
| 340 |
|
| 341 |
return layersChanged; |
| 342 |
} |
| 343 |
|
| 344 |
bool RenderLayerBacking::updateContentsLayer(bool needsContentsLayer) |
| 345 |
{ |
| 346 |
bool layerChanged = false; |
| 347 |
if (needsContentsLayer) { |
| 348 |
if (!m_contentsLayer) { |
| 349 |
m_contentsLayer = GraphicsLayer::createGraphicsLayer(this); |
| 350 |
#ifndef NDEBUG |
| 351 |
m_contentsLayer->setName("Contents"); |
| 352 |
#endif |
| 353 |
m_contentsLayer->setDrawsContent(true); |
| 354 |
m_contentsLayer->setDrawingPhase(GraphicsLayerPaintForegroundMask); |
| 355 |
m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintBackgroundMask); |
| 356 |
layerChanged = true; |
| 357 |
} |
| 358 |
} else if (m_contentsLayer) { |
| 359 |
m_contentsLayer->removeFromParent(); |
| 360 |
delete m_contentsLayer; |
| 361 |
m_contentsLayer = 0; |
| 362 |
m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintAllMask); |
| 363 |
layerChanged = true; |
| 364 |
} |
| 365 |
return layerChanged; |
| 366 |
} |
| 367 |
|
| 368 |
float RenderLayerBacking::compositingOpacity(float rendererOpacity) const |
| 369 |
{ |
| 370 |
float finalOpacity = rendererOpacity; |
| 371 |
|
| 372 |
for (RenderLayer* curr = m_owningLayer->parent(); curr != 0; curr = curr->parent()) { |
| 373 |
// We only care about parents that are stacking contexts. |
| 374 |
// Recall that opacity creates stacking context. |
| 375 |
if (!curr->isStackingContext()) |
| 376 |
continue; |
| 377 |
|
| 378 |
// If we found a compositing layer, we want to compute opacity |
| 379 |
// relative to it. So we can break here. |
| 380 |
if (curr->isComposited()) |
| 381 |
break; |
| 382 |
|
| 383 |
finalOpacity *= curr->renderer()->opacity(); |
| 384 |
} |
| 385 |
|
| 386 |
return finalOpacity; |
| 387 |
} |
| 388 |
|
| 389 |
// A simple background is either none or a solid color. |
| 390 |
static bool hasSimpleBackground(RenderStyle* inStyle) |
| 391 |
{ |
| 392 |
return !inStyle->hasBackgroundImage(); |
| 393 |
} |
| 394 |
|
| 395 |
static bool hasBorderOutlineOrShadow(RenderStyle* inStyle) |
| 396 |
{ |
| 397 |
return (inStyle->hasBorder() || inStyle->hasBorderRadius() || inStyle->hasOutline() || (inStyle->boxShadow() != 0)); |
| 398 |
} |
| 399 |
|
| 400 |
bool RenderLayerBacking::rendererHasBackground() const |
| 401 |
{ |
| 402 |
// FIXME: share more code here |
| 403 |
if (renderer()->node()->isDocumentNode()) { |
| 404 |
RenderObject* htmlObject = renderer()->firstChild(); |
| 405 |
if (!htmlObject) |
| 406 |
return false; |
| 407 |
|
| 408 |
RenderStyle* style = htmlObject->style(); |
| 409 |
if (style->hasBackground()) |
| 410 |
return true; |
| 411 |
|
| 412 |
RenderObject* bodyObject = htmlObject->firstChild(); |
| 413 |
if (!bodyObject) |
| 414 |
return false; |
| 415 |
|
| 416 |
style = bodyObject->style(); |
| 417 |
return style->hasBackground(); |
| 418 |
} |
| 419 |
|
| 420 |
return renderer()->style()->hasBackground(); |
| 421 |
} |
| 422 |
|
| 423 |
const Color& RenderLayerBacking::rendererBackgroundColor() const |
| 424 |
{ |
| 425 |
// FIXME: share more code here |
| 426 |
if (renderer()->node()->isDocumentNode()) { |
| 427 |
RenderObject* htmlObject = renderer()->firstChild(); |
| 428 |
RenderStyle* style = htmlObject->style(); |
| 429 |
if (style->hasBackground()) |
| 430 |
return style->backgroundColor(); |
| 431 |
|
| 432 |
RenderObject* bodyObject = htmlObject->firstChild(); |
| 433 |
style = bodyObject->style(); |
| 434 |
return style->backgroundColor(); |
| 435 |
} |
| 436 |
|
| 437 |
return renderer()->style()->backgroundColor(); |
| 438 |
} |
| 439 |
|
| 440 |
bool RenderLayerBacking::canBeSimpleContainerCompositingLayer() const |
| 441 |
{ |
| 442 |
RenderObject* renderObject = renderer(); |
| 443 |
if (renderObject->isReplaced() || // replaced objects are not containers |
| 444 |
renderObject->hasMask()) // masks require special treatment |
| 445 |
return false; |
| 446 |
|
| 447 |
RenderStyle* style = renderObject->style(); |
| 448 |
|
| 449 |
// Reject anything that has a border, a border-radius or outline, |
| 450 |
// or any background (color or image). |
| 451 |
// FIXME: we could optimize layers for simple backgrounds. |
| 452 |
if (hasBorderOutlineOrShadow(style) || |
| 453 |
style->hasBackground()) |
| 454 |
return false; |
| 455 |
|
| 456 |
// If we have got this far and the renderer has no children, then we're ok. |
| 457 |
if (!renderObject->firstChild()) |
| 458 |
return true; |
| 459 |
|
| 460 |
if (renderObject->node()->isDocumentNode()) { |
| 461 |
// Look to see if the root object has a non-simple backgound |
| 462 |
RenderObject* rootObject = renderObject->document()->documentElement()->renderer(); |
| 463 |
if (!rootObject) |
| 464 |
return false; |
| 465 |
|
| 466 |
style = rootObject->style(); |
| 467 |
|
| 468 |
// Reject anything that has a border, a border-radius or outline, |
| 469 |
// or is not a simple background (no background, or solid color). |
| 470 |
if (hasBorderOutlineOrShadow(style) || |
| 471 |
!hasSimpleBackground(style)) |
| 472 |
return false; |
| 473 |
|
| 474 |
// Now look at the body's renderer. |
| 475 |
HTMLElement* body = renderObject->document()->body(); |
| 476 |
RenderObject* bodyObject = (body && body->hasLocalName(HTMLNames::bodyTag)) ? body->renderer() : 0; |
| 477 |
if (!bodyObject) |
| 478 |
return false; |
| 479 |
|
| 480 |
style = bodyObject->style(); |
| 481 |
|
| 482 |
if (hasBorderOutlineOrShadow(style) || |
| 483 |
!hasSimpleBackground(style)) |
| 484 |
return false; |
| 485 |
|
| 486 |
// Ceck to see if all the body's children are compositing layers. |
| 487 |
if (hasNonCompositingContent()) |
| 488 |
return false; |
| 489 |
|
| 490 |
return true; |
| 491 |
} |
| 492 |
|
| 493 |
// Check to see if all the renderer's children are compositing layers. |
| 494 |
if (hasNonCompositingContent()) |
| 495 |
return false; |
| 496 |
|
| 497 |
return true; |
| 498 |
} |
| 499 |
|
| 500 |
bool RenderLayerBacking::hasNonCompositingContent() const |
| 501 |
{ |
| 502 |
// Conservative test for having no rendered children. |
| 503 |
|
| 504 |
// Some HTML can cause whitespace text nodes to have renderers, like: |
| 505 |
// <div> |
| 506 |
// <img src=...> |
| 507 |
// </div> |
| 508 |
// so test for 0x0 RenderTexts here |
| 509 |
for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { |
| 510 |
if (!child->hasLayer() && (child->width() > 0 || child->height() > 0)) |
| 511 |
return true; |
| 512 |
} |
| 513 |
|
| 514 |
// FIXME: test for overflow controls. |
| 515 |
if (m_owningLayer->isStackingContext()) { |
| 516 |
// Use the m_hasCompositingDescendant bit to optimize? |
| 517 |
Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList(); |
| 518 |
if (negZOrderList && negZOrderList->size() > 0) { |
| 519 |
for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { |
| 520 |
RenderLayer* curLayer = (*it); |
| 521 |
if (!curLayer->isComposited()) |
| 522 |
return true; |
| 523 |
} |
| 524 |
} |
| 525 |
|
| 526 |
Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList(); |
| 527 |
if (posZOrderList && posZOrderList->size() > 0) |
| 528 |
for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { |
| 529 |
RenderLayer* curLayer = (*it); |
| 530 |
if (!curLayer->isComposited()) |
| 531 |
return true; |
| 532 |
} |
| 533 |
} |
| 534 |
|
| 535 |
Vector<RenderLayer*>* overflowList = m_owningLayer->overflowList(); |
| 536 |
if (overflowList && overflowList->size() > 0) |
| 537 |
for (Vector<RenderLayer*>::const_iterator it = overflowList->begin(); it != overflowList->end(); ++it) { |
| 538 |
RenderLayer* curLayer = (*it); |
| 539 |
if (!curLayer->isComposited()) |
| 540 |
return true; |
| 541 |
} |
| 542 |
|
| 543 |
return false; |
| 544 |
} |
| 545 |
|
| 546 |
// A "simple container layer" is a RenderLayer which has no visible content to render. |
| 547 |
// It may have no children, or all its children may be themselves composited. |
| 548 |
// This is a useful optimization, because it allows us to avoid allocating backing store. |
| 549 |
bool RenderLayerBacking::isSimpleContainerCompositingLayer() |
| 550 |
{ |
| 551 |
if (m_simpleCompositingLayerStatusDirty) { |
| 552 |
m_isSimpleContainerCompositingLayer = canBeSimpleContainerCompositingLayer(); |
| 553 |
m_simpleCompositingLayerStatusDirty = false; |
| 554 |
} |
| 555 |
|
| 556 |
return m_isSimpleContainerCompositingLayer; |
| 557 |
} |
| 558 |
|
| 559 |
void RenderLayerBacking::detectDrawingOptimizations() |
| 560 |
{ |
| 561 |
bool drawsContent = true; |
| 562 |
|
| 563 |
if (isSimpleContainerCompositingLayer() || paintingGoesToWindow()) |
| 564 |
drawsContent = false; |
| 565 |
|
| 566 |
m_graphicsLayer->setDrawsContent(drawsContent); |
| 567 |
} |
| 568 |
|
| 569 |
void RenderLayerBacking::invalidateDrawingOptimizations() |
| 570 |
{ |
| 571 |
m_simpleCompositingLayerStatusDirty = true; |
| 572 |
} |
| 573 |
|
| 574 |
void RenderLayerBacking::forceCompositingLayer(bool force) |
| 575 |
{ |
| 576 |
m_forceCompositingLayer = force; |
| 577 |
} |
| 578 |
|
| 579 |
FloatPoint RenderLayerBacking::computeTransformOrigin(const IntRect& borderBox) const |
| 580 |
{ |
| 581 |
RenderStyle* style = renderer()->style(); |
| 582 |
|
| 583 |
FloatPoint origin; |
| 584 |
origin.setX(style->transformOriginX().calcFloatValue(borderBox.width())); |
| 585 |
origin.setY(style->transformOriginY().calcFloatValue(borderBox.height())); |
| 586 |
|
| 587 |
return origin; |
| 588 |
} |
| 589 |
|
| 590 |
// Return the offset from the top-left of this compositing layer at which the renderer's contents are painted. |
| 591 |
IntSize RenderLayerBacking::contentOffsetInCompostingLayer() |
| 592 |
{ |
| 593 |
if (!m_compositingContentOffsetDirty) |
| 594 |
return m_compositingContentOffset; |
| 595 |
|
| 596 |
IntRect relativeCompositingBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); |
| 597 |
m_compositingContentOffset = IntSize(-relativeCompositingBounds.x(), -relativeCompositingBounds.y()); |
| 598 |
m_compositingContentOffsetDirty = false; |
| 599 |
|
| 600 |
return m_compositingContentOffset; |
| 601 |
} |
| 602 |
|
| 603 |
IntRect RenderLayerBacking::contentsBox(const GraphicsLayer*) |
| 604 |
{ |
| 605 |
IntRect contentsRect; |
| 606 |
contentsRect = renderer()->contentBox(); |
| 607 |
|
| 608 |
IntSize contentOffset = contentOffsetInCompostingLayer(); |
| 609 |
contentsRect.move(contentOffset); |
| 610 |
return contentsRect; |
| 611 |
} |
| 612 |
|
| 613 |
// Map the given point from coordinates in the GraphicsLayer to RenderLayer coordinates. |
| 614 |
FloatPoint RenderLayerBacking::graphicsLayerToContentsCoordinates(const FloatPoint& point) |
| 615 |
{ |
| 616 |
IntSize contentOffset = contentOffsetInCompostingLayer(); |
| 617 |
return FloatPoint(point.x() - contentOffset.width(), point.y() - contentOffset.height()); |
| 618 |
} |
| 619 |
|
| 620 |
// Map the given point from coordinates in the RenderLayer to GraphicsLayer coordinates. |
| 621 |
FloatPoint RenderLayerBacking::contentsToGraphicsLayerCoordinates(const FloatPoint& point) |
| 622 |
{ |
| 623 |
IntSize contentOffset = contentOffsetInCompostingLayer(); |
| 624 |
return FloatPoint(point.x() + contentOffset.width(), point.y() + contentOffset.height()); |
| 625 |
} |
| 626 |
|
| 627 |
bool RenderLayerBacking::paintingGoesToWindow() const |
| 628 |
{ |
| 629 |
return m_owningLayer->isDocumentLayer() |
| 630 |
#ifndef NDEBUG |
| 631 |
&& !GraphicsLayer::showLayerHierarchy() |
| 632 |
#endif |
| 633 |
; |
| 634 |
} |
| 635 |
|
| 636 |
void RenderLayerBacking::setContentsNeedDisplay() |
| 637 |
{ |
| 638 |
if (m_graphicsLayer) |
| 639 |
m_graphicsLayer->setNeedsDisplay(); |
| 640 |
if (m_contentsLayer) |
| 641 |
m_contentsLayer->setNeedsDisplay(); |
| 642 |
} |
| 643 |
|
| 644 |
// r is in the coordinate space of the layer's render object |
| 645 |
void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) |
| 646 |
{ |
| 647 |
if (m_graphicsLayer) { |
| 648 |
FloatPoint dirtyOrigin = contentsToGraphicsLayerCoordinates(FloatPoint(r.x(), r.y())); |
| 649 |
FloatRect dirtyRect(dirtyOrigin, r.size()); |
| 650 |
FloatRect bounds(FloatPoint(), m_graphicsLayer->size()); |
| 651 |
if (bounds.intersects(dirtyRect)) |
| 652 |
m_graphicsLayer->setNeedsDisplayInRect(dirtyRect); |
| 653 |
} |
| 654 |
|
| 655 |
if (m_contentsLayer) { |
| 656 |
// FIXME: do incremental repaint |
| 657 |
m_contentsLayer->setNeedsDisplay(); |
| 658 |
} |
| 659 |
} |
| 660 |
|
| 661 |
static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect) |
| 662 |
{ |
| 663 |
if (paintDirtyRect == clipRect) |
| 664 |
return; |
| 665 |
p->save(); |
| 666 |
p->clip(clipRect); |
| 667 |
} |
| 668 |
|
| 669 |
static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect) |
| 670 |
{ |
| 671 |
if (paintDirtyRect == clipRect) |
| 672 |
return; |
| 673 |
p->restore(); |
| 674 |
} |
| 675 |
|
| 676 |
// Share this with RenderLayer::paintLayer, which would have to be educated about GraphicsLayerPaintingPhase? |
| 677 |
void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context, |
| 678 |
const IntRect& paintDirtyRect, // in the coords of rootLayer |
| 679 |
bool haveTransparency, PaintRestriction paintRestriction, GraphicsLayerPaintingPhase paintingPhase, |
| 680 |
RenderObject* paintingRoot) |
| 681 |
{ |
| 682 |
if (paintingGoesToWindow()) { |
| 683 |
ASSERT_NOT_REACHED(); |
| 684 |
return; |
| 685 |
} |
| 686 |
|
| 687 |
if (m_owningLayer->isStackingContext() && (m_owningLayer->m_zOrderListsDirty || m_owningLayer->m_overflowListDirty)) |
| 688 |
compositor()->updateCompositingLayers(m_owningLayer); |
| 689 |
|
| 690 |
// Calculate the clip rects we should use. |
| 691 |
IntRect layerBounds, damageRect, clipRectToApply, outlineRect; |
| 692 |
m_owningLayer->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); |
| 693 |
|
| 694 |
int x = layerBounds.x(); // layerBounds is computed relative to rootLayer |
| 695 |
int y = layerBounds.y(); |
| 696 |
int tx = x - renderer()->xPos(); |
| 697 |
int ty = y - renderer()->yPos() + renderer()->borderTopExtra(); |
| 698 |
|
| 699 |
// If this layer's renderer is a child of the paintingRoot, we render unconditionally, which |
| 700 |
// is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set). |
| 701 |
// Else, our renderer tree may or may not contain the painting root, so we pass that root along |
| 702 |
// so it will be tested against as we decend through the renderers. |
| 703 |
RenderObject *paintingRootForRenderer = 0; |
| 704 |
if (paintingRoot && !renderer()->isDescendantOf(paintingRoot)) |
| 705 |
paintingRootForRenderer = paintingRoot; |
| 706 |
|
| 707 |
if (paintingPhase & GraphicsLayerPaintBackgroundMask) { |
| 708 |
// If this is the root then we need to send in a bigger bounding box |
| 709 |
// because we'll be painting the background as well (see RenderBox::paintRootBoxDecorations()). |
| 710 |
IntRect paintBox = clipRectToApply; |
| 711 |
|
| 712 |
if (renderer()->node()->isDocumentNode() && renderer()->document()->isHTMLDocument()) { |
| 713 |
int w = renderer()->width(); |
| 714 |
int h = renderer()->height(); |
| 715 |
|
| 716 |
int rw; |
| 717 |
int rh; |
| 718 |
if (renderer()->view()->frameView()) { |
| 719 |
rw = renderer()->view()->frameView()->contentsWidth(); |
| 720 |
rh = renderer()->view()->frameView()->contentsHeight(); |
| 721 |
} else { |
| 722 |
rw = renderer()->view()->width(); |
| 723 |
rh = renderer()->view()->height(); |
| 724 |
} |
| 725 |
|
| 726 |
int bx = tx - renderer()->marginLeft(); |
| 727 |
int by = ty - renderer()->marginTop(); |
| 728 |
int bw = max(w + renderer()->marginLeft() + renderer()->marginRight() + renderer()->borderLeft() + renderer()->borderRight(), rw); |
| 729 |
int bh = max(h + renderer()->marginTop() + renderer()->marginBottom() + renderer()->borderTop() + renderer()->borderBottom(), rh); |
| 730 |
paintBox = IntRect(bx, by, bw, bh); |
| 731 |
} |
| 732 |
|
| 733 |
// Paint our background first, before painting any child layers. |
| 734 |
// Establish the clip used to paint our background. |
| 735 |
setClip(context, paintDirtyRect, damageRect); |
| 736 |
|
| 737 |
RenderObject::PaintInfo info(context, paintBox, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0); |
| 738 |
renderer()->paint(info, tx, ty); |
| 739 |
|
| 740 |
// Our scrollbar widgets paint exactly when we tell them to, so that they work properly with |
| 741 |
// z-index. We paint after we painted the background/border, so that the scrollbars will |
| 742 |
// sit above the background/border. |
| 743 |
m_owningLayer->paintOverflowControls(context, x, y, damageRect); |
| 744 |
|
| 745 |
// Restore the clip. |
| 746 |
restoreClip(context, paintDirtyRect, damageRect); |
| 747 |
} |
| 748 |
|
| 749 |
if (paintingPhase & GraphicsLayerPaintForegroundMask) { |
| 750 |
// Now walk the sorted list of children with negative z-indices. Only RenderLayers without compositing layers will paint. |
| 751 |
// FIXME: should these be painted as background? |
| 752 |
Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList(); |
| 753 |
if (negZOrderList) |
| 754 |
for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) |
| 755 |
it[0]->paintLayer(rootLayer, context, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); |
| 756 |
|
| 757 |
bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText; |
| 758 |
bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText; |
| 759 |
|
| 760 |
// Set up the clip used when painting our children. |
| 761 |
setClip(context, paintDirtyRect, clipRectToApply); |
| 762 |
RenderObject::PaintInfo paintInfo(context, clipRectToApply, |
| 763 |
selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, |
| 764 |
forceBlackText, paintingRootForRenderer, 0); |
| 765 |
renderer()->paint(paintInfo, tx, ty); |
| 766 |
|
| 767 |
if (!selectionOnly) { |
| 768 |
paintInfo.phase = PaintPhaseFloat; |
| 769 |
renderer()->paint(paintInfo, tx, ty); |
| 770 |
|
| 771 |
paintInfo.phase = PaintPhaseForeground; |
| 772 |
renderer()->paint(paintInfo, tx, ty); |
| 773 |
|
| 774 |
paintInfo.phase = PaintPhaseChildOutlines; |
| 775 |
renderer()->paint(paintInfo, tx, ty); |
| 776 |
} |
| 777 |
|
| 778 |
// Now restore our clip. |
| 779 |
restoreClip(context, paintDirtyRect, clipRectToApply); |
| 780 |
|
| 781 |
if (!outlineRect.isEmpty()) { |
| 782 |
// Paint our own outline |
| 783 |
RenderObject::PaintInfo paintInfo(context, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0); |
| 784 |
setClip(context, paintDirtyRect, outlineRect); |
| 785 |
renderer()->paint(paintInfo, tx, ty); |
| 786 |
restoreClip(context, paintDirtyRect, outlineRect); |
| 787 |
} |
| 788 |
|
| 789 |
// Paint any child layers that have overflow. |
| 790 |
Vector<RenderLayer*>* overflowList = m_owningLayer->overflowList(); |
| 791 |
if (overflowList) |
| 792 |
for (Vector<RenderLayer*>::iterator it = overflowList->begin(); it != overflowList->end(); ++it) |
| 793 |
it[0]->paintLayer(rootLayer, context, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); |
| 794 |
|
| 795 |
// Now walk the sorted list of children with positive z-indices. |
| 796 |
Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList(); |
| 797 |
if (posZOrderList) |
| 798 |
for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) |
| 799 |
it[0]->paintLayer(rootLayer, context, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); |
| 800 |
|
| 801 |
if (renderer()->hasMask() && !selectionOnly && !damageRect.isEmpty()) { |
| 802 |
setClip(context, paintDirtyRect, damageRect); |
| 803 |
|
| 804 |
// Paint the mask. |
| 805 |
RenderObject::PaintInfo paintInfo(context, damageRect, PaintPhaseMask, false, paintingRootForRenderer, 0); |
| 806 |
renderer()->paint(paintInfo, tx, ty); |
| 807 |
|
| 808 |
// Restore the clip. |
| 809 |
restoreClip(context, paintDirtyRect, damageRect); |
| 810 |
} |
| 811 |
} |
| 812 |
|
| 813 |
ASSERT(!m_owningLayer->m_usedTransparency); |
| 814 |
} |
| 815 |
|
| 816 |
// Up-call from compositing layer drawing callback. |
| 817 |
void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase drawingPhase, const IntRect& clip) |
| 818 |
{ |
| 819 |
// We have to use the same root as for hit testing, because both methods |
| 820 |
// can compute and cache clipRects. |
| 821 |
IntRect enclosingBBox = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); |
| 822 |
|
| 823 |
IntRect clipRect(clip); |
| 824 |
|
| 825 |
// Set up the coordinate space to be in the layer's rendering coordinates. |
| 826 |
context.translate(-enclosingBBox.x(), -enclosingBBox.y()); |
| 827 |
|
| 828 |
// Offset the clip. |
| 829 |
clipRect.move(enclosingBBox.x(), enclosingBBox.y()); |
| 830 |
|
| 831 |
// The dirtyRect is in the coords of the painting root. |
| 832 |
IntRect dirtyRect = enclosingBBox; |
| 833 |
dirtyRect.intersect(clipRect); |
| 834 |
|
| 835 |
paintIntoLayer(m_owningLayer, &context, dirtyRect, false, PaintRestrictionNone, drawingPhase, renderer()); |
| 836 |
} |
| 837 |
|
| 838 |
FloatPoint RenderLayerBacking::convertToContentsCoordinates(const GraphicsLayer*, const FloatPoint& point) |
| 839 |
{ |
| 840 |
return graphicsLayerToContentsCoordinates(point); |
| 841 |
} |
| 842 |
|
| 843 |
// Compositing layer hit testing works like this: |
| 844 |
// * hitTestLayer() is called on the root. |
| 845 |
// * in compositing mode, that calls hitTestRootLayer() |
| 846 |
// * it calls findHitCompositingLayer(). |
| 847 |
// * findHitCompositingLayer does hitTesting via GraphicsLayers, which involves |
| 848 |
// calling back via contentsContainPoint() to find out |
| 849 |
// if the given point should be considered to be "inside" the layer based on |
| 850 |
// HTML hit testing rules. |
| 851 |
// * Once we've found a hit compositing layer, hitTestRootLayer() then goes on to |
| 852 |
// do a final hitTestLayer() in order to fill in result. |
| 853 |
// |
| 854 |
// FIXME: move to RenderLayerCompositor? |
| 855 |
RenderLayer* RenderLayerBacking::hitTestRootLayer(RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, |
| 856 |
const IntRect& hitTestRect, const IntPoint& hitTestPoint) |
| 857 |
{ |
| 858 |
RenderLayer* hitCompositingLayer = findHitCompositingLayer(rootLayer, request, result, hitTestRect, hitTestPoint); |
| 859 |
if (!hitCompositingLayer) { |
| 860 |
// We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down, |
| 861 |
// return ourselves. We do this so mouse events continue getting delivered after a drag has |
| 862 |
// exited the WebView, and so hit testing over a scrollbar hits the content document. |
| 863 |
if ((request.active || request.mouseUp) && renderer()->isRenderView()) { |
| 864 |
m_owningLayer->renderer()->updateHitTestResult(result, hitTestPoint); |
| 865 |
return m_owningLayer; |
| 866 |
} |
| 867 |
return 0; |
| 868 |
} |
| 869 |
|
| 870 |
// if we hit the root layer, we're done |
| 871 |
if (hitCompositingLayer == m_owningLayer) { |
| 872 |
m_owningLayer->renderer()->updateHitTestResult(result, hitTestPoint); |
| 873 |
return m_owningLayer; |
| 874 |
} |
| 875 |
|
| 876 |
// convert hitTestPoint to coords of the hit layer |
| 877 |
FloatPoint hitPoint = convertPointToLayer(hitTestPoint, hitCompositingLayer); |
| 878 |
IntPoint destHitTestPoint(roundf(hitPoint.x()), roundf(hitPoint.y())); |
| 879 |
|
| 880 |
// convert hitTestRect to the hit layer by mapping a quad, then getting its |
| 881 |
// bounding box |
| 882 |
IntRect destHitTestRect; |
| 883 |
{ |
| 884 |
// FIXME: move into a helper function |
| 885 |
FloatQuad hitTestQuad(hitTestRect); |
| 886 |
GraphicsLayer* destCompositingLayer = hitCompositingLayer->backing()->graphicsLayer(); |
| 887 |
IntSize contentOffset = contentOffsetInCompostingLayer(); |
| 888 |
hitTestQuad.move(contentOffset.width(), contentOffset.height()); |
| 889 |
|
| 890 |
graphicsLayer()->convertQuadToLayer(hitTestQuad, destCompositingLayer); |
| 891 |
|
| 892 |
IntSize destContentOffset = hitCompositingLayer->backing()->contentOffsetInCompostingLayer(); |
| 893 |
hitTestQuad.move(-destContentOffset.width(), -destContentOffset.height()); |
| 894 |
destHitTestRect = enclosingIntRect(hitTestQuad.boundingBox()); |
| 895 |
} |
| 896 |
|
| 897 |
// clear out the state in result that we may have set in contentsContainPoint(), |
| 898 |
// and run hit testing on the hit compositing layer |
| 899 |
result.setInnerNode(0); |
| 900 |
result.setInnerNonSharedNode(0); |
| 901 |
return hitCompositingLayer->hitTestLayer(hitCompositingLayer, request, result, destHitTestRect, destHitTestPoint); |
| 902 |
} |
| 903 |
|
| 904 |
// hitTestPoint and hitTestRect are in the coordinate system of rootLayer |
| 905 |
RenderLayer* RenderLayerBacking::findHitCompositingLayer(RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, const IntRect& hitTestRect, const IntPoint& hitTestPoint) |
| 906 |
{ |
| 907 |
LayerHitTestData hitTestData(rootLayer, request, result, hitTestRect); |
| 908 |
|
| 909 |
// Calculate the clip rects we should use. |
| 910 |
IntRect layerBounds; |
| 911 |
IntRect bgRect; |
| 912 |
IntRect fgRect; |
| 913 |
IntRect outlineRect; |
| 914 |
m_owningLayer->calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect); |
| 915 |
|
| 916 |
// Check our lists are up-to-date. |
| 917 |
ASSERT(!m_owningLayer->isStackingContext() || !m_owningLayer->m_zOrderListsDirty); |
| 918 |
ASSERT(!m_owningLayer->isStackingContext() || !m_owningLayer->m_overflowListDirty); |
| 919 |
|
| 920 |
GraphicsLayer* rootGraphicsLayer = compositor()->rootPlatformLayer(); |
| 921 |
|
| 922 |
// convert hitTestPoint to the coordinate system of the compositing layer |
| 923 |
FloatPoint hitPoint = contentsToGraphicsLayerCoordinates(hitTestPoint); |
| 924 |
|
| 925 |
// We assume here that the result.point() is in the coordinate system of m_graphicsLayer, so we |
| 926 |
// convert to the root layer, since we need to pass superlayer-relative coordinates into |
| 927 |
// the hitTest. |
| 928 |
hitPoint = m_graphicsLayer->convertPointToLayer(hitPoint, rootGraphicsLayer); |
| 929 |
|
| 930 |
// as hitTest is called on LCLayers, contentsContainPoint() is called for each compositing layer |
| 931 |
GraphicsLayer* hitLayer = m_graphicsLayer->hitTest(hitPoint, &hitTestData); |
| 932 |
if (!hitLayer) |
| 933 |
return 0; |
| 934 |
|
| 935 |
// note that hitLayer may be a m_contentsLayer, but we should not need to do anything special |
| 936 |
|
| 937 |
// Convert the point to the coords of the hit GraphicsLayer, which takes |
| 938 |
// layer transforms into account |
| 939 |
hitPoint = rootGraphicsLayer->convertPointToLayer(hitPoint, hitLayer); |
| 940 |
|
| 941 |
// Then convert it back to the coords of the root layer. We do all |
| 942 |
// the hit testing in root-relative coords, because all the clip rects |
| 943 |
// are root-relative (just like painting). |
| 944 |
RenderLayerBacking* hitLayerBacking = static_cast<RenderLayerBacking*>(hitLayer->client()); |
| 945 |
RenderLayer* hitRenderLayer = hitLayerBacking ? hitLayerBacking->owningLayer() : 0; |
| 946 |
ASSERT(hitRenderLayer); |
| 947 |
return hitRenderLayer; |
| 948 |
} |
| 949 |
|
| 950 |
// up-call from compositing layer hit testing machinery. inPoint is in this layer coordinates. |
| 951 |
bool RenderLayerBacking::contentsContainPoint(const GraphicsLayer*, const IntPoint& point, GraphicsLayerPaintingPhase compositePhase, struct LayerHitTestData* hitTestData) |
| 952 |
{ |
| 953 |
RenderLayer* rootLayer = hitTestData->m_rootLayer; |
| 954 |
const HitTestRequest& request = hitTestData->m_request; |
| 955 |
HitTestResult& result = hitTestData->m_result; |
| 956 |
IntRect hitTestRect = hitTestData->m_hitTestRect; |
| 957 |
|
| 958 |
// map hitTestRect to this layer |
| 959 |
FloatQuad hitTestQuad(hitTestRect); |
| 960 |
|
| 961 |
GraphicsLayer* rootCompositingLayer = rootLayer->backing()->graphicsLayer(); |
| 962 |
IntSize rootContentOffset = rootLayer->backing()->contentOffsetInCompostingLayer(); |
| 963 |
hitTestQuad.move(rootContentOffset.width(), rootContentOffset.height()); |
| 964 |
|
| 965 |
rootCompositingLayer->convertQuadToLayer(hitTestQuad, graphicsLayer()); |
| 966 |
|
| 967 |
IntSize contentOffset = contentOffsetInCompostingLayer(); |
| 968 |
hitTestQuad.move(-contentOffset.width(), -contentOffset.height()); |
| 969 |
|
| 970 |
IntRect destHitTestRect = enclosingIntRect(hitTestQuad.boundingBox()); |
| 971 |
hitTestRect = destHitTestRect; |
| 972 |
|
| 973 |
// use this layer as the hit testing root |
| 974 |
rootLayer = m_owningLayer; |
| 975 |
|
| 976 |
// inPoint is already in the coords of this layer |
| 977 |
IntPoint hitTestPoint = point; |
| 978 |
|
| 979 |
// Calculate the clip rects we should use. |
| 980 |
IntRect layerBounds; |
| 981 |
IntRect bgRect; |
| 982 |
IntRect fgRect; |
| 983 |
IntRect outlineRect; |
| 984 |
m_owningLayer->calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect); |
| 985 |
|
| 986 |
RenderLayer* insideLayer = 0; |
| 987 |
|
| 988 |
ASSERT(m_owningLayer->isStackingContext() || (!m_owningLayer->m_posZOrderList || m_owningLayer->m_posZOrderList->size() == 0)); |
| 989 |
|
| 990 |
// FIXME: share this code with hitTestLayer above |
| 991 |
if (compositePhase & GraphicsLayerPaintForegroundMask) { |
| 992 |
// Begin by walking our list of positive layers from highest z-index down to the lowest |
| 993 |
// z-index. Only test non-compositing layers, since the first hitTestLayer will have found |
| 994 |
// any hit compositing layers. |
| 995 |
Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList(); |
| 996 |
if (posZOrderList) { |
| 997 |
for (int i = posZOrderList->size() - 1; i >= 0; --i) { |
| 998 |
RenderLayer* curLayer = posZOrderList->at(i); |
| 999 |
if (!curLayer->isComposited()) { |
| 1000 |
insideLayer = curLayer->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint); |
| 1001 |
if (insideLayer) |
| 1002 |
return true; |
| 1003 |
} |
| 1004 |
} |
| 1005 |
} |
| 1006 |
|
| 1007 |
// Now check our overflow objects. |
| 1008 |
Vector<RenderLayer*>* overflowList = m_owningLayer->overflowList(); |
| 1009 |
if (overflowList) { |
| 1010 |
for (int i = overflowList->size() - 1; i >= 0; --i) { |
| 1011 |
RenderLayer* curLayer = overflowList->at(i); |
| 1012 |
if (!curLayer->isComposited()) { |
| 1013 |
insideLayer = curLayer->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint); |
| 1014 |
if (insideLayer) |
| 1015 |
return true; |
| 1016 |
} |
| 1017 |
} |
| 1018 |
} |
| 1019 |
|
| 1020 |
// Next we want to see if the mouse pos is inside the child RenderObjects of the layer. |
| 1021 |
if (fgRect.contains(hitTestPoint) && |
| 1022 |
renderer()->hitTest(request, result, hitTestPoint, |
| 1023 |
layerBounds.x() - renderer()->xPos(), |
| 1024 |
layerBounds.y() - renderer()->yPos() + renderer()->borderTopExtra(), |
| 1025 |
HitTestDescendants)) { |
| 1026 |
// For positioned generated content, we might still not have a |
| 1027 |
// node by the time we get to the layer level, since none of |
| 1028 |
// the content in the layer has an element. So just walk up |
| 1029 |
// the tree. |
| 1030 |
if (!result.innerNode() || !result.innerNonSharedNode()) { |
| 1031 |
Node* e = m_owningLayer->enclosingElement(); |
| 1032 |
if (!result.innerNode()) |
| 1033 |
result.setInnerNode(e); |
| 1034 |
if (!result.innerNonSharedNode()) |
| 1035 |
result.setInnerNonSharedNode(e); |
| 1036 |
} |
| 1037 |
return true; |
| 1038 |
} |
| 1039 |
|
| 1040 |
// Now check our negative z-index children. |
| 1041 |
Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList(); |
| 1042 |
if (negZOrderList) { |
| 1043 |
for (int i = negZOrderList->size() - 1; i >= 0; --i) { |
| 1044 |
RenderLayer* curLayer = negZOrderList->at(i); |
| 1045 |
if (!curLayer->isComposited()) { |
| 1046 |
insideLayer = negZOrderList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint); |
| 1047 |
if (insideLayer) |
| 1048 |
return true; |
| 1049 |
} |
| 1050 |
} |
| 1051 |
} |
| 1052 |
} |
| 1053 |
|
| 1054 |
if (compositePhase & GraphicsLayerPaintBackgroundMask) { |
| 1055 |
if (bgRect.contains(hitTestPoint) && |
| 1056 |
renderer()->hitTest(request, result, hitTestPoint, |
| 1057 |
layerBounds.x() - renderer()->xPos(), |
| 1058 |
layerBounds.y() - renderer()->yPos() + renderer()->borderTopExtra(), |
| 1059 |
HitTestSelf)) { |
| 1060 |
if (!result.innerNode() || !result.innerNonSharedNode()) { |
| 1061 |
Node* e = m_owningLayer->enclosingElement(); |
| 1062 |
if (!result.innerNode()) |
| 1063 |
result.setInnerNode(e); |
| 1064 |
if (!result.innerNonSharedNode()) |
| 1065 |
result.setInnerNonSharedNode(e); |
| 1066 |
} |
| 1067 |
return true; |
| 1068 |
} |
| 1069 |
} |
| 1070 |
|
| 1071 |
return false; |
| 1072 |
} |
| 1073 |
|
| 1074 |
bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes) |
| 1075 |
{ |
| 1076 |
bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity); |
| 1077 |
bool hasTransform = keyframes.containsProperty(CSSPropertyWebkitTransform); |
| 1078 |
|
| 1079 |
if (!hasOpacity && !hasTransform) |
| 1080 |
return false; |
| 1081 |
|
| 1082 |
GraphicsLayer::TransformValueList transformVector; |
| 1083 |
GraphicsLayer::FloatValueList opacityVector; |
| 1084 |
|
| 1085 |
for (Vector<KeyframeValue>::const_iterator it = keyframes.beginKeyframes(); it != keyframes.endKeyframes(); ++it) { |
| 1086 |
const RenderStyle* keyframeStyle = it->style(); |
| 1087 |
float key = it->key(); |
| 1088 |
|
| 1089 |
if (!keyframeStyle) |
| 1090 |
continue; |
| 1091 |
|
| 1092 |
// get timing function |
| 1093 |
const TimingFunction* tf = keyframeStyle->hasAnimations() ? &((*keyframeStyle->animations()).animation(0)->timingFunction()) : 0; |
| 1094 |
|
| 1095 |
if (hasTransform) |
| 1096 |
transformVector.insert(key, &(keyframeStyle->transform()), tf); |
| 1097 |
|
| 1098 |
if (hasOpacity) |
| 1099 |
opacityVector.insert(key, keyframeStyle->opacity(), tf); |
| 1100 |
} |
| 1101 |
|
| 1102 |
bool didAnimateTransform = !hasTransform; |
| 1103 |
bool didAnimateOpacity = !hasOpacity; |
| 1104 |
|
| 1105 |
if (hasTransform && m_graphicsLayer->animateTransform(transformVector, renderer()->borderBox().size(), anim, beginTime, false)) |
| 1106 |
didAnimateTransform = true; |
| 1107 |
|
| 1108 |
if (hasOpacity && m_graphicsLayer->animateFloat(AnimatedPropertyOpacity, opacityVector, anim, beginTime)) |
| 1109 |
didAnimateOpacity = true; |
| 1110 |
|
| 1111 |
return didAnimateTransform && didAnimateOpacity; |
| 1112 |
} |
| 1113 |
|
| 1114 |
bool RenderLayerBacking::startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle) |
| 1115 |
{ |
| 1116 |
bool didAnimate = false; |
| 1117 |
|
| 1118 |
if (property == cAnimateAll || property == (int)CSSPropertyOpacity) { |
| 1119 |
const Animation* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity); |
| 1120 |
if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) { |
| 1121 |
// If beginTime is not 0, we are restarting this transition, so first set the from value |
| 1122 |
// in case it was smashed by a previous animation. |
| 1123 |
if (beginTime > 0) |
| 1124 |
m_graphicsLayer->setOpacity(compositingOpacity(fromStyle->opacity()), 0, 0); |
| 1125 |
|
| 1126 |
if (m_graphicsLayer->setOpacity(compositingOpacity(toStyle->opacity()), opacityAnim, beginTime)) |
| 1127 |
didAnimate = true; |
| 1128 |
} |
| 1129 |
} |
| 1130 |
if (property == cAnimateAll || property == (int)CSSPropertyWebkitTransform) { |
| 1131 |
// We get a TransformOperation, which is a linked list of primitive operations and their arguments. |
| 1132 |
// Arguments can be floats or Length values, which need to be converted to numbers using |
| 1133 |
// val.calcFloatValue(renderer()->width()) (or height()). |
| 1134 |
const Animation* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform); |
| 1135 |
if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) { |
| 1136 |
GraphicsLayer::TransformValueList transformVector; |
| 1137 |
transformVector.insert(0, &fromStyle->transform(), 0); |
| 1138 |
transformVector.insert(1, &toStyle->transform(), 0); |
| 1139 |
if (m_graphicsLayer->animateTransform(transformVector, renderer()->borderBox().size(), transformAnim, beginTime, true)) |
| 1140 |
didAnimate = true; |
| 1141 |
} |
| 1142 |
} |
| 1143 |
|
| 1144 |
return didAnimate; |
| 1145 |
} |
| 1146 |
|
| 1147 |
void RenderLayerBacking::notifyTransitionStarted(const GraphicsLayer*, AnimatedPropertyID property, double time) |
| 1148 |
{ |
| 1149 |
int cssProperty = CSSPropertyInvalid; |
| 1150 |
switch (property) { |
| 1151 |
case AnimatedPropertyInvalid: |
| 1152 |
break; |
| 1153 |
case AnimatedPropertyWebkitTransform: |
| 1154 |
cssProperty = CSSPropertyWebkitTransform; |
| 1155 |
break; |
| 1156 |
case AnimatedPropertyOpacity: |
| 1157 |
cssProperty = CSSPropertyOpacity; |
| 1158 |
break; |
| 1159 |
case AnimatedPropertyBackgroundColor: |
| 1160 |
cssProperty = CSSPropertyBackgroundColor; |
| 1161 |
break; |
| 1162 |
} |
| 1163 |
|
| 1164 |
renderer()->notifyTransitionStarted(cssProperty, time); |
| 1165 |
} |
| 1166 |
|
| 1167 |
void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double time) |
| 1168 |
{ |
| 1169 |
renderer()->notifyAnimationStarted(time); |
| 1170 |
} |
| 1171 |
|
| 1172 |
void RenderLayerBacking::animationFinished(const String& name, int index, bool reset) |
| 1173 |
{ |
| 1174 |
m_graphicsLayer->removeFinishedAnimations(name, index, reset); |
| 1175 |
} |
| 1176 |
|
| 1177 |
void RenderLayerBacking::transitionFinished(int property) |
| 1178 |
{ |
| 1179 |
m_graphicsLayer->removeFinishedTransitions(property); |
| 1180 |
} |
| 1181 |
|
| 1182 |
void RenderLayerBacking::suspendAnimations() |
| 1183 |
{ |
| 1184 |
m_graphicsLayer->suspendAnimations(); |
| 1185 |
} |
| 1186 |
|
| 1187 |
void RenderLayerBacking::resumeAnimations() |
| 1188 |
{ |
| 1189 |
m_graphicsLayer->resumeAnimations(); |
| 1190 |
} |
| 1191 |
|
| 1192 |
FloatPoint RenderLayerBacking::convertPointToLayer(const FloatPoint& point, RenderLayer* targetLayer) |
| 1193 |
{ |
| 1194 |
RenderLayer* srcCompLayer = compositor()->enclosingCompositingLayer(m_owningLayer); |
| 1195 |
RenderLayer* destCompLayer = compositor()->enclosingCompositingLayer(targetLayer); |
| 1196 |
|
| 1197 |
FloatPoint srcPoint(point); |
| 1198 |
|
| 1199 |
// EnclosingCompositingLayer doesn't guarantee that a compositing layer has been created yet |
| 1200 |
// FIXME: this should never happen |
| 1201 |
if (!srcCompLayer->isComposited() || !destCompLayer->isComposited()) { |
| 1202 |
#ifndef NDEBUG |
| 1203 |
fprintf(stderr, "convertPointToLayer bailing because source or target doesn't have compositing layer"); |
| 1204 |
#endif |
| 1205 |
// FIXME: sucky absolute logic |
| 1206 |
FloatPoint srcPos = renderer()->localToAbsolute(); |
| 1207 |
FloatPoint dstPos = targetLayer->renderer()->localToAbsolute(); |
| 1208 |
|
| 1209 |
srcPoint += (dstPos - srcPos); |
| 1210 |
return srcPoint; |
| 1211 |
} |
| 1212 |
|
| 1213 |
if (srcCompLayer != m_owningLayer) { |
| 1214 |
int x = 0, y = 0; |
| 1215 |
m_owningLayer->convertToLayerCoords(srcCompLayer, x, y); |
| 1216 |
srcPoint.move(x, y); |
| 1217 |
} |
| 1218 |
|
| 1219 |
// convert from RenderLayer to GraphicsLayer coords |
| 1220 |
srcPoint = contentsToGraphicsLayerCoordinates(srcPoint); |
| 1221 |
// map to the dest layer |
| 1222 |
GraphicsLayer* srcPlatformLayer = srcCompLayer->backing()->graphicsLayer(); |
| 1223 |
GraphicsLayer* dstPlatformLayer = destCompLayer->backing()->graphicsLayer(); |
| 1224 |
FloatPoint destPoint = srcPlatformLayer->convertPointToLayer(srcPoint, dstPlatformLayer); |
| 1225 |
// convert back from GraphicsLayer to RenderLayer coords |
| 1226 |
destPoint = destCompLayer->backing()->graphicsLayerToContentsCoordinates(destPoint); |
| 1227 |
|
| 1228 |
if (destCompLayer != targetLayer) { |
| 1229 |
int x = 0, y = 0; |
| 1230 |
targetLayer->convertToLayerCoords(destCompLayer, x, y); |
| 1231 |
destPoint.move(-x, -y); |
| 1232 |
} |
| 1233 |
|
| 1234 |
return destPoint; |
| 1235 |
} |
| 1236 |
|
| 1237 |
// inPoint is relative to our renderer() |
| 1238 |
FloatPoint RenderLayerBacking::convertToPageUsingCompositingLayer(const FloatPoint& inPoint) |
| 1239 |
{ |
| 1240 |
RenderLayer* docLayer = m_owningLayer->enclosingDocumentLayer(); |
| 1241 |
return convertPointToLayer(inPoint, docLayer); |
| 1242 |
} |
| 1243 |
|
| 1244 |
// inPoint is relative to the document |
| 1245 |
FloatPoint RenderLayerBacking::convertFromPageUsingCompositingLayer(const FloatPoint& inPoint) |
| 1246 |
{ |
| 1247 |
RenderLayer* docLayer = m_owningLayer->enclosingDocumentLayer(); |
| 1248 |
return docLayer->backing()->convertPointToLayer(inPoint, m_owningLayer); |
| 1249 |
} |
| 1250 |
|
| 1251 |
void RenderLayerBacking::convertQuadToPageUsingCompositingLayer(FloatQuad& quad) |
| 1252 |
{ |
| 1253 |
RenderLayer* docLayer = m_owningLayer->enclosingDocumentLayer(); |
| 1254 |
GraphicsLayer* docCompLayer = docLayer ? docLayer->backing()->graphicsLayer() : 0; |
| 1255 |
ASSERT(docCompLayer); |
| 1256 |
if (!docCompLayer) |
| 1257 |
return; |
| 1258 |
|
| 1259 |
// do the math that contentsToGraphicsLayerCoordinates does |
| 1260 |
IntSize contentOffset = contentOffsetInCompostingLayer(); |
| 1261 |
quad.move(contentOffset.width(), contentOffset.height()); |
| 1262 |
|
| 1263 |
m_graphicsLayer->convertQuadToLayer(quad, docCompLayer); |
| 1264 |
|
| 1265 |
IntSize docContentOffset = docLayer->backing()->contentOffsetInCompostingLayer(); |
| 1266 |
quad.move(-docContentOffset.width(), -docContentOffset.height()); |
| 1267 |
} |
| 1268 |
|
| 1269 |
} // namespace WebCore |
| 1270 |
|
| 1271 |
#endif // USE(ACCELERATED_COMPOSITING) |