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
const Node*,
DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
DocumentMarkerVector Markers();
// TODO(yoichio): Make const by making PossiblyHasMarkers const.
DocumentMarkerVector ComputeMarkersToPaint(const Node&);
Vector<IntRect> LayoutRectsForTextMatchMarkers();
void InvalidateRectsForAllTextMatchMarkers();
......
......@@ -74,6 +74,7 @@ blink_core_sources("paint") {
"decoration_info.h",
"details_marker_painter.cc",
"details_marker_painter.h",
"document_marker_painter.h",
"ellipsis_box_painter.cc",
"ellipsis_box_painter.h",
"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 @@
#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/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/selection_painting_utils.h"
#include "third_party/blink/renderer/core/paint/text_painter.h"
......@@ -511,31 +512,35 @@ void InlineTextBoxPainter::PaintSingleMarkerBackgroundRun(
}
DocumentMarkerVector InlineTextBoxPainter::ComputeMarkersToPaint() const {
// We don't render composition or spelling markers that overlap suggestion
// markers.
Node* const node = inline_text_box_.GetLineLayoutItem().GetNode();
if (!node)
return DocumentMarkerVector();
DocumentMarkerController& document_marker_controller =
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
// start offset.
const DocumentMarkerVector& suggestion_markers =
document_marker_controller.MarkersFor(node, DocumentMarker::kSuggestion);
MarkersFor(&node, DocumentMarker::kSuggestion);
if (suggestion_markers.IsEmpty()) {
// If there are no suggestion markers, we can return early as a minor
// performance optimization.
DocumentMarker::MarkerTypes remaining_types = DocumentMarker::AllMarkers();
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 =
document_marker_controller.MarkersFor(
node, DocumentMarker::kComposition | DocumentMarker::kSpelling);
MarkersFor(&node,
DocumentMarker::kComposition | DocumentMarker::kSpelling);
Vector<unsigned> suggestion_starts;
Vector<unsigned> suggestion_ends;
......@@ -588,8 +593,7 @@ DocumentMarkerVector InlineTextBoxPainter::ComputeMarkersToPaint() const {
DocumentMarker::kSpelling |
DocumentMarker::kSuggestion);
markers_to_paint.AppendVector(
document_marker_controller.MarkersFor(node, remaining_types));
markers_to_paint.AppendVector(MarkersFor(&node, remaining_types));
return markers_to_paint;
}
......@@ -1012,20 +1016,32 @@ void InlineTextBoxPainter::PaintStyleableMarkerUnderline(
const StyleableMarker& marker,
const ComputedStyle& style,
const Font& font) {
if (marker.HasThicknessNone() ||
(marker.UnderlineColor() == Color::kTransparent &&
!marker.UseTextColor()))
return;
if (inline_text_box_.Truncation() == kCFullTruncation)
return;
const PaintOffsets marker_offsets = MarkerPaintStartAndEnd(marker);
const TextRun& run = inline_text_box_.ConstructTextRun(style);
// Pass 0 for height since we only care about the width
const FloatRect& marker_rect = font.SelectionRectForText(
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()
LayoutUnit start = LayoutUnit(marker_rect.X());
LayoutUnit width = LayoutUnit(marker_rect.Width());
......@@ -1042,21 +1058,15 @@ void InlineTextBoxPainter::PaintStyleableMarkerUnderline(
// thick. If there's not enough space the underline will touch or overlap
// characters.
int line_thickness = 1;
const SimpleFontData* font_data =
inline_text_box_.GetLineLayoutItem()
.Style(inline_text_box_.IsFirstLineStyle())
->GetFont()
.PrimaryFont();
const SimpleFontData* font_data = style.GetFont().PrimaryFont();
DCHECK(font_data);
int baseline = font_data ? font_data->GetFontMetrics().Ascent() : 0;
if (marker.HasThicknessThick() &&
inline_text_box_.LogicalHeight() - baseline >= 2)
if (marker.HasThicknessThick() && logical_height.ToInt() - baseline >= 2)
line_thickness = 2;
Color marker_color =
marker.UseTextColor()
? inline_text_box_.GetLineLayoutItem().Style()->VisitedDependentColor(
GetCSSPropertyWebkitTextFillColor())
? style.VisitedDependentColor(GetCSSPropertyWebkitTextFillColor())
: marker.UnderlineColor();
context.SetStrokeColor(marker_color);
......@@ -1064,8 +1074,7 @@ void InlineTextBoxPainter::PaintStyleableMarkerUnderline(
context.DrawLineForText(
FloatPoint(
box_origin.X() + start,
(box_origin.Y() + inline_text_box_.LogicalHeight() - line_thickness)
.ToFloat()),
(box_origin.Y() + logical_height.ToInt() - line_thickness).ToFloat()),
width);
}
......
......@@ -5,10 +5,15 @@
#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/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/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/ng_physical_box_fragment.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_text_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
......@@ -60,6 +65,117 @@ Color SelectionBackgroundColor(const Document& document,
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
NGTextFragmentPainter::NGTextFragmentPainter(
......@@ -156,11 +272,17 @@ void NGTextFragmentPainter::Paint(const PaintInfo& paint_info,
// TODO(yoichio): Make NGPhysicalTextFragment::LocalRect and
// NGPaintFragment::ComputeLocalSelectionRect logical so that we can paint
// 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) {
// TODO(yoichio): Implement composition highlights.
PaintSelection(context, fragment_, document, style,
selection_style.fill_color, box_rect, selection_status);
PaintDocumentMarkers(context, fragment_, markers_to_paint, box_origin,
style, DocumentMarkerPaintPhase::kBackground);
if (have_selection) {
PaintSelection(context, fragment_, document, style,
selection_style.fill_color, box_rect, selection_status);
}
}
// Line break needs only selection painting.
......@@ -246,6 +368,11 @@ void NGTextFragmentPainter::Paint(const PaintInfo& paint_info,
text_painter.Paint(selection_status.start, selection_status.end, length,
selection_style);
}
if (paint_info.phase != PaintPhase::kForeground)
return;
PaintDocumentMarkers(context, fragment_, markers_to_paint, box_origin, style,
DocumentMarkerPaintPhase::kForeground);
}
} // 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