File: mathml_painter.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (186 lines) | stat: -rw-r--r-- 8,124 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// Copyright 2020 The Chromium Authors
// 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/mathml_painter.h"

#include "third_party/blink/renderer/core/layout/mathml/math_layout_utils.h"
#include "third_party/blink/renderer/core/mathml/mathml_radical_element.h"
#include "third_party/blink/renderer/core/paint/box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/paint_auto_dark_mode.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/platform/fonts/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 MathMLPainter::PaintBar(const PaintInfo& info,
                             const PhysicalRect& bar_rect) {
  gfx::Rect snapped_bar_rect = ToPixelSnappedRect(bar_rect);
  if (snapped_bar_rect.IsEmpty()) {
    return;
  }
  // The (vertical) origin of `snapped_bar_rect` is now at the mid-point of the
  // bar. Shift up by half the height to produce the corresponding rectangle.
  snapped_bar_rect -= gfx::Vector2d(0, snapped_bar_rect.height() / 2);
  const ComputedStyle& style = box_fragment_.Style();
  info.context.FillRect(
      snapped_bar_rect, style.VisitedDependentColor(GetCSSPropertyColor()),
      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground));
}

void MathMLPainter::PaintStretchyOrLargeOperator(const PaintInfo& info,
                                                 PhysicalOffset paint_offset) {
  const ComputedStyle& style = box_fragment_.Style();
  const MathMLPaintInfo& parameters = box_fragment_.GetMathMLPaintInfo();
  UChar operator_character = parameters.operator_character;
  TextFragmentPaintInfo text_fragment_paint_info = {
      StringView(base::span_from_ref(operator_character)), 0, 1,
      parameters.operator_shape_result_view.Get()};
  GraphicsContextStateSaver state_saver(info.context);
  info.context.SetFillColor(style.VisitedDependentColor(GetCSSPropertyColor()));
  AutoDarkMode auto_dark_mode(
      PaintAutoDarkMode(style, DarkModeFilter::ElementRole::kForeground));
  info.context.DrawText(*style.GetFont(), text_fragment_paint_info,
                        gfx::PointF(paint_offset), kInvalidDOMNodeId,
                        auto_dark_mode);
}

void MathMLPainter::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_.FirstBaseline()) {
    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, bar_rect);
  }
}

void MathMLPainter::PaintOperator(const PaintInfo& info,
                                  PhysicalOffset paint_offset) {
  const ComputedStyle& style = box_fragment_.Style();
  const MathMLPaintInfo& 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;

  // TODO(http://crbug.com/1124301): MathOperatorLayoutAlgorithm::Layout
  // passes the operator's inline size but this does not match the width of the
  // box fragment, which relies on the min-max sizes instead. Shift the paint
  // offset to work around that issue, splitting the size error symmetrically.
  DCHECK(box_fragment_.Style().IsHorizontalWritingMode());
  physical_offset.left +=
      (box_fragment_.Size().width - borders.HorizontalSum() -
       padding.HorizontalSum() - parameters.operator_inline_size) /
      2;

  PaintStretchyOrLargeOperator(info, paint_offset + physical_offset);
}

void MathMLPainter::PaintRadicalSymbol(const PaintInfo& info,
                                       PhysicalOffset paint_offset) {
  LayoutUnit base_child_width;
  LayoutUnit base_child_ascent;
  if (!box_fragment_.Children().empty()) {
    const auto& base_child =
        To<PhysicalBoxFragment>(*box_fragment_.Children()[0]);
    base_child_width = base_child.Size().width;
    base_child_ascent =
        base_child.FirstBaseline().value_or(base_child.Size().height);
  }

  const MathMLPaintInfo& 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_ascent + parameters.radical_base_margins.inline_start;
  LayoutUnit block_offset =
      box_fragment_.FirstBaseline().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_width + parameters.radical_base_margins.InlineSum();
  LogicalOffset bar_offset =
      LogicalOffset(inline_offset, block_offset) +
      LogicalSize(parameters.operator_inline_size, LayoutUnit());
  auto bar_physical_offset = bar_offset.ConvertToPhysical(
      style.GetWritingDirection(), box_fragment_.Size(),
      PhysicalSize(base_width, rule_thickness));
  PhysicalRect bar_rect = {bar_physical_offset.left, bar_physical_offset.top,
                           base_width, rule_thickness};
  bar_rect.Move(paint_offset);
  PaintBar(info, bar_rect);
}

void MathMLPainter::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,
      BoxFragmentPainter(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