RenderLayerCompositor.cpp [plain text]
#include "config.h"
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayerCompositor.h"
#include "AnimationController.h"
#include "ChromeClient.h"
#include "CSSPropertyNames.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsLayer.h"
#include "HitTestRequest.h"
#include "HitTestResult.h"
#include "Page.h"
#include "RenderLayerBacking.h"
#include "RenderView.h"
#if PROFILE_LAYER_REBUILD
#include <wtf/CurrentTime.h>
#endif
#ifndef NDEBUG
#include "CString.h"
#include "RenderTreeAsText.h"
#endif
#if ENABLE(3D_RENDERING)
bool WebCoreHas3DRendering = true;
#endif
namespace WebCore {
struct CompositingState {
CompositingState(RenderLayer* compAncestor)
: m_subtreeIsCompositing(false)
, m_compositingAncestor(compAncestor)
#ifndef NDEBUG
, m_depth(0)
#endif
{
}
bool m_subtreeIsCompositing;
RenderLayer* m_compositingAncestor;
#ifndef NDEBUG
int m_depth;
#endif
};
static TransformationMatrix flipTransform()
{
TransformationMatrix flipper;
flipper.flipY();
return flipper;
}
RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView)
: m_renderView(renderView)
, m_rootPlatformLayer(0)
, m_compositing(false)
, m_rootLayerAttached(false)
, m_compositingLayersNeedUpdate(false)
#if PROFILE_LAYER_REBUILD
, m_rootLayerUpdateCount(0)
#endif // PROFILE_LAYER_REBUILD
{
}
RenderLayerCompositor::~RenderLayerCompositor()
{
ASSERT(!m_rootLayerAttached);
delete m_rootPlatformLayer;
}
void RenderLayerCompositor::enableCompositingMode(bool enable )
{
if (enable != m_compositing) {
m_compositing = enable;
if (m_compositing)
ensureRootPlatformLayer();
}
}
void RenderLayerCompositor::setCompositingLayersNeedUpdate(bool needUpdate)
{
if (inCompositingMode()) {
if (!m_compositingLayersNeedUpdate && needUpdate)
scheduleViewUpdate();
m_compositingLayersNeedUpdate = needUpdate;
}
}
void RenderLayerCompositor::scheduleViewUpdate()
{
Frame* frame = m_renderView->frameView()->frame();
Page* page = frame ? frame->page() : 0;
if (!page)
return;
page->chrome()->client()->scheduleViewUpdate();
}
void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot)
{
if (!m_compositingLayersNeedUpdate)
return;
ASSERT(inCompositingMode());
if (!updateRoot) {
m_compositingLayersNeedUpdate = false;
updateRoot = rootRenderLayer();
}
#if PROFILE_LAYER_REBUILD
++m_rootLayerUpdateCount;
double startTime = WTF::currentTime();
#endif
{
CompositingState compState(updateRoot);
computeCompositingRequirements(updateRoot, compState);
}
{
CompositingState compState(updateRoot);
rebuildCompositingLayerTree(updateRoot, compState);
}
#if PROFILE_LAYER_REBUILD
double endTime = WTF::currentTime();
if (updateRoot == rootRenderLayer())
fprintf(stderr, "Update %d: computeCompositingRequirements for the world took %fms\n",
m_rootLayerUpdateCount, 1000.0 * (endTime - startTime));
#endif
ASSERT(updateRoot || !m_compositingLayersNeedUpdate);
}
bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, CompositingChangeRepaint shouldRepaint)
{
bool needsLayer = needsToBeComposited(layer);
bool layerChanged = false;
if (needsLayer) {
enableCompositingMode();
if (!layer->backing()) {
if (shouldRepaint == CompositingChangeRepaintNow)
repaintOnCompositingChange(layer);
layer->ensureBacking();
layerChanged = true;
}
} else {
if (layer->backing()) {
layer->clearBacking();
layerChanged = true;
if (shouldRepaint == CompositingChangeRepaintNow)
repaintOnCompositingChange(layer);
}
}
if (layer->backing() && layer->backing()->updateGraphicsLayerConfiguration())
layerChanged = true;
return layerChanged;
}
void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer)
{
RenderBox* repaintContainer = layer->renderer()->containerForRepaint();
if (!repaintContainer)
repaintContainer = m_renderView;
layer->repaintIncludingNonCompositingDescendants(repaintContainer);
if (repaintContainer == m_renderView) {
m_renderView->frameView()->setNeedsOneShotDrawingSynchronization();
}
}
IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer, IntRect* layerBoundingBox)
{
IntRect boundingBoxRect, unionBounds;
boundingBoxRect = unionBounds = layer->localBoundingBox();
ASSERT(layer->isStackingContext() || (!layer->m_posZOrderList || layer->m_posZOrderList->size() == 0));
Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
if (negZOrderList) {
for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
if (!curLayer->isComposited()) {
IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer);
unionBounds.unite(childUnionBounds);
}
}
}
Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
if (posZOrderList) {
for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
if (!curLayer->isComposited()) {
IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer);
unionBounds.unite(childUnionBounds);
}
}
}
Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
if (normalFlowList) {
for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
RenderLayer* curLayer = (*it);
if (!curLayer->isComposited()) {
IntRect curAbsBounds = calculateCompositedBounds(curLayer, layer);
unionBounds.unite(curAbsBounds);
}
}
}
if (layer->paintsWithTransform()) {
TransformationMatrix* affineTrans = layer->transform();
boundingBoxRect = affineTrans->mapRect(boundingBoxRect);
unionBounds = affineTrans->mapRect(unionBounds);
}
int ancestorRelX = 0, ancestorRelY = 0;
layer->convertToLayerCoords(ancestorLayer, ancestorRelX, ancestorRelY);
unionBounds.move(ancestorRelX, ancestorRelY);
if (layerBoundingBox) {
boundingBoxRect.move(ancestorRelX, ancestorRelY);
*layerBoundingBox = boundingBoxRect;
}
return unionBounds;
}
void RenderLayerCompositor::layerWasAdded(RenderLayer* , RenderLayer* )
{
setCompositingLayersNeedUpdate();
}
void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer* child)
{
if (child->isComposited())
setCompositingParent(child, 0);
if (parent->renderer()->documentBeingDestroyed())
return;
RenderLayer* compLayer = parent->enclosingCompositingLayer();
if (compLayer) {
IntRect ancestorRect = calculateCompositedBounds(child, compLayer);
compLayer->setBackingNeedsRepaintInRect(ancestorRect);
m_renderView->frameView()->setNeedsOneShotDrawingSynchronization();
}
setCompositingLayersNeedUpdate();
}
RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const RenderLayer* layer) const
{
for (RenderLayer* curr = layer->parent(); curr != 0; curr = curr->parent()) {
if (curr->isStackingContext())
return 0;
if (curr->renderer()->hasOverflowClip())
return curr;
}
return 0;
}
void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, struct CompositingState& ioCompState)
{
layer->updateLayerPosition();
layer->updateZOrderLists();
layer->updateNormalFlowList();
layer->setHasCompositingDescendant(false);
layer->setMustOverlayCompositedLayers(ioCompState.m_subtreeIsCompositing);
const bool willBeComposited = needsToBeComposited(layer);
if (!layer->isComposited() && willBeComposited)
repaintOnCompositingChange(layer);
ioCompState.m_subtreeIsCompositing = willBeComposited;
CompositingState childState = ioCompState;
if (willBeComposited)
childState.m_compositingAncestor = layer;
childState.m_subtreeIsCompositing = false;
#ifndef NDEBUG
++childState.m_depth;
#endif
if (layer->isStackingContext()) {
ASSERT(!layer->m_zOrderListsDirty);
Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
if (negZOrderList && negZOrderList->size() > 0) {
for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
computeCompositingRequirements(curLayer, childState);
if (childState.m_subtreeIsCompositing) {
layer->setMustOverlayCompositedLayers(true);
childState.m_compositingAncestor = layer;
}
}
}
}
ASSERT(!layer->m_normalFlowListDirty);
Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
if (normalFlowList && normalFlowList->size() > 0) {
for (Vector<RenderLayer*>::const_iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
RenderLayer* curLayer = (*it);
computeCompositingRequirements(curLayer, childState);
}
}
if (layer->isStackingContext()) {
Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
if (posZOrderList && posZOrderList->size() > 0) {
for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
computeCompositingRequirements(curLayer, childState);
}
}
}
if (childState.m_subtreeIsCompositing &&
(layer->renderer()->hasTransform() || layer->renderer()->style()->opacity() < 1))
layer->setMustOverlayCompositedLayers(true);
if (childState.m_subtreeIsCompositing)
ioCompState.m_subtreeIsCompositing = true;
layer->setHasCompositingDescendant(childState.m_subtreeIsCompositing);
}
void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer)
{
ASSERT(childLayer->isComposited());
ASSERT(!parentLayer || parentLayer->isComposited());
if (parentLayer) {
GraphicsLayer* hostingLayer = parentLayer->backing()->parentForSublayers();
GraphicsLayer* hostedLayer = childLayer->backing()->childForSuperlayers();
hostingLayer->addChild(hostedLayer);
} else
childLayer->backing()->childForSuperlayers()->removeFromParent();
}
void RenderLayerCompositor::removeCompositedChildren(RenderLayer* layer)
{
ASSERT(layer->isComposited());
GraphicsLayer* hostingLayer = layer->backing()->parentForSublayers();
hostingLayer->removeAllChildren();
}
void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer)
{
ASSERT(layer->isComposited());
GraphicsLayer* layerAnchor = layer->backing()->childForSuperlayers();
if (layerAnchor->parent() != m_rootPlatformLayer) {
layerAnchor->removeFromParent();
if (m_rootPlatformLayer)
m_rootPlatformLayer->addChild(layerAnchor);
}
}
void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& ioCompState)
{
bool wasComposited = layer->isComposited();
updateLayerCompositingState(layer, CompositingChangeWillRepaintLater);
if (layer->isRootLayer())
parentInRootLayer(layer);
CompositingState childState = ioCompState;
if (layer->isComposited())
childState.m_compositingAncestor = layer;
#ifndef NDEBUG
++childState.m_depth;
#endif
RenderLayerBacking* layerBacking = layer->backing();
if (layerBacking) {
layerBacking->parentForSublayers()->removeAllChildren();
layerBacking->updateInternalHierarchy();
}
childState.m_subtreeIsCompositing = false;
if (layer->isStackingContext()) {
ASSERT(!layer->m_zOrderListsDirty);
Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
if (negZOrderList && negZOrderList->size() > 0) {
for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
rebuildCompositingLayerTree(curLayer, childState);
if (curLayer->isComposited())
setCompositingParent(curLayer, childState.m_compositingAncestor);
}
}
if (layerBacking && layerBacking->contentsLayer()) {
layerBacking->contentsLayer()->removeFromParent();
GraphicsLayer* hostingLayer = layerBacking->clippingLayer() ? layerBacking->clippingLayer() : layerBacking->graphicsLayer();
hostingLayer->addChild(layerBacking->contentsLayer());
}
}
ASSERT(!layer->m_normalFlowListDirty);
Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
if (normalFlowList && normalFlowList->size() > 0) {
for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
RenderLayer* curLayer = (*it);
rebuildCompositingLayerTree(curLayer, childState);
if (curLayer->isComposited())
setCompositingParent(curLayer, childState.m_compositingAncestor);
}
}
if (layer->isStackingContext()) {
Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
if (posZOrderList && posZOrderList->size() > 0) {
for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
rebuildCompositingLayerTree(curLayer, childState);
if (curLayer->isComposited())
setCompositingParent(curLayer, childState.m_compositingAncestor);
}
}
}
if (layerBacking) {
layerBacking->updateGraphicsLayerGeometry();
} else if (wasComposited) {
repaintOnCompositingChange(layer);
}
}
void RenderLayerCompositor::repaintCompositedLayersAbsoluteRect(const IntRect& absRect)
{
recursiveRepaintLayerRect(rootRenderLayer(), absRect);
}
void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect)
{
if (layer->isComposited())
layer->setBackingNeedsRepaintInRect(rect);
if (layer->hasCompositingDescendant()) {
Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
if (negZOrderList) {
for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
int x = 0, y = 0;
curLayer->convertToLayerCoords(layer, x, y);
IntRect childRect(rect);
childRect.move(-x, -y);
recursiveRepaintLayerRect(curLayer, childRect);
}
}
Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
if (posZOrderList) {
for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
int x = 0, y = 0;
curLayer->convertToLayerCoords(layer, x, y);
IntRect childRect(rect);
childRect.move(-x, -y);
recursiveRepaintLayerRect(curLayer, childRect);
}
}
Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
if (normalFlowList) {
for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
RenderLayer* curLayer = (*it);
int x = 0, y = 0;
curLayer->convertToLayerCoords(layer, x, y);
IntRect childRect(rect);
childRect.move(-x, -y);
recursiveRepaintLayerRect(curLayer, childRect);
}
}
}
}
RenderLayer* RenderLayerCompositor::rootRenderLayer() const
{
return m_renderView->layer();
}
GraphicsLayer* RenderLayerCompositor::rootPlatformLayer() const
{
return m_rootPlatformLayer;
}
void RenderLayerCompositor::didMoveOnscreen()
{
if (!m_rootPlatformLayer)
return;
Frame* frame = m_renderView->frameView()->frame();
Page* page = frame ? frame->page() : 0;
if (!page)
return;
page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer);
m_rootLayerAttached = true;
}
void RenderLayerCompositor::willMoveOffscreen()
{
if (!m_rootPlatformLayer || !m_rootLayerAttached)
return;
Frame* frame = m_renderView->frameView()->frame();
Page* page = frame ? frame->page() : 0;
if (!page)
return;
page->chrome()->client()->attachRootGraphicsLayer(frame, 0);
m_rootLayerAttached = false;
}
void RenderLayerCompositor::updateRootLayerPosition()
{
if (m_rootPlatformLayer) {
FloatSize layerSize(m_renderView->docWidth(), m_renderView->docHeight());
IntSize windowOffset = m_renderView->frameView()->offsetInWindow();
m_rootPlatformLayer->setPosition(FloatPoint(windowOffset.width(), windowOffset.height()));
if (m_renderView->document()->ownerElement()) {
layerSize = FloatSize(m_renderView->frameView()->width(), m_renderView->frameView()->height());
}
m_rootPlatformLayer->setSize(layerSize);
}
}
bool RenderLayerCompositor::has3DContent() const
{
return layerHas3DContent(rootRenderLayer());
}
bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const
{
return requiresCompositingLayer(layer) || layer->mustOverlayCompositedLayers();
}
#define VERBOSE_COMPOSITINGLAYER 0
bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) const
{
#if VERBOSE_COMPOSITINGLAYER
bool gotReason = false;
if (!gotReason && inCompositingMode() && layer->isRootLayer()) {
fprintf(stderr, "RenderLayer %p requires compositing layer because: it's the document root\n", layer);
gotReason = true;
}
if (!gotReason && requiresCompositingForTransform(layer->renderer())) {
fprintf(stderr, "RenderLayer %p requires compositing layer because: it has 3d transform, perspective, backface, or animating transform\n", layer);
gotReason = true;
}
if (!gotReason && layer->renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
fprintf(stderr, "RenderLayer %p requires compositing layer because: it has backface-visibility: hidden\n", layer);
gotReason = true;
}
if (!gotReason && clipsCompositingDescendants(layer)) {
fprintf(stderr, "RenderLayer %p requires compositing layer because: it has overflow clip\n", layer);
gotReason = true;
}
if (!gotReason && requiresCompositingForAnimation(layer->renderer())) {
fprintf(stderr, "RenderLayer %p requires compositing layer because: it has a running transition for opacity or transform\n", layer);
gotReason = true;
}
if (!gotReason)
fprintf(stderr, "RenderLayer %p does not require compositing layer\n", layer);
#endif
return (inCompositingMode() && layer->isRootLayer()) ||
requiresCompositingForTransform(layer->renderer()) ||
layer->renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden ||
clipsCompositingDescendants(layer) ||
requiresCompositingForAnimation(layer->renderer());
}
bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const
{
if (!layer->isComposited() || !layer->parent())
return false;
RenderLayer* compositingAncestor = layer->ancestorCompositingLayer();
if (!compositingAncestor)
return false;
RenderLayer* computeClipRoot = 0;
RenderLayer* curr = layer;
while (curr) {
RenderLayer* next = curr->parent();
if (next == compositingAncestor) {
computeClipRoot = curr;
break;
}
curr = next;
}
if (!computeClipRoot || computeClipRoot == layer)
return false;
ClipRects parentRects;
layer->parentClipRects(computeClipRoot, parentRects, true);
return parentRects.overflowClipRect() != ClipRects::infiniteRect();
}
bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer) const
{
return layer->hasCompositingDescendant() &&
layer->renderer()->hasOverflowClip();
}
bool RenderLayerCompositor::requiresCompositingForTransform(RenderObject* renderer)
{
RenderStyle* style = renderer->style();
return renderer->hasTransform() && (style->transform().has3DOperation() || style->transformStyle3D() == TransformStyle3DPreserve3D || style->hasPerspective());
}
bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer)
{
AnimationController* animController = renderer->animation();
if (animController)
return animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyOpacity) ||
animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyWebkitTransform);
return false;
}
bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* layer) const
{
return (layer->m_negZOrderList && layer->m_negZOrderList->size() > 0);
}
void RenderLayerCompositor::ensureRootPlatformLayer()
{
if (m_rootPlatformLayer)
return;
m_rootPlatformLayer = GraphicsLayer::createGraphicsLayer(0);
m_rootPlatformLayer->setSize(FloatSize(m_renderView->docWidth(), m_renderView->docHeight()));
m_rootPlatformLayer->setPosition(FloatPoint(0, 0));
if (GraphicsLayer::graphicsContextsFlipped())
m_rootPlatformLayer->setChildrenTransform(flipTransform());
m_rootPlatformLayer->setMasksToBounds(true);
didMoveOnscreen();
}
bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const
{
const RenderStyle* style = layer->renderer()->style();
if (style &&
(style->transformStyle3D() == TransformStyle3DPreserve3D ||
style->hasPerspective() ||
style->transform().has3DOperation()))
return true;
if (layer->isStackingContext()) {
Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
if (negZOrderList) {
for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
if (layerHas3DContent(curLayer))
return true;
}
}
Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
if (posZOrderList) {
for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
RenderLayer* curLayer = (*it);
if (layerHas3DContent(curLayer))
return true;
}
}
}
Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
if (normalFlowList) {
for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
RenderLayer* curLayer = (*it);
if (layerHas3DContent(curLayer))
return true;
}
}
return false;
}
void RenderLayerCompositor::setDocumentScale(float scale, RenderLayer* layer)
{
if (!layer)
layer = rootRenderLayer();
layer->setDocumentScale(scale);
if (layer->isStackingContext()) {
Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
if (negZOrderList) {
for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it)
setDocumentScale(scale, *it);
}
Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
if (posZOrderList) {
for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it)
setDocumentScale(scale, *it);
}
}
Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
if (normalFlowList) {
for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it)
setDocumentScale(scale, *it);
}
}
}
#endif // USE(ACCELERATED_COMPOSITING)