Commit 4d474821 authored by Yoichi Osato's avatar Yoichi Osato Committed by Commit Bot

[LayoutNG] Paint composition document marker

This patch imports the paint logic from InlineTextBoxPainter, converts DOM offset
to inline offset and paint markers with NGPhysicalTextFragment.

Here is copied functions from InlinTextBoxPainter
to NGTextFragmentPainter:
 PaintSingleMarkerBackgroundRun
 PaintStyleableMarkerUnderline
 PaintDocumentMarkers

This patch fixes:
paint/markers/active-suggestion-marker-basic.html
paint/markers/composition-marker-basic.html

Bug: 850448
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;master.tryserver.chromium.linux:linux_layout_tests_layout_ng;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: I6126bcc3880fe8ba9bd0ebd6262bae4cd7b762be
Reviewed-on: https://chromium-review.googlesource.com/1090601
Commit-Queue: Yoichi Osato <yoichio@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#566769}
parent 591fe7b9
...@@ -120,6 +120,8 @@ class CORE_EXPORT DocumentMarkerController final ...@@ -120,6 +120,8 @@ class CORE_EXPORT DocumentMarkerController final
const Node*, const Node*,
DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers()); DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
DocumentMarkerVector Markers(); DocumentMarkerVector Markers();
// TODO(yoichio): Make const by making PossiblyHasMarkers const.
DocumentMarkerVector ComputeMarkersToPaint(const Node&);
Vector<IntRect> LayoutRectsForTextMatchMarkers(); Vector<IntRect> LayoutRectsForTextMatchMarkers();
void InvalidateRectsForAllTextMatchMarkers(); void InvalidateRectsForAllTextMatchMarkers();
......
...@@ -74,6 +74,7 @@ blink_core_sources("paint") { ...@@ -74,6 +74,7 @@ blink_core_sources("paint") {
"decoration_info.h", "decoration_info.h",
"details_marker_painter.cc", "details_marker_painter.cc",
"details_marker_painter.h", "details_marker_painter.h",
"document_marker_painter.h",
"ellipsis_box_painter.cc", "ellipsis_box_painter.cc",
"ellipsis_box_painter.h", "ellipsis_box_painter.h",
"embedded_content_painter.cc", "embedded_content_painter.cc",
......
// Copyright 2018 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_DOCUMENT_MARKER_PAINTER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_DOCUMENT_MARKER_PAINTER_H_
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
class ComputedStyle;
class FloatRect;
class GraphicsContext;
class LayoutPoint;
class StyleableMarker;
// Document marker painter for both LayoutNG and legacy layout.
// This paints text decorations for spell/grammer check, find-in-page, and
// input method.
class DocumentMarkerPainter {
STATIC_ONLY(DocumentMarkerPainter);
public:
static void PaintStyleableMarkerUnderline(GraphicsContext& context,
const LayoutPoint& box_origin,
const StyleableMarker& marker,
const ComputedStyle& style,
const FloatRect& marker_rect,
LayoutUnit logical_height);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_DOCUMENT_MARKER_PAINTER_H_
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "third_party/blink/renderer/core/layout/text_decoration_offset.h" #include "third_party/blink/renderer/core/layout/text_decoration_offset.h"
#include "third_party/blink/renderer/core/paint/applied_decoration_painter.h" #include "third_party/blink/renderer/core/paint/applied_decoration_painter.h"
#include "third_party/blink/renderer/core/paint/decoration_info.h" #include "third_party/blink/renderer/core/paint/decoration_info.h"
#include "third_party/blink/renderer/core/paint/document_marker_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h" #include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/selection_painting_utils.h" #include "third_party/blink/renderer/core/paint/selection_painting_utils.h"
#include "third_party/blink/renderer/core/paint/text_painter.h" #include "third_party/blink/renderer/core/paint/text_painter.h"
...@@ -511,31 +512,35 @@ void InlineTextBoxPainter::PaintSingleMarkerBackgroundRun( ...@@ -511,31 +512,35 @@ void InlineTextBoxPainter::PaintSingleMarkerBackgroundRun(
} }
DocumentMarkerVector InlineTextBoxPainter::ComputeMarkersToPaint() const { DocumentMarkerVector InlineTextBoxPainter::ComputeMarkersToPaint() const {
// We don't render composition or spelling markers that overlap suggestion
// markers.
Node* const node = inline_text_box_.GetLineLayoutItem().GetNode(); Node* const node = inline_text_box_.GetLineLayoutItem().GetNode();
if (!node) if (!node)
return DocumentMarkerVector(); return DocumentMarkerVector();
DocumentMarkerController& document_marker_controller = DocumentMarkerController& document_marker_controller =
inline_text_box_.GetLineLayoutItem().GetDocument().Markers(); inline_text_box_.GetLineLayoutItem().GetDocument().Markers();
return document_marker_controller.ComputeMarkersToPaint(*node);
}
// TODO(yoichio): Move this to document_marker_controller.cc
DocumentMarkerVector DocumentMarkerController::ComputeMarkersToPaint(
const Node& node) {
// We don't render composition or spelling markers that overlap suggestion
// markers.
// Note: DocumentMarkerController::MarkersFor() returns markers sorted by // Note: DocumentMarkerController::MarkersFor() returns markers sorted by
// start offset. // start offset.
const DocumentMarkerVector& suggestion_markers = const DocumentMarkerVector& suggestion_markers =
document_marker_controller.MarkersFor(node, DocumentMarker::kSuggestion); MarkersFor(&node, DocumentMarker::kSuggestion);
if (suggestion_markers.IsEmpty()) { if (suggestion_markers.IsEmpty()) {
// If there are no suggestion markers, we can return early as a minor // If there are no suggestion markers, we can return early as a minor
// performance optimization. // performance optimization.
DocumentMarker::MarkerTypes remaining_types = DocumentMarker::AllMarkers(); DocumentMarker::MarkerTypes remaining_types = DocumentMarker::AllMarkers();
remaining_types.Remove(DocumentMarker::kSuggestion); remaining_types.Remove(DocumentMarker::kSuggestion);
return document_marker_controller.MarkersFor(node, remaining_types); return MarkersFor(&node, remaining_types);
} }
const DocumentMarkerVector& markers_overridden_by_suggestion_markers = const DocumentMarkerVector& markers_overridden_by_suggestion_markers =
document_marker_controller.MarkersFor( MarkersFor(&node,
node, DocumentMarker::kComposition | DocumentMarker::kSpelling); DocumentMarker::kComposition | DocumentMarker::kSpelling);
Vector<unsigned> suggestion_starts; Vector<unsigned> suggestion_starts;
Vector<unsigned> suggestion_ends; Vector<unsigned> suggestion_ends;
...@@ -588,8 +593,7 @@ DocumentMarkerVector InlineTextBoxPainter::ComputeMarkersToPaint() const { ...@@ -588,8 +593,7 @@ DocumentMarkerVector InlineTextBoxPainter::ComputeMarkersToPaint() const {
DocumentMarker::kSpelling | DocumentMarker::kSpelling |
DocumentMarker::kSuggestion); DocumentMarker::kSuggestion);
markers_to_paint.AppendVector( markers_to_paint.AppendVector(MarkersFor(&node, remaining_types));
document_marker_controller.MarkersFor(node, remaining_types));
return markers_to_paint; return markers_to_paint;
} }
...@@ -1012,20 +1016,32 @@ void InlineTextBoxPainter::PaintStyleableMarkerUnderline( ...@@ -1012,20 +1016,32 @@ void InlineTextBoxPainter::PaintStyleableMarkerUnderline(
const StyleableMarker& marker, const StyleableMarker& marker,
const ComputedStyle& style, const ComputedStyle& style,
const Font& font) { const Font& font) {
if (marker.HasThicknessNone() ||
(marker.UnderlineColor() == Color::kTransparent &&
!marker.UseTextColor()))
return;
if (inline_text_box_.Truncation() == kCFullTruncation) if (inline_text_box_.Truncation() == kCFullTruncation)
return; return;
const PaintOffsets marker_offsets = MarkerPaintStartAndEnd(marker); const PaintOffsets marker_offsets = MarkerPaintStartAndEnd(marker);
const TextRun& run = inline_text_box_.ConstructTextRun(style); const TextRun& run = inline_text_box_.ConstructTextRun(style);
// Pass 0 for height since we only care about the width // Pass 0 for height since we only care about the width
const FloatRect& marker_rect = font.SelectionRectForText( const FloatRect& marker_rect = font.SelectionRectForText(
run, FloatPoint(), 0, marker_offsets.start, marker_offsets.end); run, FloatPoint(), 0, marker_offsets.start, marker_offsets.end);
DocumentMarkerPainter::PaintStyleableMarkerUnderline(
context, box_origin, marker, style, marker_rect,
inline_text_box_.LogicalHeight());
}
// TODO(yoichio) : Move this to document_marker_painter.cc
void DocumentMarkerPainter::PaintStyleableMarkerUnderline(
GraphicsContext& context,
const LayoutPoint& box_origin,
const StyleableMarker& marker,
const ComputedStyle& style,
const FloatRect& marker_rect,
LayoutUnit logical_height) {
if (marker.HasThicknessNone() ||
(marker.UnderlineColor() == Color::kTransparent &&
!marker.UseTextColor()))
return;
// start of line to draw, relative to box_origin.X() // start of line to draw, relative to box_origin.X()
LayoutUnit start = LayoutUnit(marker_rect.X()); LayoutUnit start = LayoutUnit(marker_rect.X());
LayoutUnit width = LayoutUnit(marker_rect.Width()); LayoutUnit width = LayoutUnit(marker_rect.Width());
...@@ -1042,21 +1058,15 @@ void InlineTextBoxPainter::PaintStyleableMarkerUnderline( ...@@ -1042,21 +1058,15 @@ void InlineTextBoxPainter::PaintStyleableMarkerUnderline(
// thick. If there's not enough space the underline will touch or overlap // thick. If there's not enough space the underline will touch or overlap
// characters. // characters.
int line_thickness = 1; int line_thickness = 1;
const SimpleFontData* font_data = const SimpleFontData* font_data = style.GetFont().PrimaryFont();
inline_text_box_.GetLineLayoutItem()
.Style(inline_text_box_.IsFirstLineStyle())
->GetFont()
.PrimaryFont();
DCHECK(font_data); DCHECK(font_data);
int baseline = font_data ? font_data->GetFontMetrics().Ascent() : 0; int baseline = font_data ? font_data->GetFontMetrics().Ascent() : 0;
if (marker.HasThicknessThick() && if (marker.HasThicknessThick() && logical_height.ToInt() - baseline >= 2)
inline_text_box_.LogicalHeight() - baseline >= 2)
line_thickness = 2; line_thickness = 2;
Color marker_color = Color marker_color =
marker.UseTextColor() marker.UseTextColor()
? inline_text_box_.GetLineLayoutItem().Style()->VisitedDependentColor( ? style.VisitedDependentColor(GetCSSPropertyWebkitTextFillColor())
GetCSSPropertyWebkitTextFillColor())
: marker.UnderlineColor(); : marker.UnderlineColor();
context.SetStrokeColor(marker_color); context.SetStrokeColor(marker_color);
...@@ -1064,8 +1074,7 @@ void InlineTextBoxPainter::PaintStyleableMarkerUnderline( ...@@ -1064,8 +1074,7 @@ void InlineTextBoxPainter::PaintStyleableMarkerUnderline(
context.DrawLineForText( context.DrawLineForText(
FloatPoint( FloatPoint(
box_origin.X() + start, box_origin.X() + start,
(box_origin.Y() + inline_text_box_.LogicalHeight() - line_thickness) (box_origin.Y() + logical_height.ToInt() - line_thickness).ToFloat()),
.ToFloat()),
width); width);
} }
......
...@@ -5,10 +5,15 @@ ...@@ -5,10 +5,15 @@
#include "third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h" #include "third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h" #include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/markers/composition_marker.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
#include "third_party/blink/renderer/core/editing/markers/text_match_marker.h"
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h" #include "third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h"
#include "third_party/blink/renderer/core/paint/document_marker_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_text_painter.h" #include "third_party/blink/renderer/core/paint/ng/ng_text_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h" #include "third_party/blink/renderer/core/paint/paint_info.h"
...@@ -60,6 +65,117 @@ Color SelectionBackgroundColor(const Document& document, ...@@ -60,6 +65,117 @@ Color SelectionBackgroundColor(const Document& document,
return color; return color;
} }
DocumentMarkerVector ComputeMarkersToPaint(
const NGPaintFragment& paint_fragment) {
// TODO(yoichio): Handle first-letter
Node* const node = paint_fragment.GetNode();
if (!node)
return DocumentMarkerVector();
DocumentMarkerController& document_marker_controller =
node->GetDocument().Markers();
return document_marker_controller.ComputeMarkersToPaint(*node);
}
void PaintSingleMarkerBackgroundRun(GraphicsContext& context,
const LayoutPoint& box_origin,
Color background_color,
const NGPhysicalOffsetRect& local_rect) {
if (background_color == Color::kTransparent)
return;
GraphicsContextStateSaver state_saver(context);
const NGPhysicalOffsetRect global_rect(
local_rect.offset + NGPhysicalOffset(box_origin), local_rect.size);
context.FillRect(global_rect.ToFloatRect(), background_color);
}
void PaintStyleableMarkerUnderline(GraphicsContext& context,
const LayoutPoint& box_origin,
const StyleableMarker& marker,
const ComputedStyle& style,
const NGPhysicalOffsetRect& local_rect) {
const SimpleFontData* font_data = style.GetFont().PrimaryFont();
DCHECK(font_data);
DocumentMarkerPainter::PaintStyleableMarkerUnderline(
context, box_origin, marker, style, local_rect.ToFloatRect(),
LayoutUnit(font_data->GetFontMetrics().Height()));
}
unsigned GetTextContentOffset(const Text& text, unsigned offset) {
const Position position(text, offset);
const NGOffsetMapping* const offset_mapping =
NGOffsetMapping::GetFor(position);
DCHECK(offset_mapping);
const base::Optional<unsigned>& ng_offset =
offset_mapping->GetTextContentOffset(position);
DCHECK(ng_offset.has_value());
return ng_offset.value();
}
// ClampOffset modifies |offset| fixed in a range of |text_fragment| start/end
// offsets.
unsigned ClampOffset(unsigned offset,
const NGPhysicalTextFragment& text_fragment) {
return std::min(std::max(offset, text_fragment.StartOffset()),
text_fragment.EndOffset());
}
// Copied from InlineTextBoxPainter
enum class DocumentMarkerPaintPhase { kForeground, kBackground };
// Copied from InlineTextBoxPainter
void PaintDocumentMarkers(GraphicsContext& context,
const NGPaintFragment& paint_fragment,
const DocumentMarkerVector& markers_to_paint,
const LayoutPoint& box_origin,
const ComputedStyle& style,
DocumentMarkerPaintPhase marker_paint_phase) {
if (markers_to_paint.IsEmpty())
return;
const NGPhysicalTextFragment& text_fragment =
ToNGPhysicalTextFragmentOrDie(paint_fragment.PhysicalFragment());
DCHECK(text_fragment.GetNode());
const Text& text = ToTextOrDie(*text_fragment.GetNode());
for (const DocumentMarker* marker : markers_to_paint) {
const unsigned marker_start_offset =
GetTextContentOffset(text, marker->StartOffset());
const unsigned marker_end_offset =
GetTextContentOffset(text, marker->EndOffset());
const unsigned paint_start_offset =
ClampOffset(marker_start_offset, text_fragment);
const unsigned paint_end_offset =
ClampOffset(marker_end_offset, text_fragment);
if (paint_start_offset == paint_end_offset)
continue;
switch (marker->GetType()) {
// TODO(yoichio): Implement following cases
// case DocumentMarker::kSpelling:
// case DocumentMarker::kGrammar:
// case DocumentMarker::kTextMatch:
case DocumentMarker::kComposition:
case DocumentMarker::kActiveSuggestion:
case DocumentMarker::kSuggestion: {
const StyleableMarker& styleable_marker = ToStyleableMarker(*marker);
if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground) {
PaintSingleMarkerBackgroundRun(
context, box_origin, styleable_marker.BackgroundColor(),
text_fragment.LocalRect(paint_start_offset, paint_end_offset));
} else {
// TODO(yoichio) We call this on vertical/horizontal flipped context.
// Since NGPhysicalTextFragment::LocalRect returns physical rect,
// we need to adapt it.
PaintStyleableMarkerUnderline(
context, box_origin, styleable_marker, style,
text_fragment.LocalRect(paint_start_offset, paint_end_offset));
}
} break;
default:
// Marker is not painted, or painting code has not been added yet
break;
}
}
}
} // namespace } // namespace
NGTextFragmentPainter::NGTextFragmentPainter( NGTextFragmentPainter::NGTextFragmentPainter(
...@@ -156,11 +272,17 @@ void NGTextFragmentPainter::Paint(const PaintInfo& paint_info, ...@@ -156,11 +272,17 @@ void NGTextFragmentPainter::Paint(const PaintInfo& paint_info,
// TODO(yoichio): Make NGPhysicalTextFragment::LocalRect and // TODO(yoichio): Make NGPhysicalTextFragment::LocalRect and
// NGPaintFragment::ComputeLocalSelectionRect logical so that we can paint // NGPaintFragment::ComputeLocalSelectionRect logical so that we can paint
// selection in same fliped dimention as NGTextPainter. // selection in same fliped dimention as NGTextPainter.
if (have_selection && paint_info.phase != PaintPhase::kSelection && const DocumentMarkerVector& markers_to_paint =
ComputeMarkersToPaint(fragment_);
if (paint_info.phase != PaintPhase::kSelection &&
paint_info.phase != PaintPhase::kTextClip && !is_printing) { paint_info.phase != PaintPhase::kTextClip && !is_printing) {
// TODO(yoichio): Implement composition highlights. PaintDocumentMarkers(context, fragment_, markers_to_paint, box_origin,
PaintSelection(context, fragment_, document, style, style, DocumentMarkerPaintPhase::kBackground);
selection_style.fill_color, box_rect, selection_status);
if (have_selection) {
PaintSelection(context, fragment_, document, style,
selection_style.fill_color, box_rect, selection_status);
}
} }
// Line break needs only selection painting. // Line break needs only selection painting.
...@@ -246,6 +368,11 @@ void NGTextFragmentPainter::Paint(const PaintInfo& paint_info, ...@@ -246,6 +368,11 @@ void NGTextFragmentPainter::Paint(const PaintInfo& paint_info,
text_painter.Paint(selection_status.start, selection_status.end, length, text_painter.Paint(selection_status.start, selection_status.end, length,
selection_style); selection_style);
} }
if (paint_info.phase != PaintPhase::kForeground)
return;
PaintDocumentMarkers(context, fragment_, markers_to_paint, box_origin, style,
DocumentMarkerPaintPhase::kForeground);
} }
} // namespace blink } // namespace blink
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