Commit e744b301 authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[FragmentItem] Use |PaintBlockFlowContents|

Before this patch, |NGFragmentItem| used its own function to
paint inline children of |LayoutBlockFlow|. This patch
changes it to use |PaintBlockFlowContents| by making the
function support |NGFragmentItem|.

Fixes ~45 failiures.

Bug: 982194
Change-Id: I9f4de6c71f85cf14722fcb8b1721719445dd1f08
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1994556Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Commit-Queue: Koji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#731835}
parent 1bb360e0
......@@ -157,6 +157,23 @@ NGInlineCursor NGInlineCursor::CursorForDescendants() const {
return NGInlineCursor();
}
void NGInlineCursor::ExpandRootToContainingBlock() {
if (root_paint_fragment_) {
root_paint_fragment_ = root_paint_fragment_->Root();
return;
}
if (fragment_items_) {
const unsigned index_diff = items_.data() - fragment_items_->Items().data();
DCHECK_LT(index_diff, fragment_items_->Items().size());
const unsigned item_index = item_iter_ - items_.begin();
items_ = fragment_items_->Items();
// Update the iterator to the one for the new span.
MoveToItem(items_.begin() + item_index + index_diff);
return;
}
NOTREACHED();
}
bool NGInlineCursor::HasSoftWrapToNextLine() const {
DCHECK(IsLineBox());
const NGInlineBreakToken& break_token = CurrentInlineBreakToken();
......
......@@ -101,6 +101,12 @@ class CORE_EXPORT NGInlineCursor {
// has no children, returns an empty cursor.
NGInlineCursor CursorForDescendants() const;
// If |this| is created by |CursorForDescendants()| to traverse parts of an
// inline formatting context, expand the traversable range to the containing
// |LayoutBlockFlow|. Does nothing if |this| is for an inline formatting
// context.
void ExpandRootToContainingBlock();
// True if current position has soft wrap to next line. It is error to call
// other than line.
bool HasSoftWrapToNextLine() const;
......
......@@ -181,7 +181,8 @@ Vector<PhysicalRect> BuildBackplate(NGInlineCursor* descendants,
// inlines.
for (; *descendants; descendants->MoveToNext()) {
const NGPaintFragment* child = descendants->CurrentPaintFragment();
DCHECK(child); // TODO(kojii): Support NGFragmentItem
if (!child) // TODO(kojii): Support NGFragmentItem
continue;
const NGPhysicalFragment& child_fragment = child->PhysicalFragment();
if (child_fragment.IsHiddenForPaint() || child_fragment.IsFloating())
continue;
......@@ -232,6 +233,12 @@ PhysicalRect NGBoxFragmentPainter::SelfInkOverflow() const {
->PhysicalSelfVisualOverflowRect();
}
PhysicalRect NGBoxFragmentPainter::ContentsInkOverflow() const {
const NGPhysicalFragment& fragment = PhysicalFragment();
return ToLayoutBox(fragment.GetLayoutObject())
->PhysicalContentsVisualOverflowRect();
}
void NGBoxFragmentPainter::Paint(const PaintInfo& paint_info) {
if (PhysicalFragment().IsPaintedAtomically() &&
!box_fragment_.HasSelfPaintingLayer())
......@@ -384,9 +391,13 @@ void NGBoxFragmentPainter::PaintObject(
paint_offset_to_inline_formatting_context,
descendants_);
} else if (items_) {
// Paint |NGFragmentItems| for this block if we have one.
NGInlineCursor cursor(*items_);
PaintInlineItems(paint_info.ForDescendants(), paint_offset, &cursor);
if (physical_box_fragment.IsBlockFlow()) {
PaintBlockFlowContents(paint_info, paint_offset);
} else {
DCHECK(physical_box_fragment.IsInlineBox());
NGInlineCursor cursor(*items_);
PaintInlineItems(paint_info.ForDescendants(), paint_offset, &cursor);
}
} else if (physical_box_fragment.ChildrenInline()) {
DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK(paint_fragment_);
......@@ -445,14 +456,12 @@ void NGBoxFragmentPainter::PaintBlockFlowContents(
const PhysicalOffset& paint_offset) {
const NGPhysicalBoxFragment& fragment = PhysicalFragment();
const LayoutObject* layout_object = fragment.GetLayoutObject();
DCHECK(fragment.ChildrenInline());
DCHECK(paint_fragment_);
// When the layout-tree gets into a bad state, we can end up trying to paint
// a fragment with inline children, without a paint fragment. See:
// http://crbug.com/1022545
if (!paint_fragment_) {
if ((!paint_fragment_ && !items_) || layout_object->NeedsLayout()) {
NOTREACHED();
return;
}
......@@ -470,7 +479,7 @@ void NGBoxFragmentPainter::PaintBlockFlowContents(
// |LayoutOverflow()|, but this can be approximiated with
// |ContentsInkOverflow()|.
PhysicalRect content_ink_rect = fragment.LocalRect();
content_ink_rect.Unite(paint_fragment_->ContentsInkOverflow());
content_ink_rect.Unite(ContentsInkOverflow());
content_ink_rect.offset += PhysicalOffset(paint_offset);
if (!paint_info.GetCullRect().Intersects(content_ink_rect.ToLayoutRect()))
return;
......@@ -478,7 +487,13 @@ void NGBoxFragmentPainter::PaintBlockFlowContents(
DCHECK(layout_object->IsLayoutBlockFlow());
const auto& layout_block = To<LayoutBlock>(*layout_object);
DCHECK(layout_block.ChildrenInline());
NGInlineCursor children(*paint_fragment_);
if (paint_fragment_) {
NGInlineCursor children(*paint_fragment_);
PaintLineBoxChildren(&children, paint_info.ForDescendants(), paint_offset);
return;
}
DCHECK(items_);
NGInlineCursor children(*items_);
PaintLineBoxChildren(&children, paint_info.ForDescendants(), paint_offset);
}
......@@ -1005,10 +1020,6 @@ void NGBoxFragmentPainter::PaintAllPhasesAtomically(
void NGBoxFragmentPainter::PaintInlineItems(const PaintInfo& paint_info,
const PhysicalOffset& paint_offset,
NGInlineCursor* cursor) {
ScopedPaintTimingDetectorBlockPaintHook
scoped_paint_timing_detector_block_paint_hook;
// TODO(kojii): Copy more from |PaintLineBoxChildren|.
while (*cursor) {
const NGFragmentItem* item = cursor->CurrentItem();
DCHECK(item);
......@@ -1017,19 +1028,15 @@ void NGBoxFragmentPainter::PaintInlineItems(const PaintInfo& paint_info,
case NGFragmentItem::kGeneratedText:
PaintTextItem(*cursor, paint_info, paint_offset);
break;
case NGFragmentItem::kLine:
if (PaintLineBoxItem(*item, paint_info, paint_offset) ==
kSkipChildren) {
cursor->MoveToNextSkippingChildren();
continue;
}
break;
case NGFragmentItem::kBox:
if (PaintBoxItem(*item, paint_info, paint_offset) == kSkipChildren) {
cursor->MoveToNextSkippingChildren();
continue;
}
break;
case NGFragmentItem::kLine:
NOTREACHED();
break;
}
cursor->MoveToNext();
}
......@@ -1102,6 +1109,11 @@ void NGBoxFragmentPainter::PaintLineBoxChildren(
return;
}
if (UNLIKELY(children->IsItemCursor())) {
PaintLineBoxChildItems(children, paint_info, paint_offset);
return;
}
const bool is_horizontal = box_fragment_.Style().IsHorizontalWritingMode();
for (; *children; children->MoveToNextSkippingChildren()) {
const NGPaintFragment* line = children->CurrentPaintFragment();
......@@ -1139,6 +1151,56 @@ void NGBoxFragmentPainter::PaintLineBoxChildren(
}
}
void NGBoxFragmentPainter::PaintLineBoxChildItems(
NGInlineCursor* children,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) {
const bool is_horizontal = box_fragment_.Style().IsHorizontalWritingMode();
for (; *children; children->MoveToNextSkippingChildren()) {
const NGFragmentItem* child_item = children->CurrentItem();
DCHECK(child_item);
// Check if CullRect intersects with this child, only in block direction
// because soft-wrap and <br> needs to paint outside of InkOverflow() in
// inline direction.
const PhysicalOffset& child_offset = paint_offset + child_item->Offset();
const PhysicalRect child_rect = child_item->InkOverflow();
if (is_horizontal) {
LayoutUnit y = child_rect.offset.top + child_offset.top;
if (!paint_info.GetCullRect().IntersectsVerticalRange(
y, y + child_rect.size.height))
continue;
} else {
LayoutUnit x = child_rect.offset.left + child_offset.left;
if (!paint_info.GetCullRect().IntersectsHorizontalRange(
x, x + child_rect.size.width))
continue;
}
if (child_item->Type() == NGFragmentItem::kLine) {
const NGPhysicalLineBoxFragment* line_box_fragment =
child_item->LineBoxFragment();
DCHECK(line_box_fragment);
PaintLineBox(*line_box_fragment, *child_item,
/* line_box_paint_fragment */ nullptr, child_item,
paint_info, child_offset);
NGInlineCursor line_box_cursor = children->CursorForDescendants();
PaintInlineItems(paint_info, paint_offset, &line_box_cursor);
continue;
}
if (const NGPhysicalBoxFragment* child_fragment =
child_item->BoxFragment()) {
if (child_fragment->IsListMarker()) {
PaintBoxItem(*child_item, paint_info, paint_offset);
continue;
}
}
NOTREACHED();
}
}
void NGBoxFragmentPainter::PaintBackplate(NGInlineCursor* line_boxes,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) {
......
......@@ -105,6 +105,9 @@ class NGBoxFragmentPainter : public BoxPainterBase {
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 NGPaintFragment* line_box_paint_fragment,
......@@ -250,6 +253,7 @@ class NGBoxFragmentPainter : public BoxPainterBase {
}
const NGBorderEdges& BorderEdges() const;
PhysicalRect SelfInkOverflow() const;
PhysicalRect ContentsInkOverflow() const;
const NGPhysicalBoxFragment& box_fragment_;
const DisplayItemClient& display_item_client_;
......
......@@ -64,6 +64,26 @@ inline const NGPaintFragment& AsDisplayItemClient(
return cursor.PaintFragment();
}
inline const NGInlineCursor& InlineCursorForBlockFlow(
const NGInlineCursor& cursor,
base::Optional<NGInlineCursor>* storage) {
if (*storage)
return **storage;
*storage = cursor;
(*storage)->ExpandRootToContainingBlock();
return **storage;
}
inline const NGInlineCursor& InlineCursorForBlockFlow(
const NGTextPainterCursor& cursor,
base::Optional<NGInlineCursor>* storage) {
if (*storage)
return **storage;
storage->emplace(cursor.RootPaintFragment());
(*storage)->MoveTo(cursor.PaintFragment());
return **storage;
}
// TODO(yosin): Remove |GetTextFragmentPaintInfo| once the transition to
// |NGFragmentItem| is done. http://crbug.com/982194
inline NGTextFragmentPaintInfo GetTextFragmentPaintInfo(
......@@ -98,28 +118,13 @@ inline std::pair<LayoutUnit, LayoutUnit> GetLineLeftAndRightForOffsets(
// |NGFragmentItem| is done. http://crbug.com/982194
inline LayoutSelectionStatus ComputeLayoutSelectionStatus(
const NGInlineCursor& cursor) {
return cursor.CurrentItem()
->GetLayoutObject()
return cursor.CurrentLayoutObject()
->GetDocument()
.GetFrame()
->Selection()
.ComputeLayoutSelectionStatus(cursor);
}
inline LayoutSelectionStatus ComputeLayoutSelectionStatus(
const NGTextPainterCursor& cursor) {
// Note:: Because of this function is hot, we should not use |NGInlineCursor|
// on paint fragment which requires traversing ancestors to root.
NGInlineCursor inline_cursor(cursor.RootPaintFragment());
inline_cursor.MoveTo(cursor.PaintFragment());
return cursor.CurrentItem()
->GetLayoutObject()
->GetDocument()
.GetFrame()
->Selection()
.ComputeLayoutSelectionStatus(inline_cursor);
}
// TODO(yosin): Remove |ComputeLocalRect| once the transition to
// |NGFragmentItem| is done. http://crbug.com/982194
inline PhysicalRect ComputeLocalRect(const NGFragmentItem& text_item,
......@@ -326,20 +331,11 @@ template <typename Cursor>
NGTextFragmentPainter<Cursor>::NGTextFragmentPainter(const Cursor& cursor)
: cursor_(cursor) {}
static PhysicalRect ComputeLocalSelectionRectForText(
const NGTextPainterCursor& cursor,
const LayoutSelectionStatus& selection_status) {
NGInlineCursor inline_cursor(cursor.RootPaintFragment());
inline_cursor.MoveTo(cursor.PaintFragment());
return ComputeLocalSelectionRectForText(inline_cursor, selection_status);
}
// Logic is copied from InlineTextBoxPainter::PaintSelection.
// |selection_start| and |selection_end| should be between
// [text_fragment.StartOffset(), text_fragment.EndOffset()].
template <typename Cursor>
static void PaintSelection(GraphicsContext& context,
const Cursor& cursor,
const NGInlineCursor& cursor,
Node* node,
const Document& document,
const ComputedStyle& style,
......@@ -400,7 +396,9 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
layout_object->IsSelected();
base::Optional<LayoutSelectionStatus> selection_status;
if (have_selection) {
selection_status = ComputeLayoutSelectionStatus(cursor_);
const NGInlineCursor& root_inline_cursor =
InlineCursorForBlockFlow(cursor_, &inline_cursor_for_block_flow_);
selection_status = ComputeLayoutSelectionStatus(root_inline_cursor);
DCHECK_LE(selection_status->start, selection_status->end);
have_selection = selection_status->start < selection_status->end;
}
......@@ -483,7 +481,9 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
markers_to_paint, box_rect.offset, style,
DocumentMarkerPaintPhase::kBackground, nullptr);
if (have_selection) {
PaintSelection(context, cursor_, node, document, style,
const NGInlineCursor& root_inline_cursor =
InlineCursorForBlockFlow(cursor_, &inline_cursor_for_block_flow_);
PaintSelection(context, root_inline_cursor, node, document, style,
selection_style.fill_color, box_rect, *selection_status);
}
}
......
......@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TEXT_FRAGMENT_PAINTER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TEXT_FRAGMENT_PAINTER_H_
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
......@@ -80,6 +81,7 @@ class NGTextFragmentPainter {
const PhysicalOffset& paint_offset);
const Cursor& cursor_;
base::Optional<NGInlineCursor> inline_cursor_for_block_flow_;
};
extern template class NGTextFragmentPainter<NGTextPainterCursor>;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment