blob: 9d41f9c6b3708037c1a021409da2f688654b7ec1 [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/layout/ng/mathml/ng_math_operator_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/mathml/mathml_operator_element.h"
#include "third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.h"
namespace blink {
namespace {
inline LayoutUnit DisplayOperatorMinHeight(const ComputedStyle& style) {
return LayoutUnit(
MathConstant(
style, OpenTypeMathSupport::MathConstants::kDisplayOperatorMinHeight)
.value_or(0));
}
} // namespace
NGMathOperatorLayoutAlgorithm::NGMathOperatorLayoutAlgorithm(
const NGLayoutAlgorithmParams& params)
: NGLayoutAlgorithm(params) {
DCHECK(params.space.IsNewFormattingContext());
container_builder_.SetIsInlineFormattingContext(
Node().IsInlineFormattingContextRoot());
}
scoped_refptr<const NGLayoutResult> NGMathOperatorLayoutAlgorithm::Layout() {
// This algorithm can only be used for operators with a single text node,
// which itself must contain only one glyph. We ensure that the subtree is
// properly laid out but the glyph will actually be used to determine a
// "large" or "stretched" version, from which we perform measurement and
// painting.
// See https://mathml-refresh.github.io/mathml-core/#layout-of-operators
NGLayoutInputNode child = Node().FirstChild();
DCHECK(child && child.IsInline());
DCHECK(!child.NextSibling());
DCHECK(!child.IsOutOfFlowPositioned());
NGInlineChildLayoutContext context;
NGFragmentItemsBuilder items_builder(
To<NGInlineNode>(child), container_builder_.GetWritingDirection());
container_builder_.SetItemsBuilder(&items_builder);
context.SetItemsBuilder(&items_builder);
scoped_refptr<const NGLayoutResult> child_layout_result =
To<NGInlineNode>(child).Layout(ConstraintSpace(), nullptr, &context);
container_builder_.AddResult(*child_layout_result, {});
// TODO(http://crbug.com/1124301) Implement stretchy operators.
float operator_target_size = DisplayOperatorMinHeight(Style());
StretchyOperatorShaper shaper(GetBaseCodePoint(),
OpenTypeMathStretchData::StretchAxis::Vertical);
StretchyOperatorShaper::Metrics metrics;
scoped_refptr<ShapeResult> shape_result =
shaper.Shape(&Style().GetFont(), operator_target_size, &metrics);
scoped_refptr<const ShapeResultView> shape_result_view =
ShapeResultView::Create(shape_result.get());
if (metrics.italic_correction) {
container_builder_.SetMathItalicCorrection(
LayoutUnit(metrics.italic_correction));
}
LayoutUnit operator_ascent = LayoutUnit::FromFloatFloor(metrics.ascent);
LayoutUnit operator_descent = LayoutUnit::FromFloatFloor(metrics.descent);
container_builder_.SetMathMLPaintInfo(
GetBaseCodePoint(), std::move(shape_result_view),
LayoutUnit(metrics.advance), operator_ascent, operator_descent);
LayoutUnit ascent = BorderScrollbarPadding().block_start + operator_ascent;
LayoutUnit descent = operator_descent + BorderScrollbarPadding().block_end;
LayoutUnit intrinsic_block_size = ascent + descent;
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), BorderPadding(), intrinsic_block_size,
container_builder_.InitialBorderBoxSize().inline_size,
Node().ShouldBeConsideredAsReplaced());
container_builder_.SetBaseline(ascent);
container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
container_builder_.SetFragmentsTotalBlockSize(block_size);
container_builder_.SetIsMathMLOperator();
return container_builder_.ToBoxFragment();
}
MinMaxSizesResult NGMathOperatorLayoutAlgorithm::ComputeMinMaxSizes(
const MinMaxSizesInput& input) const {
// TODO(http://crbug.com/1124301) Implement stretchy operators.
MinMaxSizes sizes;
StretchyOperatorShaper shaper(GetBaseCodePoint(),
OpenTypeMathStretchData::Vertical);
StretchyOperatorShaper::Metrics metrics;
float operator_target_size = DisplayOperatorMinHeight(Style());
shaper.Shape(&Style().GetFont(), operator_target_size, &metrics);
sizes.Encompass(LayoutUnit(metrics.advance));
sizes += BorderScrollbarPadding().InlineSum();
return MinMaxSizesResult(sizes, /* depends_on_percentage_block_size */ false);
}
UChar32 NGMathOperatorLayoutAlgorithm::GetBaseCodePoint() const {
return DynamicTo<MathMLOperatorElement>(Node().GetDOMNode())
->GetOperatorContent()
.code_point;
}
} // namespace blink