Commit deb6bb60 authored by Yoichi Osato's avatar Yoichi Osato Committed by Commit Bot

Let SelectionPaintRange iterator iterate on a flat tree.

SelectionPaintRange::Iterator iterated LayoutObjects using layout order
but we marks SelectionStatus on flat tree order.
This causes invalidation leak if they are not same order.
Ruby element is a reported example for that.

This patch changes SelectionPaintRange::Iterator iterate on a flat tree
considering first-letter.

Bug: 843144
Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng
Change-Id: I02cbad86e64d0a7781f8fb37e2d13c7aa00228fb
Reviewed-on: https://chromium-review.googlesource.com/1063521
Commit-Queue: Yoichi Osato <yoichio@chromium.org>
Reviewed-by: default avatarXiaocheng Hu <xiaochengh@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569168}
parent f4859e36
......@@ -76,13 +76,49 @@ base::Optional<unsigned> SelectionPaintRange::EndOffset() const {
return end_offset_;
}
static LayoutTextFragment* FirstLetterPartFor(
const LayoutObject* layout_object) {
if (!layout_object->IsText())
return nullptr;
if (!ToLayoutText(layout_object)->IsTextFragment())
return nullptr;
return ToLayoutTextFragment(const_cast<LayoutObject*>(
AssociatedLayoutObjectOf(*layout_object->GetNode(), 0)));
}
static LayoutObject* NextLayoutObjectOnFlatTree(
const LayoutObject& layout_object) {
// If |layout_object| is a first letter part, return remaining part.
if (layout_object.IsText() && ToLayoutText(layout_object).IsTextFragment() &&
!ToLayoutTextFragment(layout_object).IsRemainingTextLayoutObject()) {
const Node* associated_node =
ToLayoutTextFragment(layout_object).AssociatedTextNode();
if (!associated_node)
return nullptr;
return associated_node->GetLayoutObject();
}
// Otherwise, find the first layouted object of following nodes.
const Node* node = layout_object.GetNode();
DCHECK(node);
for (const Node* next = FlatTreeTraversal::Next(*node); next;
next = FlatTreeTraversal::Next(*next)) {
LayoutObject* layout_object = next->GetLayoutObject();
if (!layout_object)
continue;
if (LayoutObject* first_letter = FirstLetterPartFor(layout_object))
return first_letter;
return layout_object;
}
return nullptr;
}
SelectionPaintRange::Iterator::Iterator(const SelectionPaintRange* range) {
if (!range || range->IsNull()) {
current_ = nullptr;
return;
}
current_ = range->StartLayoutObject();
stop_ = range->EndLayoutObject()->NextInPreOrder();
stop_ = NextLayoutObjectOnFlatTree(*range->EndLayoutObject());
}
LayoutObject* SelectionPaintRange::Iterator::operator*() const {
......@@ -92,7 +128,7 @@ LayoutObject* SelectionPaintRange::Iterator::operator*() const {
SelectionPaintRange::Iterator& SelectionPaintRange::Iterator::operator++() {
DCHECK(current_);
current_ = current_->NextInPreOrder();
current_ = NextLayoutObjectOnFlatTree(*current_);
if (current_ && current_ != stop_)
return *this;
......@@ -425,15 +461,6 @@ static base::Optional<unsigned> ComputeEndOffset(
return ToText(layout_node)->length();
}
static LayoutTextFragment* FirstLetterPartFor(LayoutObject* layout_object) {
if (!layout_object->IsText())
return nullptr;
if (!ToLayoutText(layout_object)->IsTextFragment())
return nullptr;
return ToLayoutTextFragment(const_cast<LayoutObject*>(
AssociatedLayoutObjectOf(*layout_object->GetNode(), 0)));
}
static void MarkSelected(SelectedLayoutObjects* selected_objects,
LayoutObject* layout_object,
SelectionState state) {
......
......@@ -76,18 +76,20 @@ using IsTypeOfSimple = bool(const LayoutObject& layout_object);
return layout_object.member_func(); \
}
USING_LAYOUTOBJECT_FUNC(IsBR);
USING_LAYOUTOBJECT_FUNC(IsLayoutBlock);
USING_LAYOUTOBJECT_FUNC(IsLayoutBlockFlow);
USING_LAYOUTOBJECT_FUNC(IsLayoutNGBlockFlow);
USING_LAYOUTOBJECT_FUNC(IsLayoutButton);
USING_LAYOUTOBJECT_FUNC(IsLayoutEmbeddedContent);
USING_LAYOUTOBJECT_FUNC(IsLayoutImage);
USING_LAYOUTOBJECT_FUNC(IsLayoutInline);
USING_LAYOUTOBJECT_FUNC(IsBR);
USING_LAYOUTOBJECT_FUNC(IsLayoutNGBlockFlow);
USING_LAYOUTOBJECT_FUNC(IsListItem);
USING_LAYOUTOBJECT_FUNC(IsListMarker);
USING_LAYOUTOBJECT_FUNC(IsLayoutImage);
USING_LAYOUTOBJECT_FUNC(IsLayoutButton);
USING_LAYOUTOBJECT_FUNC(IsRuby);
USING_LAYOUTOBJECT_FUNC(IsRubyText);
USING_LAYOUTOBJECT_FUNC(IsSVGRoot);
USING_LAYOUTOBJECT_FUNC(IsSVGText);
USING_LAYOUTOBJECT_FUNC(IsLayoutEmbeddedContent);
static IsTypeOf IsLayoutTextFragmentOf(const String& text) {
return WTF::BindRepeating(
......@@ -686,6 +688,41 @@ TEST_F(LayoutSelectionTest, Embed) {
TEST_NO_NEXT_LAYOUT_OBJECT();
}
// http:/crbug.com/843144
TEST_F(LayoutSelectionTest, Ruby) {
Selection().SetSelectionAndEndTyping(
SetSelectionTextToBody("^<ruby>foo<rt>bar</rt></ruby>|"));
Selection().CommitAppearanceIfNeeded();
TEST_NEXT(IsLayoutBlock, kContain, NotInvalidate);
TEST_NEXT(IsRuby, kNone, NotInvalidate);
TEST_NEXT(IsLayoutBlock, kContain, NotInvalidate);
TEST_NEXT(IsRubyText, kContain, NotInvalidate);
TEST_NEXT("bar", kEnd, ShouldInvalidate);
TEST_NEXT(IsLayoutBlock, kContain, NotInvalidate);
TEST_NEXT("foo", kStart, ShouldInvalidate);
TEST_NO_NEXT_LAYOUT_OBJECT();
UpdateAllLifecyclePhases();
TEST_NEXT(IsLayoutBlock, kContain, NotInvalidate);
TEST_NEXT(IsRuby, kNone, NotInvalidate);
TEST_NEXT(IsLayoutBlock, kContain, NotInvalidate);
TEST_NEXT(IsRubyText, kContain, NotInvalidate);
TEST_NEXT("bar", kEnd, NotInvalidate);
TEST_NEXT(IsLayoutBlock, kContain, NotInvalidate);
TEST_NEXT("foo", kStart, NotInvalidate);
TEST_NO_NEXT_LAYOUT_OBJECT();
Selection().ClearLayoutSelection();
TEST_NEXT(IsLayoutBlock, kNone, NotInvalidate);
TEST_NEXT(IsRuby, kNone, NotInvalidate);
TEST_NEXT(IsLayoutBlock, kNone, NotInvalidate);
TEST_NEXT(IsRubyText, kNone, NotInvalidate);
TEST_NEXT("bar", kNone, ShouldInvalidate);
TEST_NEXT(IsLayoutBlock, kNone, NotInvalidate);
TEST_NEXT("foo", kNone, ShouldInvalidate);
TEST_NO_NEXT_LAYOUT_OBJECT();
}
static const NGPaintFragment* FindNGPaintFragmentInternal(
const NGPaintFragment* paint,
const LayoutObject* layout_object) {
......
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