blob: 92af60cdc0f9102efa2a90f3e720e4fb2a880c27 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ObjectPaintProperties_h
#define ObjectPaintProperties_h
#include "core/CoreExport.h"
#include "platform/geometry/LayoutPoint.h"
#include "platform/graphics/paint/ClipPaintPropertyNode.h"
#include "platform/graphics/paint/EffectPaintPropertyNode.h"
#include "platform/graphics/paint/PaintChunkProperties.h"
#include "platform/graphics/paint/PropertyTreeState.h"
#include "platform/graphics/paint/ScrollPaintPropertyNode.h"
#include "platform/graphics/paint/TransformPaintPropertyNode.h"
#include "wtf/PassRefPtr.h"
#include "wtf/PtrUtil.h"
#include "wtf/RefPtr.h"
#include <memory>
namespace blink {
// This class stores property tree related information associated with a
// LayoutObject.
// Currently there are two groups of information:
// 1. The set of property nodes created locally by this LayoutObject.
// 2. The set of property nodes (inherited, or created locally) and paint offset
// that can be used to paint the border box of this LayoutObject (see:
// localBorderBoxProperties).
class CORE_EXPORT ObjectPaintProperties {
WTF_MAKE_NONCOPYABLE(ObjectPaintProperties);
USING_FAST_MALLOC(ObjectPaintProperties);
public:
static std::unique_ptr<ObjectPaintProperties> create() {
return wrapUnique(new ObjectPaintProperties());
}
// The hierarchy of the transform subtree created by a LayoutObject is as
// follows:
// [ paintOffsetTranslation ] Normally paint offset is accumulated
// | without creating a node until we see,
// | for example, transform or
// | position:fixed.
// +---[ transform ] The space created by CSS transform.
// | This is the local border box space,
// | see: localBorderBoxProperties below.
// +---[ perspective ] The space created by CSS perspective.
// | +---[ svgLocalToBorderBoxTransform ] Additional transform for
// children of the outermost root SVG.
// | OR (SVG does not support scrolling.)
// | +---[ scrollTranslation ] The space created by overflow clip.
// +---[ scrollbarPaintOffset ] TODO(trchen): Remove this once we bake
// the paint offset into frameRect. This
// is equivalent to the local border box
// space above, with pixel snapped paint
// offset baked in. It is really
// redundant, but it is a pain to teach
// scrollbars to paint with an offset.
const TransformPaintPropertyNode* paintOffsetTranslation() const {
return m_paintOffsetTranslation.get();
}
const TransformPaintPropertyNode* transform() const {
return m_transform.get();
}
const TransformPaintPropertyNode* perspective() const {
return m_perspective.get();
}
const TransformPaintPropertyNode* svgLocalToBorderBoxTransform() const {
return m_svgLocalToBorderBoxTransform.get();
}
const TransformPaintPropertyNode* scrollTranslation() const {
return m_scrollTranslation.get();
}
const TransformPaintPropertyNode* scrollbarPaintOffset() const {
return m_scrollbarPaintOffset.get();
}
// Auxiliary scrolling information. Includes information such as the hierarchy
// of scrollable areas, the extent that can be scrolled, etc. The actual
// scroll offset is stored in the transform tree (m_scrollTranslation).
const ScrollPaintPropertyNode* scroll() const { return m_scroll.get(); }
const EffectPaintPropertyNode* effect() const { return m_effect.get(); }
// The hierarchy of the clip subtree created by a LayoutObject is as follows:
// [ css clip ]
// [ css clip fixed position]
// [ inner border radius clip ] Clip created by a rounded border with overflow
// clip. This clip is not inset by scrollbars.
// +--- [ overflow clip ] Clip created by overflow clip and is inset by
// the scrollbars.
const ClipPaintPropertyNode* cssClip() const { return m_cssClip.get(); }
const ClipPaintPropertyNode* cssClipFixedPosition() const {
return m_cssClipFixedPosition.get();
}
const ClipPaintPropertyNode* innerBorderRadiusClip() const {
return m_innerBorderRadiusClip.get();
}
const ClipPaintPropertyNode* overflowClip() const {
return m_overflowClip.get();
}
// The complete set of property tree nodes (inherited, or created locally) and
// paint offset that can be used to paint. |paintOffset| is relative to the
// propertyTreeState's transform space.
// See: localBorderBoxProperties and contentsProperties.
struct PropertyTreeStateWithOffset {
PropertyTreeStateWithOffset(LayoutPoint offset, PropertyTreeState treeState)
: paintOffset(offset), propertyTreeState(treeState) {}
LayoutPoint paintOffset;
PropertyTreeState propertyTreeState;
};
// This is a complete set of property nodes and paint offset that should be
// used as a starting point to paint this layout object. This is cached
// because some properties inherit from the containing block chain instead of
// the painting parent and cannot be derived in O(1) during the paint walk.
// For example, <div style='opacity: 0.3; position: relative; margin: 11px;'/>
// would have a paint offset of (11px, 11px) and propertyTreeState.effect()
// would be an effect node with opacity of 0.3 which was created by the div
// itself. Note that propertyTreeState.transform() would not be null but would
// instead point to the transform space setup by div's ancestors.
const PropertyTreeStateWithOffset* localBorderBoxProperties() const {
return m_localBorderBoxProperties.get();
}
void setLocalBorderBoxProperties(
std::unique_ptr<PropertyTreeStateWithOffset> properties) {
m_localBorderBoxProperties = std::move(properties);
}
// This is the complete set of property nodes and paint offset that can be
// used to paint the contents of this object. It is similar to
// localBorderBoxProperties but includes properties (e.g., overflow clip,
// scroll translation) that apply to contents. This is suitable for paint
// invalidation.
ObjectPaintProperties::PropertyTreeStateWithOffset contentsProperties() const;
void clearPaintOffsetTranslation() { m_paintOffsetTranslation = nullptr; }
void clearTransform() { m_transform = nullptr; }
void clearEffect() { m_effect = nullptr; }
void clearCssClip() { m_cssClip = nullptr; }
void clearCssClipFixedPosition() { m_cssClipFixedPosition = nullptr; }
void clearInnerBorderRadiusClip() { m_innerBorderRadiusClip = nullptr; }
void clearOverflowClip() { m_overflowClip = nullptr; }
void clearPerspective() { m_perspective = nullptr; }
void clearSvgLocalToBorderBoxTransform() {
m_svgLocalToBorderBoxTransform = nullptr;
}
void clearScrollTranslation() { m_scrollTranslation = nullptr; }
void clearScrollbarPaintOffset() { m_scrollbarPaintOffset = nullptr; }
void clearScroll() { m_scroll = nullptr; }
template <typename... Args>
TransformPaintPropertyNode* createOrUpdatePaintOffsetTranslation(
Args&&... args) {
return createOrUpdateProperty(m_paintOffsetTranslation,
std::forward<Args>(args)...);
}
template <typename... Args>
TransformPaintPropertyNode* createOrUpdateTransform(Args&&... args) {
return createOrUpdateProperty(m_transform, std::forward<Args>(args)...);
}
template <typename... Args>
TransformPaintPropertyNode* createOrUpdatePerspective(Args&&... args) {
return createOrUpdateProperty(m_perspective, std::forward<Args>(args)...);
}
template <typename... Args>
TransformPaintPropertyNode* createOrUpdateSvgLocalToBorderBoxTransform(
Args&&... args) {
DCHECK(!scrollTranslation()) << "SVG elements cannot scroll so there "
"should never be both a scroll translation "
"and an SVG local to border box transform.";
return createOrUpdateProperty(m_svgLocalToBorderBoxTransform,
std::forward<Args>(args)...);
}
template <typename... Args>
TransformPaintPropertyNode* createOrUpdateScrollTranslation(Args&&... args) {
DCHECK(!svgLocalToBorderBoxTransform())
<< "SVG elements cannot scroll so there should never be both a scroll "
"translation and an SVG local to border box transform.";
return createOrUpdateProperty(m_scrollTranslation,
std::forward<Args>(args)...);
}
template <typename... Args>
TransformPaintPropertyNode* createOrUpdateScrollbarPaintOffset(
Args&&... args) {
return createOrUpdateProperty(m_scrollbarPaintOffset,
std::forward<Args>(args)...);
}
template <typename... Args>
ScrollPaintPropertyNode* createOrUpdateScroll(Args&&... args) {
return createOrUpdateProperty(m_scroll, std::forward<Args>(args)...);
}
template <typename... Args>
EffectPaintPropertyNode* createOrUpdateEffect(Args&&... args) {
return createOrUpdateProperty(m_effect, std::forward<Args>(args)...);
}
template <typename... Args>
ClipPaintPropertyNode* createOrUpdateCssClip(Args&&... args) {
return createOrUpdateProperty(m_cssClip, std::forward<Args>(args)...);
}
template <typename... Args>
ClipPaintPropertyNode* createOrUpdateCssClipFixedPosition(Args&&... args) {
return createOrUpdateProperty(m_cssClipFixedPosition,
std::forward<Args>(args)...);
}
template <typename... Args>
ClipPaintPropertyNode* createOrUpdateInnerBorderRadiusClip(Args&&... args) {
return createOrUpdateProperty(m_innerBorderRadiusClip,
std::forward<Args>(args)...);
}
template <typename... Args>
ClipPaintPropertyNode* createOrUpdateOverflowClip(Args&&... args) {
return createOrUpdateProperty(m_overflowClip, std::forward<Args>(args)...);
}
private:
ObjectPaintProperties() {}
template <typename PaintPropertyNode, typename... Args>
PaintPropertyNode* createOrUpdateProperty(RefPtr<PaintPropertyNode>& field,
Args&&... args) {
if (field)
field->update(std::forward<Args>(args)...);
else
field = PaintPropertyNode::create(std::forward<Args>(args)...);
return field.get();
}
RefPtr<TransformPaintPropertyNode> m_paintOffsetTranslation;
RefPtr<TransformPaintPropertyNode> m_transform;
RefPtr<EffectPaintPropertyNode> m_effect;
RefPtr<ClipPaintPropertyNode> m_cssClip;
RefPtr<ClipPaintPropertyNode> m_cssClipFixedPosition;
RefPtr<ClipPaintPropertyNode> m_innerBorderRadiusClip;
RefPtr<ClipPaintPropertyNode> m_overflowClip;
RefPtr<TransformPaintPropertyNode> m_perspective;
// TODO(pdr): Only LayoutSVGRoot needs this and it should be moved there.
RefPtr<TransformPaintPropertyNode> m_svgLocalToBorderBoxTransform;
RefPtr<TransformPaintPropertyNode> m_scrollTranslation;
RefPtr<TransformPaintPropertyNode> m_scrollbarPaintOffset;
RefPtr<ScrollPaintPropertyNode> m_scroll;
std::unique_ptr<PropertyTreeStateWithOffset> m_localBorderBoxProperties;
};
} // namespace blink
#endif // ObjectPaintProperties_h