| // 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 |