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
|