blob: d764b2f2567d76754103ac1c143a1260515c80fc [file] [log] [blame]
// Copyright 2020 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.
#include "third_party/blink/renderer/core/paint/ng/ng_mathml_painter.h"
#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h"
#include "third_party/blink/renderer/core/mathml/mathml_radical_element.h"
#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
namespace blink {
void NGMathMLPainter::PaintBar(const PaintInfo& info, const IntRect& bar) {
if (bar.IsEmpty())
return;
GraphicsContextStateSaver state_saver(info.context);
info.context.SetStrokeThickness(bar.Height());
info.context.SetStrokeStyle(kSolidStroke);
info.context.SetStrokeColor(
box_fragment_.Style().VisitedDependentColor(GetCSSPropertyColor()));
IntPoint line_end_point = {bar.Width(), 0};
info.context.DrawLine(bar.Location(), bar.Location() + line_end_point);
}
void NGMathMLPainter::PaintStretchyOrLargeOperator(
const PaintInfo& info,
PhysicalOffset paint_offset) {
const ComputedStyle& style = box_fragment_.Style();
const NGMathMLPaintInfo& parameters = box_fragment_.GetMathMLPaintInfo();
UChar operator_character = parameters.operator_character;
NGTextFragmentPaintInfo text_fragment_paint_info = {
StringView(&operator_character, 1), 0, 1,
parameters.operator_shape_result_view.get()};
GraphicsContextStateSaver state_saver(info.context);
info.context.SetFillColor(style.VisitedDependentColor(GetCSSPropertyColor()));
info.context.DrawText(style.GetFont(), text_fragment_paint_info,
FloatPoint(paint_offset), kInvalidDOMNodeId);
}
void NGMathMLPainter::PaintFractionBar(
const PaintInfo& info,
PhysicalOffset paint_offset) {
DCHECK(box_fragment_.Style().IsHorizontalWritingMode());
const ComputedStyle& style = box_fragment_.Style();
LayoutUnit line_thickness = FractionLineThickness(style);
if (!line_thickness)
return;
LayoutUnit axis_height = MathAxisHeight(style);
if (auto baseline = box_fragment_.Baseline()) {
auto borders = box_fragment_.Borders();
auto padding = box_fragment_.Padding();
PhysicalRect bar_rect = {
borders.left + padding.left, *baseline - axis_height,
box_fragment_.Size().width - borders.HorizontalSum() -
padding.HorizontalSum(),
line_thickness};
bar_rect.Move(paint_offset);
PaintBar(info, PixelSnappedIntRect(bar_rect));
}
}
void NGMathMLPainter::PaintOperator(const PaintInfo& info,
PhysicalOffset paint_offset) {
const ComputedStyle& style = box_fragment_.Style();
const NGMathMLPaintInfo& parameters = box_fragment_.GetMathMLPaintInfo();
LogicalOffset offset(LayoutUnit(), parameters.operator_ascent);
PhysicalOffset physical_offset = offset.ConvertToPhysical(
style.GetWritingDirection(),
PhysicalSize(box_fragment_.Size().width, box_fragment_.Size().height),
PhysicalSize(parameters.operator_inline_size,
parameters.operator_ascent + parameters.operator_descent));
auto borders = box_fragment_.Borders();
auto padding = box_fragment_.Padding();
physical_offset.left += borders.left + padding.left;
physical_offset.top += borders.top + padding.top;
PaintStretchyOrLargeOperator(info, paint_offset + physical_offset);
}
void NGMathMLPainter::PaintRadicalSymbol(
const PaintInfo& info,
PhysicalOffset paint_offset) {
auto children = box_fragment_.Children();
if (children.size() == 0)
return;
const auto& base_child = To<NGPhysicalBoxFragment>(*children[0]);
const NGMathMLPaintInfo& parameters = box_fragment_.GetMathMLPaintInfo();
DCHECK(box_fragment_.Style().IsHorizontalWritingMode());
// Paint the vertical symbol.
const ComputedStyle& style = box_fragment_.Style();
bool has_index =
To<MathMLRadicalElement>(box_fragment_.GetNode())->HasIndex();
auto vertical = GetRadicalVerticalParameters(style, has_index);
auto radical_base_ascent =
base_child.Baseline().value_or(base_child.Size().height) +
parameters.radical_base_margins.inline_start;
LayoutUnit block_offset =
box_fragment_.Baseline().value_or(box_fragment_.Size().height) -
vertical.vertical_gap - radical_base_ascent;
auto borders = box_fragment_.Borders();
auto padding = box_fragment_.Padding();
LayoutUnit inline_offset = borders.left + padding.left;
inline_offset += *parameters.radical_operator_inline_offset;
LogicalOffset radical_symbol_offset(
inline_offset, block_offset + parameters.operator_ascent);
auto radical_symbol_physical_offset = radical_symbol_offset.ConvertToPhysical(
style.GetWritingDirection(),
PhysicalSize(box_fragment_.Size().width, box_fragment_.Size().height),
PhysicalSize(parameters.operator_ascent,
parameters.operator_ascent + parameters.operator_descent));
PaintStretchyOrLargeOperator(info,
paint_offset + radical_symbol_physical_offset);
// Paint the horizontal overbar.
LayoutUnit rule_thickness = vertical.rule_thickness;
if (!rule_thickness)
return;
LayoutUnit base_width =
base_child.Size().width + parameters.radical_base_margins.InlineSum();
LogicalOffset bar_offset =
LogicalOffset(inline_offset, block_offset) +
LogicalSize(parameters.operator_inline_size, LayoutUnit());
LayoutSize bar_size = {base_width, rule_thickness};
auto bar_physical_offset = bar_offset.ConvertToPhysical(
style.GetWritingDirection(),
PhysicalSize(box_fragment_.Size().width, box_fragment_.Size().height),
PhysicalSize(bar_size));
PhysicalRect bar_rect = {bar_physical_offset.left, bar_physical_offset.top,
base_width, rule_thickness};
bar_rect.Move(paint_offset);
PaintBar(info, PixelSnappedIntRect(bar_rect));
}
void NGMathMLPainter::Paint(const PaintInfo& info,
PhysicalOffset paint_offset) {
const DisplayItemClient& display_item_client =
*box_fragment_.GetLayoutObject();
if (DrawingRecorder::UseCachedDrawingIfPossible(
info.context, display_item_client, info.phase))
return;
DrawingRecorder recorder(
info.context, display_item_client, info.phase,
NGBoxFragmentPainter(box_fragment_).VisualRect(paint_offset));
// Fraction
if (box_fragment_.IsMathMLFraction()) {
PaintFractionBar(info, paint_offset);
return;
}
// Radical symbol
if (box_fragment_.GetMathMLPaintInfo().IsRadicalOperator()) {
PaintRadicalSymbol(info, paint_offset);
return;
}
// Operator
PaintOperator(info, paint_offset);
}
} // namespace blink