Ojan Vafai 6ee8440f27 Walk render tree instead of render layers for paint.
This is the first step of getting rid of RenderLayer.
Instead of walking the RenderLayer tree, wall the RenderObject
tree and add any layers encountered to a vector to paint later.

This patch just consolidates and move the code from RenderLayer
to RenderBox and then changes the children painting to
iterate over the vector. Therefore we walk the RenderObject tree.
We still call out to RenderLayer in a bunch of places.
A followup patch will get rid of those.

R=esprehn@chromium.org

Review URL: https://codereview.chromium.org/899753003
2015-02-06 11:38:25 +11:00

366 lines
17 KiB
C++

/*
* Copyright (C) 2003, 2009, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2013 Intel Corporation. All rights reserved.
*
* Portions are Copyright (C) 1998 Netscape Communications Corporation.
*
* Other contributors:
* Robert O'Callahan <roc+@cs.cmu.edu>
* David Baron <dbaron@fas.harvard.edu>
* Christian Biesinger <cbiesinger@web.de>
* Randall Jesup <rjesup@wgate.com>
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
* Josh Soref <timeless@mac.com>
* Boris Zbarsky <bzbarsky@mit.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Alternatively, the contents of this file may be used under the terms
* of either the Mozilla Public License Version 1.1, found at
* http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
* License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
* (the "GPL"), in which case the provisions of the MPL or the GPL are
* applicable instead of those above. If you wish to allow use of your
* version of this file only under the terms of one of those two
* licenses (the MPL or the GPL) and not to allow others to use your
* version of this file under the LGPL, indicate your decision by
* deletingthe provisions above and replace them with the notice and
* other provisions required by the MPL or the GPL, as the case may be.
* If you do not delete the provisions above, a recipient may use your
* version of this file under any of the LGPL, the MPL or the GPL.
*/
#ifndef SKY_ENGINE_CORE_RENDERING_RENDERLAYER_H_
#define SKY_ENGINE_CORE_RENDERING_RENDERLAYER_H_
#include "sky/engine/core/rendering/LayerPaintingInfo.h"
#include "sky/engine/core/rendering/RenderBox.h"
#include "sky/engine/core/rendering/RenderLayerClipper.h"
#include "sky/engine/core/rendering/RenderLayerFilterInfo.h"
#include "sky/engine/core/rendering/RenderLayerStackingNode.h"
#include "sky/engine/core/rendering/RenderLayerStackingNodeIterator.h"
#include "sky/engine/public/platform/WebBlendMode.h"
#include "sky/engine/wtf/OwnPtr.h"
namespace blink {
class FilterEffectRenderer;
class FilterOperations;
class HitTestRequest;
class HitTestResult;
class HitTestingTransformState;
class RenderStyle;
class TransformationMatrix;
enum BorderRadiusClippingRule { IncludeSelfForBorderRadius, DoNotIncludeSelfForBorderRadius };
enum IncludeSelfOrNot { IncludeSelf, ExcludeSelf };
class RenderLayer {
WTF_MAKE_NONCOPYABLE(RenderLayer);
public:
RenderLayer(RenderLayerModelObject*, LayerType);
~RenderLayer();
String debugName() const;
RenderLayerModelObject* renderer() const { return m_renderer; }
RenderBox* renderBox() const { return m_renderer && m_renderer->isBox() ? toRenderBox(m_renderer) : 0; }
RenderLayer* parent() const { return m_parent; }
RenderLayer* previousSibling() const { return m_previous; }
RenderLayer* nextSibling() const { return m_next; }
RenderLayer* firstChild() const { return m_first; }
RenderLayer* lastChild() const { return m_last; }
void addChild(RenderLayer* newChild, RenderLayer* beforeChild = 0);
RenderLayer* removeChild(RenderLayer*);
void removeOnlyThisLayer();
void insertOnlyThisLayer();
void styleChanged(StyleDifference, const RenderStyle* oldStyle);
// FIXME: Many people call this function while it has out-of-date information.
bool isSelfPaintingLayer() const { return m_isSelfPaintingLayer; }
void setLayerType(LayerType layerType) { m_layerType = layerType; }
bool isTransparent() const { return renderer()->isTransparent(); }
RenderLayer* transparentPaintingAncestor();
void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation);
const RenderLayer* root() const
{
const RenderLayer* curr = this;
while (curr->parent())
curr = curr->parent();
return curr;
}
LayoutPoint location() const;
IntSize size() const;
LayoutRect rect() const { return LayoutRect(location(), size()); }
bool isRootLayer() const { return m_isRootLayer; }
void updateLayerPositionsAfterLayout();
void updateTransformationMatrix();
RenderLayer* renderingContextRoot();
// Our current relative position offset.
const LayoutSize offsetForInFlowPosition() const;
RenderLayerStackingNode* stackingNode() { return m_stackingNode.get(); }
const RenderLayerStackingNode* stackingNode() const { return m_stackingNode.get(); }
bool hasBoxDecorationsOrBackground() const;
bool hasVisibleBoxDecorations() const;
// Returns true if this layer has visible content (ignoring any child layers).
bool isVisuallyNonEmpty() const;
// True if this layer container renderers that paint.
bool hasNonEmptyChildRenderers() const;
bool usedTransparency() const { return m_usedTransparency; }
void clearUsedTransparency() { m_usedTransparency = false; }
// Gets the nearest enclosing positioned ancestor layer (also includes
// the <html> layer and the root layer).
RenderLayer* enclosingPositionedAncestor() const;
RenderLayer* enclosingOverflowClipLayer(IncludeSelfOrNot = IncludeSelf) const;
const RenderLayer* compositingContainer() const;
RenderLayer* enclosingFilterLayer(IncludeSelfOrNot = IncludeSelf) const;
bool hasAncestorWithFilterOutsets() const;
void convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint&) const;
void convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect&) const;
// The two main functions that use the layer system. The paint method
// paints the layers that intersect the damage rect from back to
// front. The hitTest method looks for mouse events by walking
// layers that intersect the point from front to back.
bool hitTest(const HitTestRequest&, HitTestResult&);
bool hitTest(const HitTestRequest&, const HitTestLocation&, HitTestResult&);
// Pass offsetFromRoot if known.
bool intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot = 0) const;
// Bounding box relative to some ancestor layer. Pass offsetFromRoot if known.
LayoutRect physicalBoundingBox(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot = 0) const;
LayoutRect physicalBoundingBoxIncludingReflectionAndStackingChildren(const RenderLayer* ancestorLayer, const LayoutPoint& offsetFromRoot) const;
// If true, this layer's children are included in its bounds for overlap testing.
// We can't rely on the children's positions if this layer has a filter that could have moved the children's pixels around.
bool overlapBoundsIncludeChildren() const { return hasFilter() && renderer()->style()->filter().hasFilterThatMovesPixels(); }
LayoutRect boundingBoxForCompositing(const RenderLayer* ancestorLayer = 0) const;
LayoutUnit staticInlinePosition() const { return m_staticInlinePosition; }
LayoutUnit staticBlockPosition() const { return m_staticBlockPosition; }
void setStaticInlinePosition(LayoutUnit position) { m_staticInlinePosition = position; }
void setStaticBlockPosition(LayoutUnit position) { m_staticBlockPosition = position; }
LayoutSize subpixelAccumulation() const;
void setSubpixelAccumulation(const LayoutSize&);
bool hasTransform() const { return renderer()->hasTransform(); }
// Note that this transform has the transform-origin baked in.
TransformationMatrix* transform() const { return m_transform.get(); }
// currentTransform computes a transform which takes accelerated animations into account. The
// resulting transform has transform-origin baked in. If the layer does not have a transform,
// returns the identity matrix.
TransformationMatrix currentTransform(RenderStyle::ApplyTransformOrigin = RenderStyle::IncludeTransformOrigin) const;
TransformationMatrix renderableTransform() const;
// Get the perspective transform, which is applied to transformed sublayers.
// Returns true if the layer has a -webkit-perspective.
// Note that this transform has the perspective-origin baked in.
TransformationMatrix perspectiveTransform() const;
FloatPoint perspectiveOrigin() const;
bool preserves3D() const { return renderer()->style()->transformStyle3D() == TransformStyle3DPreserve3D; }
bool has3DTransform() const { return m_transform && !m_transform->isAffine(); }
// FIXME: reflections should force transform-style to be flat in the style: https://bugs.webkit.org/show_bug.cgi?id=106959
bool shouldPreserve3D() const { return renderer()->style()->transformStyle3D() == TransformStyle3DPreserve3D; }
bool hasFilter() const { return renderer()->hasFilter(); }
void* operator new(size_t);
// Only safe to call from RenderLayerModelObject::destroyLayer()
void operator delete(void*);
bool paintsWithTransform() const;
FilterOperations computeFilterOperations(const RenderStyle*);
bool paintsWithFilters() const;
bool requiresFullLayerImageForFilters() const;
FilterEffectRenderer* filterRenderer() const
{
RenderLayerFilterInfo* filterInfo = this->filterInfo();
return filterInfo ? filterInfo->renderer() : 0;
}
RenderLayerFilterInfo* filterInfo() const { return hasFilterInfo() ? RenderLayerFilterInfo::filterInfoForRenderLayer(this) : 0; }
RenderLayerFilterInfo* ensureFilterInfo() { return RenderLayerFilterInfo::createFilterInfoForRenderLayerIfNeeded(this); }
void removeFilterInfoIfNeeded()
{
if (hasFilterInfo())
RenderLayerFilterInfo::removeFilterInfoForRenderLayer(this);
}
bool hasFilterInfo() const { return m_hasFilterInfo; }
void setHasFilterInfo(bool hasFilterInfo) { m_hasFilterInfo = hasFilterInfo; }
void updateFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle);
Node* enclosingElement() const;
RenderLayerClipper& clipper() { return m_clipper; }
const RenderLayerClipper& clipper() const { return m_clipper; }
inline bool isPositionedContainer() const
{
// FIXME: This is not in sync with containingBlock.
RenderLayerModelObject* layerRenderer = renderer();
return isRootLayer() || layerRenderer->isPositioned() || hasTransform();
}
void updateOrRemoveFilterEffectRenderer();
void updateSelfPaintingLayer();
void clipToRect(const LayerPaintingInfo&, GraphicsContext*, const ClipRect&, BorderRadiusClippingRule = IncludeSelfForBorderRadius);
void restoreClip(GraphicsContext*, const LayoutRect& paintDirtyRect, const ClipRect&);
private:
// TODO(ojan): Get rid of this. These are basically layer-tree-only paint phases.
enum PaintLayerFlags {
PaintContent,
};
// Bounding box in the coordinates of this layer.
LayoutRect logicalBoundingBox() const;
void setAncestorChainHasSelfPaintingLayerDescendant();
void dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
void setNextSibling(RenderLayer* next) { m_next = next; }
void setPreviousSibling(RenderLayer* prev) { m_previous = prev; }
void setFirstChild(RenderLayer* first) { m_first = first; }
void setLastChild(RenderLayer* last) { m_last = last; }
void updateHasSelfPaintingLayerDescendant() const;
bool hasSelfPaintingLayerDescendant() const
{
if (m_hasSelfPaintingLayerDescendantDirty)
updateHasSelfPaintingLayerDescendant();
ASSERT(!m_hasSelfPaintingLayerDescendantDirty);
return m_hasSelfPaintingLayerDescendant;
}
LayoutPoint renderBoxLocation() const { return renderer()->isBox() ? toRenderBox(renderer())->location() : LayoutPoint(); }
RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
const LayoutRect& hitTestRect, const HitTestLocation&, bool appliedTransform,
const HitTestingTransformState* transformState = 0, double* zOffset = 0);
RenderLayer* hitTestLayerByApplyingTransform(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest&, HitTestResult&,
const LayoutRect& hitTestRect, const HitTestLocation&, const HitTestingTransformState* = 0, double* zOffset = 0,
const LayoutPoint& translationOffset = LayoutPoint());
RenderLayer* hitTestChildren(ChildrenIteration, RenderLayer* rootLayer, const HitTestRequest&, HitTestResult&,
const LayoutRect& hitTestRect, const HitTestLocation&,
const HitTestingTransformState* transformState, double* zOffsetForDescendants, double* zOffset,
const HitTestingTransformState* unflattenedTransformState, bool depthSortDescendants);
PassRefPtr<HitTestingTransformState> createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
const LayoutRect& hitTestRect, const HitTestLocation&,
const HitTestingTransformState* containerTransformState,
const LayoutPoint& translationOffset = LayoutPoint()) const;
bool hitTestContents(const HitTestRequest&, HitTestResult&, const LayoutRect& layerBounds, const HitTestLocation&, HitTestFilter) const;
bool shouldBeSelfPaintingLayer() const;
// FIXME: We should only create the stacking node if needed.
bool requiresStackingNode() const { return true; }
void updateStackingNode();
void updateTransform(const RenderStyle* oldStyle, RenderStyle* newStyle);
void dirty3DTransformedDescendantStatus();
// Both updates the status, and returns true if descendants of this have 3d.
bool update3DTransformedDescendantStatus();
void updateOrRemoveFilterClients();
LayoutRect paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation);
LayerType m_layerType;
// Self-painting layer is an optimization where we avoid the heavy RenderLayer painting
// machinery for a RenderLayer allocated only to handle the overflow clip case.
// FIXME(crbug.com/332791): Self-painting layer should be merged into the overflow-only concept.
unsigned m_isSelfPaintingLayer : 1;
// If have no self-painting descendants, we don't have to walk our children during painting. This can lead to
// significant savings, especially if the tree has lots of non-self-painting layers grouped together (e.g. table cells).
mutable unsigned m_hasSelfPaintingLayerDescendant : 1;
mutable unsigned m_hasSelfPaintingLayerDescendantDirty : 1;
const unsigned m_isRootLayer : 1;
unsigned m_usedTransparency : 1; // Tracks whether we need to close a transparent layer, i.e., whether
// we ended up painting this layer or any descendants (and therefore need to
// blend).
unsigned m_3DTransformedDescendantStatusDirty : 1;
// Set on a stacking context layer that has 3D descendants anywhere
// in a preserves3D hierarchy. Hint to do 3D-aware hit testing.
unsigned m_has3DTransformedDescendant : 1;
unsigned m_hasFilterInfo : 1;
RenderLayerModelObject* m_renderer;
RenderLayer* m_parent;
RenderLayer* m_previous;
RenderLayer* m_next;
RenderLayer* m_first;
RenderLayer* m_last;
// Cached normal flow values for absolute positioned elements with static left/top values.
LayoutUnit m_staticInlinePosition;
LayoutUnit m_staticBlockPosition;
OwnPtr<TransformationMatrix> m_transform;
RenderLayerClipper m_clipper; // FIXME: Lazily allocate?
OwnPtr<RenderLayerStackingNode> m_stackingNode;
LayoutSize m_subpixelAccumulation; // The accumulated subpixel offset of a composited layer's composited bounds compared to absolute coordinates.
};
} // namespace blink
#ifndef NDEBUG
// Outside the WebCore namespace for ease of invocation from gdb.
void showLayerTree(const blink::RenderLayer*);
void showLayerTree(const blink::RenderObject*);
#endif
#endif // SKY_ENGINE_CORE_RENDERING_RENDERLAYER_H_