blob: 4c433b31448e6fd967df910d3918fbd5024354a9 [file] [log] [blame]
// Copyright 2017 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 THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_BOX_FRAGMENT_PAINTER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_BOX_FRAGMENT_PAINTER_H_
#include "third_party/blink/renderer/core/layout/api/hit_test_action.h"
#include "third_party/blink/renderer/core/layout/background_bleed_avoidance.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/paint/box_painter_base.h"
#include "third_party/blink/renderer/platform/geometry/layout_point.h"
#include "third_party/blink/renderer/platform/geometry/layout_size.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
class BoxDecorationData;
class FillLayer;
class HitTestLocation;
class HitTestResult;
class NGFragmentItems;
class NGInlineCursor;
class NGInlineBackwardCursor;
class NGInlineBoxFragmentPainter;
class NGPhysicalFragment;
class ScopedPaintState;
struct PaintInfo;
// Painter for LayoutNG box fragments, paints borders and background. Delegates
// to NGTextFragmentPainter to paint line box fragments.
class CORE_EXPORT NGBoxFragmentPainter : public BoxPainterBase {
STACK_ALLOCATED();
public:
NGBoxFragmentPainter(const NGPhysicalBoxFragment&);
// Construct for an inline box.
NGBoxFragmentPainter(const NGInlineCursor& inline_box_cursor,
const NGFragmentItem& item,
const NGPhysicalBoxFragment& fragment);
void Paint(const PaintInfo&);
// Routes single PaintPhase to actual painters, and traverses children.
void PaintObject(const PaintInfo&,
const PhysicalOffset&,
bool suppress_box_decoration_background = false);
// Hit tests this box fragment.
// @param physical_offset Physical offset of this box fragment in the
// coordinate space of |hit_test_location|.
// TODO(eae): Change to take a HitTestResult pointer instead as it mutates.
bool NodeAtPoint(HitTestResult&,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction);
bool NodeAtPoint(HitTestResult&,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
const PhysicalOffset& inline_root_offset,
HitTestAction);
bool HitTestAllPhases(HitTestResult&,
const HitTestLocation&,
const PhysicalOffset& accumulated_offset,
HitTestFilter = kHitTestAll);
void PaintBoxDecorationBackgroundWithRectImpl(const PaintInfo&,
const PhysicalRect&,
const BoxDecorationData&);
IntRect VisualRect(const PhysicalOffset& paint_offset);
protected:
LayoutRectOutsets ComputeBorders() const override;
LayoutRectOutsets ComputePadding() const override;
BoxPainterBase::FillLayerInfo GetFillLayerInfo(
const Color&,
const FillLayer&,
BackgroundBleedAvoidance,
bool is_painting_scrolling_background) const override;
bool IsPaintingScrollingBackground(const PaintInfo&) const override;
void PaintTextClipMask(GraphicsContext&,
const IntRect& mask_rect,
const PhysicalOffset& paint_offset,
bool object_has_multiple_boxes) override;
void PaintTextClipMask(const PaintInfo& paint_info,
PhysicalOffset paint_offset,
NGInlineBoxFragmentPainter* inline_box_painter);
PhysicalRect AdjustRectForScrolledContent(
const PaintInfo&,
const BoxPainterBase::FillLayerInfo&,
const PhysicalRect&) override;
private:
NGBoxFragmentPainter(const NGPhysicalBoxFragment&,
const DisplayItemClient& display_item_client,
const NGInlineCursor* inline_box_cursor = nullptr,
const NGFragmentItem* = nullptr);
enum MoveTo { kDontSkipChildren, kSkipChildren };
bool ShouldPaint(const ScopedPaintState&) const;
void PaintBoxDecorationBackground(const PaintInfo&,
const PhysicalOffset& paint_offset,
bool suppress_box_decoration_background);
// |visual_rect| is for the drawing display item, covering overflowing box
// shadows and border image outsets. |paint_rect| is the border box rect in
// paint coordinates.
void PaintBoxDecorationBackgroundWithRect(const PaintInfo&,
const IntRect& visual_rect,
const PhysicalRect& paint_rect,
const DisplayItemClient&);
void PaintColumnRules(const PaintInfo&, const PhysicalOffset& paint_offset);
void PaintInternal(const PaintInfo&);
void PaintAllPhasesAtomically(const PaintInfo&);
void PaintBlockChildren(const PaintInfo&, PhysicalOffset);
void PaintInlineItems(const PaintInfo&,
const PhysicalOffset& paint_offset,
const PhysicalOffset& parent_offset,
NGInlineCursor* cursor);
void PaintLineBoxChildren(NGInlineCursor* children,
const PaintInfo&,
const PhysicalOffset& paint_offset);
void PaintLineBoxChildItems(NGInlineCursor* children,
const PaintInfo&,
const PhysicalOffset& paint_offset);
void PaintLineBox(const NGPhysicalFragment& line_box_fragment,
const DisplayItemClient& display_item_client,
const NGFragmentItem& line_box_item,
wtf_size_t line_fragment_id,
const PaintInfo&,
const PhysicalOffset& paint_offset);
void PaintBackplate(NGInlineCursor* descendants,
const PaintInfo&,
const PhysicalOffset& paint_offset);
void PaintInlineChildBoxUsingLegacyFallback(const NGPhysicalFragment&,
const PaintInfo&);
void PaintBlockFlowContents(const PaintInfo&,
const PhysicalOffset& paint_offset);
void PaintTextItem(const NGInlineCursor& cursor,
const PaintInfo&,
const PhysicalOffset& paint_offset,
const PhysicalOffset& parent_offset);
void PaintBoxItem(const NGFragmentItem& item,
const NGPhysicalBoxFragment& child_fragment,
const NGInlineCursor& cursor,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset);
void PaintBoxItem(const NGFragmentItem& item,
const NGInlineCursor& cursor,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset,
const PhysicalOffset& parent_offset);
void PaintFloatingItems(const PaintInfo&, NGInlineCursor* cursor);
void PaintFloatingChildren(const NGPhysicalContainerFragment&,
const PaintInfo& paint_info,
const PaintInfo& float_paint_info);
void PaintFloats(const PaintInfo&);
void PaintMask(const PaintInfo&, const PhysicalOffset& paint_offset);
void PaintBackground(const PaintInfo&,
const PhysicalRect&,
const Color& background_color,
BackgroundBleedAvoidance = kBackgroundBleedNone);
void PaintCarets(const PaintInfo&, const PhysicalOffset& paint_offset);
// This should be called in the background paint phase even if there is no
// other painted content.
void RecordScrollHitTestData(const PaintInfo&,
const DisplayItemClient& background_client);
bool ShouldRecordHitTestData(const PaintInfo&);
// This struct has common data needed while traversing trees for the hit
// testing.
struct HitTestContext {
STACK_ALLOCATED();
public:
HitTestContext(HitTestAction action,
const HitTestLocation& location,
const PhysicalOffset& inline_root_offset,
HitTestResult* result)
: action(action),
location(location),
inline_root_offset(inline_root_offset),
result(result) {}
// Add |node| to |HitTestResult|. Returns true if the hit-testing should
// stop.
bool AddNodeToResult(Node* node,
const NGPhysicalBoxFragment* box_fragment,
const PhysicalRect& bounds_rect,
const PhysicalOffset& offset) const;
// Same as |AddNodeToResult|, except that |offset| is in the content
// coordinate system rather than the container coordinate system. They
// differ when |container| is a scroll container.
bool AddNodeToResultWithContentOffset(
Node* node,
const NGPhysicalBoxFragment& container,
const PhysicalRect& bounds_rect,
PhysicalOffset offset) const;
HitTestAction action;
const HitTestLocation& location;
// When traversing within an inline formatting context, this member
// represents the offset of the root of the inline formatting context.
PhysicalOffset inline_root_offset;
// The result is set to this member, but its address does not change during
// the traversal.
HitTestResult* result;
};
// Hit tests the children of a container fragment, which is either
// |box_fragment_|, or one of its child line box fragments.
// @param physical_offset Physical offset of the container fragment's content
// box in paint layer. Note that this includes scrolling offset when the
// container has 'overflow: scroll'.
bool NodeAtPoint(const HitTestContext& hit_test,
const PhysicalOffset& physical_offset);
bool HitTestChildren(const HitTestContext& hit_test,
const PhysicalOffset& physical_offset);
bool HitTestChildren(const HitTestContext& hit_test,
const NGPhysicalBoxFragment& container,
const NGInlineCursor& children,
const PhysicalOffset& physical_offset);
bool HitTestBlockChildren(HitTestResult&,
const HitTestLocation&,
PhysicalOffset,
HitTestAction);
bool HitTestItemsChildren(const HitTestContext& hit_test,
const NGPhysicalBoxFragment& container,
const NGInlineCursor& children);
bool HitTestFloatingChildren(const HitTestContext& hit_test,
const NGPhysicalContainerFragment& container,
const PhysicalOffset& accumulated_offset);
bool HitTestFloatingChildItems(const HitTestContext& hit_test,
const NGInlineCursor& children,
const PhysicalOffset& accumulated_offset);
// Hit tests a box fragment, which is a child of either |box_fragment_|, or
// one of its child line box fragments.
// @param physical_offset Physical offset of the given box fragment in the
// paint layer.
bool HitTestChildBoxFragment(const HitTestContext& hit_test,
const NGPhysicalBoxFragment& fragment,
const NGInlineBackwardCursor& cursor,
const PhysicalOffset& physical_offset);
bool HitTestChildBoxItem(const HitTestContext& hit_test,
const NGPhysicalBoxFragment& container,
const NGFragmentItem& item,
const NGInlineBackwardCursor& cursor);
// Hit tests the given text fragment.
// @param physical_offset Physical offset of the text fragment in paint layer.
bool HitTestTextFragment(const HitTestContext& hit_test,
const NGInlineBackwardCursor& cursor,
const PhysicalOffset& physical_offset);
bool HitTestTextItem(const HitTestContext& hit_test,
const NGFragmentItem& text_item,
const NGInlineBackwardCursor& cursor);
// Hit tests the given line box fragment.
// @param physical_offset Physical offset of the line box fragment in paint
// layer.
bool HitTestLineBoxFragment(const HitTestContext& hit_test,
const NGPhysicalLineBoxFragment& fragment,
const NGInlineBackwardCursor& cursor,
const PhysicalOffset& physical_offset);
// Returns whether the hit test location is completely outside the border box,
// which possibly has rounded corners.
bool HitTestClippedOutByBorder(
const HitTestLocation&,
const PhysicalOffset& border_box_location) const;
bool HitTestOverflowControl(const HitTestContext&,
PhysicalOffset accumulated_offset);
const NGPhysicalBoxFragment& PhysicalFragment() const {
return box_fragment_;
}
const DisplayItemClient& GetDisplayItemClient() const {
return display_item_client_;
}
PhysicalRect SelfInkOverflow() const;
const NGPhysicalBoxFragment& box_fragment_;
const DisplayItemClient& display_item_client_;
const NGFragmentItems* items_;
const NGFragmentItem* box_item_ = nullptr;
const NGInlineCursor* inline_box_cursor_ = nullptr;
};
inline NGBoxFragmentPainter::NGBoxFragmentPainter(
const NGPhysicalBoxFragment& box,
const DisplayItemClient& display_item_client,
const NGInlineCursor* inline_box_cursor,
const NGFragmentItem* box_item)
: BoxPainterBase(&box.GetDocument(), box.Style(), box.GeneratingNode()),
box_fragment_(box),
display_item_client_(display_item_client),
items_(box.Items()),
box_item_(box_item),
inline_box_cursor_(inline_box_cursor) {
DCHECK(box.IsBox() || box.IsRenderedLegend());
DCHECK_EQ(box.PostLayout(), &box);
#if DCHECK_IS_ON()
if (inline_box_cursor_)
DCHECK_EQ(inline_box_cursor_->Current().Item(), box_item_);
if (box_item_)
DCHECK_EQ(box_item_->BoxFragment(), &box);
DCHECK_EQ(box.IsInlineBox(), !!inline_box_cursor_);
DCHECK_EQ(box.IsInlineBox(), !!box_item_);
#endif
}
inline NGBoxFragmentPainter::NGBoxFragmentPainter(
const NGPhysicalBoxFragment& fragment)
: NGBoxFragmentPainter(fragment,
*fragment.GetLayoutObject(),
/* inline_box_cursor */ nullptr,
/* box_item */ nullptr) {}
inline NGBoxFragmentPainter::NGBoxFragmentPainter(
const NGInlineCursor& inline_box_cursor,
const NGFragmentItem& item,
const NGPhysicalBoxFragment& fragment)
: NGBoxFragmentPainter(fragment,
*item.GetDisplayItemClient(),
&inline_box_cursor,
&item) {
DCHECK_EQ(item.BoxFragment(), &fragment);
DCHECK(fragment.IsInlineBox());
}
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_BOX_FRAGMENT_PAINTER_H_