Home | History | Annotate | Download | only in compositing
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "core/rendering/compositing/CompositingInputsUpdater.h"
      7 
      8 #include "core/rendering/RenderBlock.h"
      9 #include "core/rendering/RenderLayer.h"
     10 #include "core/rendering/compositing/CompositedLayerMapping.h"
     11 #include "core/rendering/compositing/RenderLayerCompositor.h"
     12 #include "platform/TraceEvent.h"
     13 
     14 namespace blink {
     15 
     16 CompositingInputsUpdater::CompositingInputsUpdater(RenderLayer* rootRenderLayer)
     17     : m_geometryMap(UseTransforms)
     18     , m_rootRenderLayer(rootRenderLayer)
     19 {
     20 }
     21 
     22 CompositingInputsUpdater::~CompositingInputsUpdater()
     23 {
     24 }
     25 
     26 void CompositingInputsUpdater::update()
     27 {
     28     TRACE_EVENT0("blink", "CompositingInputsUpdater::update");
     29     updateRecursive(m_rootRenderLayer, DoNotForceUpdate, AncestorInfo());
     30 }
     31 
     32 static const RenderLayer* findParentLayerOnClippingContainerChain(const RenderLayer* layer)
     33 {
     34     RenderObject* current = layer->renderer();
     35     while (current) {
     36         if (current->style()->position() == FixedPosition) {
     37             for (current = current->parent(); current && !current->canContainFixedPositionObjects(); current = current->parent()) {
     38                 // All types of clips apply to fixed-position descendants of other fixed-position elements.
     39                 // Note: it's unclear whether this is what the spec says. Firefox does not clip, but Chrome does.
     40                 if (current->style()->position() == FixedPosition && current->hasClipOrOverflowClip()) {
     41                     ASSERT(current->hasLayer());
     42                     return static_cast<const RenderLayerModelObject*>(current)->layer();
     43                 }
     44 
     45                 // CSS clip applies to fixed position elements even for ancestors that are not what the
     46                 // fixed element is positioned with respect to.
     47                 if (current->hasClip()) {
     48                     ASSERT(current->hasLayer());
     49                     return static_cast<const RenderLayerModelObject*>(current)->layer();
     50                 }
     51             }
     52         } else {
     53             current = current->containingBlock();
     54         }
     55 
     56         if (current->hasLayer())
     57             return static_cast<const RenderLayerModelObject*>(current)->layer();
     58         // Having clip or overflow clip forces the RenderObject to become a layer.
     59         ASSERT(!current->hasClipOrOverflowClip());
     60     }
     61     ASSERT_NOT_REACHED();
     62     return 0;
     63 }
     64 
     65 static const RenderLayer* findParentLayerOnContainingBlockChain(const RenderObject* object)
     66 {
     67     for (const RenderObject* current = object; current; current = current->containingBlock()) {
     68         if (current->hasLayer())
     69             return static_cast<const RenderLayerModelObject*>(current)->layer();
     70     }
     71     ASSERT_NOT_REACHED();
     72     return 0;
     73 }
     74 
     75 static bool hasClippedStackingAncestor(const RenderLayer* layer, const RenderLayer* clippingLayer)
     76 {
     77     if (layer == clippingLayer)
     78         return false;
     79     const RenderObject* clippingRenderer = clippingLayer->renderer();
     80     for (const RenderLayer* current = layer->compositingContainer(); current && current != clippingLayer; current = current->compositingContainer()) {
     81         if (current->renderer()->hasClipOrOverflowClip() && !clippingRenderer->isDescendantOf(current->renderer()))
     82             return true;
     83 
     84         if (const RenderObject* container = current->clippingContainer()) {
     85             if (clippingRenderer != container && !clippingRenderer->isDescendantOf(container))
     86                 return true;
     87         }
     88     }
     89     return false;
     90 }
     91 
     92 void CompositingInputsUpdater::updateRecursive(RenderLayer* layer, UpdateType updateType, AncestorInfo info)
     93 {
     94     if (!layer->childNeedsCompositingInputsUpdate() && updateType != ForceUpdate)
     95         return;
     96 
     97     m_geometryMap.pushMappingsToAncestor(layer, layer->parent());
     98 
     99     if (layer->hasCompositedLayerMapping())
    100         info.enclosingCompositedLayer = layer;
    101 
    102     if (layer->needsCompositingInputsUpdate()) {
    103         if (info.enclosingCompositedLayer)
    104             info.enclosingCompositedLayer->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
    105         updateType = ForceUpdate;
    106     }
    107 
    108     if (updateType == ForceUpdate) {
    109         RenderLayer::AncestorDependentCompositingInputs properties;
    110 
    111         if (!layer->isRootLayer()) {
    112             properties.clippedAbsoluteBoundingBox = enclosingIntRect(m_geometryMap.absoluteRect(layer->boundingBoxForCompositingOverlapTest()));
    113             // FIXME: Setting the absBounds to 1x1 instead of 0x0 makes very little sense,
    114             // but removing this code will make JSGameBench sad.
    115             // See https://codereview.chromium.org/13912020/
    116             if (properties.clippedAbsoluteBoundingBox.isEmpty())
    117                 properties.clippedAbsoluteBoundingBox.setSize(IntSize(1, 1));
    118 
    119             IntRect clipRect = pixelSnappedIntRect(layer->clipper().backgroundClipRect(ClipRectsContext(m_rootRenderLayer, AbsoluteClipRects)).rect());
    120             properties.clippedAbsoluteBoundingBox.intersect(clipRect);
    121 
    122             const RenderLayer* parent = layer->parent();
    123             properties.opacityAncestor = parent->isTransparent() ? parent : parent->opacityAncestor();
    124             properties.transformAncestor = parent->hasTransform() ? parent : parent->transformAncestor();
    125             properties.filterAncestor = parent->hasFilter() ? parent : parent->filterAncestor();
    126 
    127             if (info.hasAncestorWithClipOrOverflowClip) {
    128                 const RenderLayer* parentLayerOnClippingContainerChain = findParentLayerOnClippingContainerChain(layer);
    129                 const bool parentHasClipOrOverflowClip = parentLayerOnClippingContainerChain->renderer()->hasClipOrOverflowClip();
    130                 properties.clippingContainer = parentHasClipOrOverflowClip ? parentLayerOnClippingContainerChain->renderer() : parentLayerOnClippingContainerChain->clippingContainer();
    131             }
    132 
    133             if (info.lastScrollingAncestor) {
    134                 const RenderObject* containingBlock = layer->renderer()->containingBlock();
    135                 const RenderLayer* parentLayerOnContainingBlockChain = findParentLayerOnContainingBlockChain(containingBlock);
    136 
    137                 properties.ancestorScrollingLayer = parentLayerOnContainingBlockChain->ancestorScrollingLayer();
    138                 if (parentLayerOnContainingBlockChain->scrollsOverflow())
    139                     properties.ancestorScrollingLayer = parentLayerOnContainingBlockChain;
    140 
    141                 if (layer->renderer()->isOutOfFlowPositioned() && !layer->subtreeIsInvisible()) {
    142                     const RenderObject* lastScroller = info.lastScrollingAncestor->renderer();
    143                     const RenderLayer* clippingLayer = properties.clippingContainer ? properties.clippingContainer->enclosingLayer() : layer->compositor()->rootRenderLayer();
    144                     properties.isUnclippedDescendant = lastScroller != containingBlock && lastScroller->isDescendantOf(containingBlock);
    145                     if (hasClippedStackingAncestor(layer, clippingLayer))
    146                         properties.clipParent = clippingLayer;
    147                 }
    148 
    149                 if (!layer->stackingNode()->isNormalFlowOnly()
    150                     && properties.ancestorScrollingLayer
    151                     && !info.ancestorStackingContext->renderer()->isDescendantOf(properties.ancestorScrollingLayer->renderer()))
    152                     properties.scrollParent = properties.ancestorScrollingLayer;
    153             }
    154         }
    155 
    156         properties.hasAncestorWithClipPath = info.hasAncestorWithClipPath;
    157         layer->updateAncestorDependentCompositingInputs(properties);
    158     }
    159 
    160     if (layer->stackingNode()->isStackingContext())
    161         info.ancestorStackingContext = layer;
    162 
    163     if (layer->scrollsOverflow())
    164         info.lastScrollingAncestor = layer;
    165 
    166     if (layer->renderer()->hasClipOrOverflowClip())
    167         info.hasAncestorWithClipOrOverflowClip = true;
    168 
    169     if (layer->renderer()->hasClipPath())
    170         info.hasAncestorWithClipPath = true;
    171 
    172     RenderLayer::DescendantDependentCompositingInputs descendantProperties;
    173     for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) {
    174         updateRecursive(child, updateType, info);
    175 
    176         descendantProperties.hasDescendantWithClipPath |= child->hasDescendantWithClipPath() || child->renderer()->hasClipPath();
    177         descendantProperties.hasDescendantWithBlendMode |= child->hasDescendantWithBlendMode() || child->renderer()->hasBlendMode();
    178     }
    179 
    180     layer->updateDescendantDependentCompositingInputs(descendantProperties);
    181     layer->didUpdateCompositingInputs();
    182 
    183     m_geometryMap.popMappingsToAncestor(layer->parent());
    184 }
    185 
    186 #if ENABLE(ASSERT)
    187 
    188 void CompositingInputsUpdater::assertNeedsCompositingInputsUpdateBitsCleared(RenderLayer* layer)
    189 {
    190     ASSERT(!layer->childNeedsCompositingInputsUpdate());
    191     ASSERT(!layer->needsCompositingInputsUpdate());
    192 
    193     for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling())
    194         assertNeedsCompositingInputsUpdateBitsCleared(child);
    195 }
    196 
    197 #endif
    198 
    199 } // namespace blink
    200