Commit 07c1ced3 authored by Rob Buis's avatar Rob Buis Committed by Commit Bot

[mathml] Implement italic correction

Implement italic correction [1] when laying out scripts. In order to
signal that an operator has an italic correction we add
SetMathItalicCorrection on the fragment builder and set it if
needed when laying out the operator. The script layout algorithm
uses this value when laying out the script, where appropriate.

[1] https://mathml-refresh.github.io/mathml-core/#dfn-italic-correction
Bug: 1125136, 6606

Change-Id: I2995b0fad1e1c8e96cc08818d50927d28cb54f4c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2414240Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarFrédéric Wang <fwang@igalia.com>
Commit-Queue: Rob Buis <rbuis@igalia.com>
Cr-Commit-Position: refs/heads/master@{#824055}
parent f56188d3
......@@ -64,6 +64,11 @@ scoped_refptr<const NGLayoutResult> NGMathOperatorLayoutAlgorithm::Layout() {
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);
......
......@@ -317,7 +317,8 @@ scoped_refptr<const NGLayoutResult> NGMathScriptsLayoutAlgorithm::Layout() {
content_start_offset.block_offset;
LayoutUnit descent =
std::max(base_metrics.descent, metrics.descent + metrics.sub_shift);
// TODO(crbug.com/1125136): take into account italic correction.
LayoutUnit base_italic_correction = std::min(
base_metrics.inline_size, base_metrics.result->MathItalicCorrection());
LayoutUnit inline_offset = content_start_offset.inline_offset;
LayoutUnit space = GetSpaceAfterScript(Style());
......@@ -366,9 +367,12 @@ scoped_refptr<const NGLayoutResult> NGMathScriptsLayoutAlgorithm::Layout() {
sup_metric = sup_metrics[idx];
if (sub_metric.node) {
LogicalOffset sub_offset(inline_offset + sub_metric.margins.inline_start,
ascent + metrics.sub_shift - sub_metric.ascent +
sub_metric.margins.block_start);
LogicalOffset sub_offset(
LayoutUnit(inline_offset + sub_metric.margins.inline_start -
base_italic_correction)
.ClampNegativeToZero(),
ascent + metrics.sub_shift - sub_metric.ascent +
sub_metric.margins.block_start);
container_builder_.AddChild(sub_metric.result->PhysicalFragment(),
sub_offset);
sub_metric.node.StoreMargins(ConstraintSpace(), sub_metric.margins);
......@@ -419,6 +423,9 @@ MinMaxSizesResult NGMathScriptsLayoutAlgorithm::ComputeMinMaxSizes(
MinMaxSizes sizes;
bool depends_on_percentage_block_size = false;
ChildAndMetrics base_metrics = LayoutAndGetMetrics(base);
LayoutUnit base_italic_correction = std::min(
base_metrics.inline_size, base_metrics.result->MathItalicCorrection());
MinMaxSizesResult base_result =
ComputeMinAndMaxContentContribution(Style(), base, child_input);
base_result.sizes += ComputeMinMaxMargins(Style(), base).InlineSum();
......@@ -433,7 +440,6 @@ MinMaxSizesResult NGMathScriptsLayoutAlgorithm::ComputeMinMaxSizes(
case MathScriptType::kUnder:
case MathScriptType::kOver:
case MathScriptType::kSuper: {
// TODO(crbug.com/1125136): Take italic correction into account.
NGBlockNode sub = sub_sup_pairs[0].sub;
NGBlockNode sup = sub_sup_pairs[0].sup;
auto first_post_script = sub ? sub : sup;
......@@ -443,6 +449,8 @@ MinMaxSizesResult NGMathScriptsLayoutAlgorithm::ComputeMinMaxSizes(
ComputeMinMaxMargins(Style(), first_post_script).InlineSum();
sizes += first_post_script_result.sizes;
if (sub)
sizes -= base_italic_correction;
sizes += space;
depends_on_percentage_block_size |=
first_post_script_result.depends_on_percentage_block_size;
......@@ -451,7 +459,6 @@ MinMaxSizesResult NGMathScriptsLayoutAlgorithm::ComputeMinMaxSizes(
case MathScriptType::kSubSup:
case MathScriptType::kUnderOver:
case MathScriptType::kMultiscripts: {
// TODO(crbug.com/1125136): Take italic correction into account.
MinMaxSizes sub_sup_pair_size;
unsigned index = 0;
do {
......@@ -461,6 +468,7 @@ MinMaxSizesResult NGMathScriptsLayoutAlgorithm::ComputeMinMaxSizes(
auto sub_result =
ComputeMinAndMaxContentContribution(Style(), sub, child_input);
sub_result.sizes += ComputeMinMaxMargins(Style(), sub).InlineSum();
sub_result.sizes -= base_italic_correction;
sub_sup_pair_size.Encompass(sub_result.sizes);
auto sup = sub_sup_pairs[index].sup;
......
......@@ -43,6 +43,7 @@ class CORE_EXPORT NGMathScriptsLayoutAlgorithm
LayoutUnit ascent;
LayoutUnit descent;
LayoutUnit inline_size;
LayoutUnit base_italic_correction;
NGBoxStrut margins;
NGBlockNode node = nullptr;
};
......
......@@ -604,6 +604,13 @@ void NGBoxFragmentBuilder::SetLastBaselineToBlockEndMarginEdgeIfNeeded() {
SetLastBaseline(FragmentBlockSize() + margins.block_end);
}
void NGBoxFragmentBuilder::SetMathItalicCorrection(
LayoutUnit italic_correction) {
if (!math_data_)
math_data_.emplace();
math_data_->italic_correction_ = italic_correction;
}
#if DCHECK_IS_ON()
void NGBoxFragmentBuilder::CheckNoBlockFragmentation() const {
......
......@@ -551,6 +551,8 @@ class CORE_EXPORT NGBoxFragmentBuilder final
// any baselines, OOFs, etc, are also moved by the appropriate amount).
void MoveChildrenInBlockDirection(LayoutUnit offset);
void SetMathItalicCorrection(LayoutUnit italic_correction);
private:
// Update whether we have fragmented in this flow.
void PropagateBreak(const NGLayoutResult&);
......@@ -626,6 +628,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
base::Optional<int> lines_until_clamp_;
std::unique_ptr<NGMathMLPaintInfo> mathml_paint_info_;
base::Optional<NGLayoutResult::MathData> math_data_;
scoped_refptr<const NGBlockBreakToken> previous_break_token_;
......
......@@ -106,6 +106,8 @@ NGLayoutResult::NGLayoutResult(
}
if (builder->table_column_count_)
EnsureRareData()->table_column_count_ = *builder->table_column_count_;
if (builder->math_data_.has_value())
EnsureRareData()->math_layout_data_ = builder->math_data_;
}
NGLayoutResult::NGLayoutResult(
......
......@@ -220,6 +220,12 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
return HasRareData() ? rare_data_->table_column_count_ : 0;
}
LayoutUnit MathItalicCorrection() const {
return HasRareData() && rare_data_->math_layout_data_
? rare_data_->math_layout_data_->italic_correction_
: LayoutUnit();
}
// The break-before value on the first child needs to be propagated to the
// container, in search of a valid class A break point.
EBreakBetween InitialBreakBefore() const {
......@@ -344,6 +350,11 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
scoped_refptr<const NGPhysicalContainerFragment> physical_fragment,
NGLineBoxFragmentBuilder*);
// See https://mathml-refresh.github.io/mathml-core/#box-model
struct MathData {
LayoutUnit italic_correction_;
};
private:
friend class MutableForOutOfFlow;
......@@ -416,6 +427,7 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
bool is_single_use = false;
int lines_until_clamp = 0;
wtf_size_t table_column_count_ = 0;
base::Optional<MathData> math_layout_data_;
};
bool HasRareData() const { return bitfields_.has_rare_data; }
......
This is a testharness.js-based test.
PASS Null Italic Correction
FAIL NonNull Italic Correction (MathGlyphVariantRecord) assert_approx_equals: msub expected 30 +/- 1 but got 0
FAIL NonNull Italic Correction (GlyphAssembly) assert_approx_equals: msub expected 50 +/- 1 but got 0
Harness: the test ran to completion.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment