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

Refactor painting selection in NGTextFragmentPainter

This patch refactors painting selection, as a follow up to
the mid-ligature support in r750701 <crrev.com/c/2103968>:
1. Avoid calling |SelectionPaintingStyle| and a few other
   functions that are needed only when there is a selection,
   if there is no selection.
2. Collect logic to |SelectionPaintState|.
3. Eliminate |have_selection| and put all state variables
   to |Optional<SelectionPaintState>|.

This patch has no behavior changes.

Bug: 1025341, 982194
Change-Id: I1cd52d281c1191d19dd93f0657906733f3ea1af6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2108207Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Commit-Queue: Koji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#751381}
parent 665132b2
...@@ -87,6 +87,9 @@ struct LayoutSelectionStatus { ...@@ -87,6 +87,9 @@ struct LayoutSelectionStatus {
: start(passed_start), end(passed_end), line_break(passed_line_break) { : start(passed_start), end(passed_end), line_break(passed_line_break) {
DCHECK_LE(start, end); DCHECK_LE(start, end);
} }
bool HasValidRange() const { return start < end; }
bool operator==(const LayoutSelectionStatus& other) const { bool operator==(const LayoutSelectionStatus& other) const {
return start == other.start && end == other.end && return start == other.start && end == other.end &&
line_break == other.line_break; line_break == other.line_break;
......
...@@ -344,20 +344,90 @@ void PaintDocumentMarkers(GraphicsContext& context, ...@@ -344,20 +344,90 @@ void PaintDocumentMarkers(GraphicsContext& context,
} }
} }
template <typename Cursor> class SelectionPaintState {
void ComputeSelectionRect( STACK_ALLOCATED();
const LayoutSelectionStatus& selection_status,
const Cursor& cursor, public:
base::Optional<NGInlineCursor>* inline_cursor_for_block_flow, explicit SelectionPaintState(const NGInlineCursor& containing_block)
const PhysicalOffset& box_offset, : selection_status_(ComputeLayoutSelectionStatus(containing_block)),
base::Optional<PhysicalRect>* selection_rect) { containing_block_(containing_block) {}
DCHECK(!*selection_rect);
const NGInlineCursor& root_inline_cursor = const LayoutSelectionStatus& Status() const { return selection_status_; }
InlineCursorForBlockFlow(cursor, inline_cursor_for_block_flow);
*selection_rect = bool ShouldPaintSelectedTextOnly() const { return paint_selected_text_only_; }
ComputeLocalSelectionRectForText(root_inline_cursor, selection_status);
(*selection_rect)->offset += box_offset; bool ShouldPaintSelectedTextSeparately() const {
} return paint_selected_text_separately_;
}
bool IsSelectionRectComputed() const { return selection_rect_.has_value(); }
void ComputeSelectionStyle(const Document& document,
const ComputedStyle& style,
Node* node,
const PaintInfo& paint_info,
const TextPaintStyle& text_style) {
selection_style_ = TextPainterBase::SelectionPaintingStyle(
document, style, node, /*have_selection*/ true, paint_info, text_style);
paint_selected_text_only_ = (paint_info.phase == PaintPhase::kSelection);
paint_selected_text_separately_ =
!paint_selected_text_only_ && text_style != selection_style_;
}
void ComputeSelectionRect(const PhysicalOffset& box_offset) {
DCHECK(!selection_rect_);
selection_rect_ =
ComputeLocalSelectionRectForText(containing_block_, selection_status_);
selection_rect_->offset += box_offset;
}
// Logic is copied from InlineTextBoxPainter::PaintSelection.
// |selection_start| and |selection_end| should be between
// [text_fragment.StartOffset(), text_fragment.EndOffset()].
void PaintSelectionBackground(GraphicsContext& context,
Node* node,
const Document& document,
const ComputedStyle& style) {
const Color color = SelectionBackgroundColor(document, style, node,
selection_style_.fill_color);
PaintRect(context, *selection_rect_, color);
}
// Paint the selected text only.
void PaintSelectedText(NGTextPainter& text_painter,
unsigned length,
const TextPaintStyle& text_style,
DOMNodeId node_id) {
text_painter.PaintSelectedText(selection_status_.start,
selection_status_.end, length, text_style,
selection_style_, *selection_rect_, node_id);
}
// Paint the text except selected parts. Does nothing if all is selected.
void PaintBeforeAndAfterSelectedText(NGTextPainter& text_painter,
unsigned start_offset,
unsigned end_offset,
unsigned length,
const TextPaintStyle& text_style,
DOMNodeId node_id) {
if (start_offset < selection_status_.start) {
text_painter.Paint(start_offset, selection_status_.start, length,
text_style, node_id);
}
if (selection_status_.end < end_offset) {
text_painter.Paint(selection_status_.end, end_offset, length, text_style,
node_id);
}
}
private:
LayoutSelectionStatus selection_status_;
TextPaintStyle selection_style_;
base::Optional<PhysicalRect> selection_rect_;
const NGInlineCursor& containing_block_;
bool paint_selected_text_only_;
bool paint_selected_text_separately_;
};
} // namespace } // namespace
...@@ -371,20 +441,6 @@ const NGPaintFragment& NGTextPainterCursor::RootPaintFragment() const { ...@@ -371,20 +441,6 @@ const NGPaintFragment& NGTextPainterCursor::RootPaintFragment() const {
return *root_paint_fragment_; return *root_paint_fragment_;
} }
// Logic is copied from InlineTextBoxPainter::PaintSelection.
// |selection_start| and |selection_end| should be between
// [text_fragment.StartOffset(), text_fragment.EndOffset()].
static void PaintSelection(GraphicsContext& context,
Node* node,
const Document& document,
const ComputedStyle& style,
Color text_color,
const PhysicalRect& selection_rect) {
const Color color =
SelectionBackgroundColor(document, style, node, text_color);
PaintRect(context, selection_rect, color);
}
template <typename Cursor> template <typename Cursor>
void NGTextFragmentPainter<Cursor>::PaintSymbol( void NGTextFragmentPainter<Cursor>::PaintSymbol(
const LayoutObject* layout_object, const LayoutObject* layout_object,
...@@ -426,18 +482,16 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info, ...@@ -426,18 +482,16 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
const bool is_printing = paint_info.IsPrinting(); const bool is_printing = paint_info.IsPrinting();
// Determine whether or not we're selected. // Determine whether or not we're selected.
bool have_selection = !is_printing && base::Optional<SelectionPaintState> selection;
paint_info.phase != PaintPhase::kTextClip && if (UNLIKELY(!is_printing && paint_info.phase != PaintPhase::kTextClip &&
layout_object->IsSelected(); layout_object->IsSelected())) {
base::Optional<LayoutSelectionStatus> selection_status;
if (have_selection) {
const NGInlineCursor& root_inline_cursor = const NGInlineCursor& root_inline_cursor =
InlineCursorForBlockFlow(cursor_, &inline_cursor_for_block_flow_); InlineCursorForBlockFlow(cursor_, &inline_cursor_for_block_flow_);
selection_status = ComputeLayoutSelectionStatus(root_inline_cursor); selection.emplace(root_inline_cursor);
DCHECK_LE(selection_status->start, selection_status->end); if (!selection->Status().HasValidRange())
have_selection = selection_status->start < selection_status->end; selection.reset();
} }
if (!have_selection) { if (!selection) {
// When only painting the selection, don't bother to paint if there is none. // When only painting the selection, don't bother to paint if there is none.
if (paint_info.phase == PaintPhase::kSelection) if (paint_info.phase == PaintPhase::kSelection)
return; return;
...@@ -484,11 +538,10 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info, ...@@ -484,11 +538,10 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
Node* node = layout_object->GetNode(); Node* node = layout_object->GetNode();
TextPaintStyle text_style = TextPaintStyle text_style =
TextPainterBase::TextPaintingStyle(document, style, paint_info); TextPainterBase::TextPaintingStyle(document, style, paint_info);
TextPaintStyle selection_style = TextPainterBase::SelectionPaintingStyle( if (UNLIKELY(selection)) {
document, style, node, have_selection, paint_info, text_style); selection->ComputeSelectionStyle(document, style, node, paint_info,
bool paint_selected_text_only = (paint_info.phase == PaintPhase::kSelection); text_style);
bool paint_selected_text_separately = }
!paint_selected_text_only && text_style != selection_style;
// Set our font. // Set our font.
const Font& font = style.GetFont(); const Font& font = style.GetFont();
...@@ -507,18 +560,14 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info, ...@@ -507,18 +560,14 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
// paint selection in same flipped dimension as NGTextPainter. // paint selection in same flipped dimension as NGTextPainter.
const DocumentMarkerVector& markers_to_paint = const DocumentMarkerVector& markers_to_paint =
ComputeMarkersToPaint(node, text_item.IsEllipsis()); ComputeMarkersToPaint(node, text_item.IsEllipsis());
base::Optional<PhysicalRect> selection_rect;
if (paint_info.phase != PaintPhase::kSelection && if (paint_info.phase != PaintPhase::kSelection &&
paint_info.phase != PaintPhase::kTextClip && !is_printing) { paint_info.phase != PaintPhase::kTextClip && !is_printing) {
PaintDocumentMarkers(context, text_item, cursor_.CurrentText(), PaintDocumentMarkers(context, text_item, cursor_.CurrentText(),
markers_to_paint, box_rect.offset, style, markers_to_paint, box_rect.offset, style,
DocumentMarkerPaintPhase::kBackground, nullptr); DocumentMarkerPaintPhase::kBackground, nullptr);
if (have_selection) { if (UNLIKELY(selection)) {
ComputeSelectionRect(*selection_status, cursor_, selection->ComputeSelectionRect(box_rect.offset);
&inline_cursor_for_block_flow_, box_rect.offset, selection->PaintSelectionBackground(context, node, document, style);
&selection_rect);
PaintSelection(context, node, document, style, selection_style.fill_color,
*selection_rect);
} }
} }
...@@ -554,7 +603,7 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info, ...@@ -554,7 +603,7 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
} }
const unsigned length = fragment_paint_info.to - fragment_paint_info.from; const unsigned length = fragment_paint_info.to - fragment_paint_info.from;
if (!paint_selected_text_only) { if (!selection || !selection->ShouldPaintSelectedTextOnly()) {
// Paint text decorations except line-through. // Paint text decorations except line-through.
DecorationInfo decoration_info; DecorationInfo decoration_info;
bool has_line_through_decoration = false; bool has_line_through_decoration = false;
...@@ -583,16 +632,9 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info, ...@@ -583,16 +632,9 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
unsigned start_offset = fragment_paint_info.from; unsigned start_offset = fragment_paint_info.from;
unsigned end_offset = fragment_paint_info.to; unsigned end_offset = fragment_paint_info.to;
if (have_selection && paint_selected_text_separately) { if (UNLIKELY(selection && selection->ShouldPaintSelectedTextSeparately())) {
// Paint only the text that is not selected. selection->PaintBeforeAndAfterSelectedText(
if (start_offset < selection_status->start) { text_painter, start_offset, end_offset, length, text_style, node_id);
text_painter.Paint(start_offset, selection_status->start, length,
text_style, node_id);
}
if (selection_status->end < end_offset) {
text_painter.Paint(selection_status->end, end_offset, length,
text_style, node_id);
}
} else { } else {
text_painter.Paint(start_offset, end_offset, length, text_style, node_id); text_painter.Paint(start_offset, end_offset, length, text_style, node_id);
} }
...@@ -605,17 +647,12 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info, ...@@ -605,17 +647,12 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
} }
} }
if (have_selection && if (UNLIKELY(selection && (selection->ShouldPaintSelectedTextOnly() ||
(paint_selected_text_only || paint_selected_text_separately)) { selection->ShouldPaintSelectedTextSeparately()))) {
// Paint only the text that is selected. // Paint only the text that is selected.
if (!selection_rect) { if (!selection->IsSelectionRectComputed())
ComputeSelectionRect(*selection_status, cursor_, selection->ComputeSelectionRect(box_rect.offset);
&inline_cursor_for_block_flow_, box_rect.offset, selection->PaintSelectedText(text_painter, length, text_style, node_id);
&selection_rect);
}
text_painter.PaintSelectedText(selection_status->start,
selection_status->end, length, text_style,
selection_style, *selection_rect, node_id);
} }
if (paint_info.phase != PaintPhase::kForeground) if (paint_info.phase != PaintPhase::kForeground)
......
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