Commit 5d3212da authored by Yoichi Osato's avatar Yoichi Osato Committed by Commit Bot

Stabilize LayoutSelection

This patch stabilizes LayoutSelection by letting it be off from
LayoutObject reference.
Design doc: https://bit.ly/2KT87L9

Algorithm updates:
 Mark SelectionState::kContain to all ascendants of each leaf selected node on flat tree.
 Do nothing while Node/LayoutObject::RemoveChild().
 At prepaint phase, collect all selected LayoutObject from root using kContain on flat tree.

Bug: 843144
Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng;luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Ib4b39c621043d5fe03f46e0ce8b4d2b972e9ed3e
Reviewed-on: https://chromium-review.googlesource.com/1125709Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Reviewed-by: default avatarXiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Yoichi Osato <yoichio@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577114}
parent 7a2c3194
......@@ -57,14 +57,6 @@
{
"object": "RootInlineBox",
"reason": "geometry"
},
{
"object": "LayoutBR BR",
"reason": "selection"
},
{
"object": "InlineTextBox '\n'",
"reason": "selection"
}
]
}
......
......@@ -68,14 +68,6 @@
{
"object": "RootInlineBox",
"reason": "geometry"
},
{
"object": "LayoutBR BR",
"reason": "selection"
},
{
"object": "InlineTextBox '\n'",
"reason": "selection"
}
]
}
......
......@@ -68,14 +68,6 @@
{
"object": "RootInlineBox",
"reason": "geometry"
},
{
"object": "LayoutBR BR",
"reason": "selection"
},
{
"object": "InlineTextBox '\n'",
"reason": "selection"
}
]
}
......
......@@ -68,14 +68,6 @@
{
"object": "RootInlineBox",
"reason": "geometry"
},
{
"object": "LayoutBR BR",
"reason": "selection"
},
{
"object": "InlineTextBox '\n'",
"reason": "selection"
}
]
}
......
......@@ -34,60 +34,6 @@ class LayoutObject;
class NGPaintFragment;
class FrameSelection;
struct LayoutSelectionStatus;
// This class represents a selection range in layout tree for painting and
// paint invalidation.
// The current selection to be painted is represented as 2 pairs of
// (LayoutObject, offset).
// 2 LayoutObjects are only valid for |Text| node without 'transform' or
// 'first-letter'.
// TODO(editing-dev): Clarify the meaning of "offset".
// editing/ passes them as offsets in the DOM tree but layout uses them as
// offset in the layout tree. This doesn't work in the cases of
// CSS first-letter or character transform. See crbug.com/17528.
class SelectionPaintRange {
DISALLOW_NEW();
public:
class Iterator
: public std::iterator<std::input_iterator_tag, LayoutObject*> {
public:
explicit Iterator(const SelectionPaintRange*);
Iterator(const Iterator&) = default;
bool operator==(const Iterator& other) const {
return current_ == other.current_;
}
bool operator!=(const Iterator& other) const { return !operator==(other); }
Iterator& operator++();
LayoutObject* operator*() const;
private:
LayoutObject* current_;
const LayoutObject* stop_;
};
Iterator begin() const { return Iterator(this); };
Iterator end() const { return Iterator(nullptr); };
SelectionPaintRange() = default;
SelectionPaintRange(LayoutObject* start_layout_object,
base::Optional<unsigned> start_offset,
LayoutObject* end_layout_object,
base::Optional<unsigned> end_offset);
bool operator==(const SelectionPaintRange& other) const;
LayoutObject* StartLayoutObject() const;
base::Optional<unsigned> StartOffset() const;
LayoutObject* EndLayoutObject() const;
base::Optional<unsigned> EndOffset() const;
bool IsNull() const { return !start_layout_object_; }
private:
LayoutObject* start_layout_object_ = nullptr;
base::Optional<unsigned> start_offset_ = base::nullopt;
LayoutObject* end_layout_object_ = nullptr;
base::Optional<unsigned> end_offset_ = base::nullopt;
};
class LayoutSelection final : public GarbageCollected<LayoutSelection> {
public:
......@@ -102,6 +48,7 @@ class LayoutSelection final : public GarbageCollected<LayoutSelection> {
IntRect AbsoluteSelectionBounds();
void InvalidatePaintForSelection();
// TODO(yoichio): Remove this function since this doesn't do anything.
void ClearSelection();
base::Optional<unsigned> SelectionStart() const;
base::Optional<unsigned> SelectionEnd() const;
......@@ -116,8 +63,19 @@ class LayoutSelection final : public GarbageCollected<LayoutSelection> {
Member<FrameSelection> frame_selection_;
bool has_pending_selection_ : 1;
SelectionPaintRange paint_range_;
// Each offset represents text offsets on selection edge if it is text.
// For example, suppose we select "f^oo<br><img>|",
// |start_offset_| is 1 and |end_offset_| is nullopt.
// Each of them is only valid for a |Text| node without 'transform' or
// 'first-letter'.
// TODO(editing-dev): Clarify the meaning of "offset".
// editing/ passes them as offsets in the DOM tree but layout uses them as
// offset in the layout tree. This doesn't work in the cases of
// character transform. See crbug.com/17528.
base::Optional<unsigned> start_offset_;
base::Optional<unsigned> end_offset_;
// This is true if at least one LayoutObject has a valid SelectionState.
bool has_selection_;
};
void CORE_EXPORT PrintLayoutObjectForSelection(std::ostream&, LayoutObject*);
......
......@@ -10,25 +10,32 @@
namespace blink {
// Each LayoutObject has a SelectionState and it represents how the
// LayoutObject is selected. This enum is used to paint/invalidate selection
// highlight for the LayoutObject.
enum class SelectionState {
// LayoutObject is not selected.
// The LayoutObject is not selected.
kNone,
// LayoutObject is the start of a selection run and doesn't have children.
// kStart, kInside, kEnd and kStartAndEnd represent the LayoutObject
// is somehow selected to paint and either LayoutText or LayoutReplaced.
// The start of a selection.
kStart,
// LayoutObject is fully encompassed by a selection run and
// doesn't have children.
// Inside a selection.
kInside,
// LayoutObject is the end of a selection run and doesn't have children.
// The end of a selection.
kEnd,
// LayoutObject contains an entire selection run and doesn't have children.
// The LayoutObject contains an entire selection.
kStartAndEnd,
// LayoutObject has at least one LayoutObject child which SelectionState is
// kStart, kInside, kEnd or kStartAndEnd.
// This property is used to invalidate LayoutObject for ::selection style
// change. See LayoutObject::InvalidatePaintForSelection().
// The LayoutObject has at least one LayoutObject child which SelectionState
// is not KNone.
// This property is used to invalidate LayoutObject.
kContain
};
inline bool IsSelected(const SelectionState state) {
return state != SelectionState::kNone && state != SelectionState::kContain;
}
CORE_EXPORT std::ostream& operator<<(std::ostream&, const SelectionState);
} // namespace blink
......
......@@ -108,7 +108,7 @@ void ReplacedPainter::Paint(const PaintInfo& paint_info) {
// want it to run right up to the edges of surrounding content.
bool draw_selection_tint =
local_paint_info.phase == PaintPhase::kForeground &&
layout_replaced_.GetSelectionState() != SelectionState::kNone &&
IsSelected(layout_replaced_.GetSelectionState()) &&
!local_paint_info.IsPrinting();
if (draw_selection_tint && !DrawingRecorder::UseCachedDrawingIfPossible(
local_paint_info.context, layout_replaced_,
......
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