Commit 1875b8f1 authored by Rob Buis's avatar Rob Buis Committed by Commit Bot

[mathml] Take lspace/rspace into account in row layout

When laying out rows [1] lspace and rspace values from operators
need to be taken into account. Since we did not introduce
embellished operators yet, this CL just takes into account
row children that are of type <mo> [2].

[1] https://mathml-refresh.github.io/mathml-core/#layout-of-mrow
[2] https://mathml-refresh.github.io/mathml-core/#dfn-embellished-operator

Bug: 6606
Change-Id: I35cb69724fa58f39c18511ce13ec941f5536a7bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2390652
Commit-Queue: Rob Buis <rbuis@igalia.com>
Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Reviewed-by: default avatarFrédéric Wang <fwang@igalia.com>
Cr-Commit-Position: refs/heads/master@{#804793}
parent b8c36287
......@@ -126,11 +126,11 @@ RadicalHorizontalParameters GetRadicalHorizontalParameters(
parameters.kern_before_degree = LayoutUnit(
MathConstant(style,
OpenTypeMathSupport::MathConstants::kRadicalKernBeforeDegree)
.value_or(5 * style.FontSize() / 18));
.value_or(5 * style.FontSize() * kMathUnitFraction));
parameters.kern_after_degree = LayoutUnit(
MathConstant(style,
OpenTypeMathSupport::MathConstants::kRadicalKernAfterDegree)
.value_or(-10 * style.FontSize() / 18));
.value_or(-10 * style.FontSize() * kMathUnitFraction));
return parameters;
}
......
......@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/mathml/mathml_element.h"
#include "third_party/blink/renderer/core/mathml/mathml_operator_element.h"
namespace blink {
namespace {
......@@ -25,6 +26,26 @@ inline LayoutUnit InlineOffsetForDisplayMathCentering(
return LayoutUnit();
}
static void DetermineOperatorSpacing(const NGLayoutInputNode& node,
LayoutUnit* lspace,
LayoutUnit* rspace) {
auto* core_operator =
DynamicTo<MathMLOperatorElement>(node.GetLayoutBox()->GetNode());
if (core_operator) {
// TODO(crbug.com/1124298): Implement embellished operators.
LayoutUnit leading_space(core_operator->DefaultLeadingSpace() *
node.Style().FontSize());
*lspace = std::max<LayoutUnit>(
ValueForLength(node.Style().GetMathLSpace(), leading_space),
LayoutUnit());
LayoutUnit trailing_space(core_operator->DefaultTrailingSpace() *
node.Style().FontSize());
*rspace = std::max<LayoutUnit>(
ValueForLength(node.Style().GetMathRSpace(), trailing_space),
LayoutUnit());
}
}
} // namespace
NGMathRowLayoutAlgorithm::NGMathRowLayoutAlgorithm(
......@@ -51,6 +72,8 @@ void NGMathRowLayoutAlgorithm::LayoutRowItems(
To<NGBlockNode>(child), BorderScrollbarPadding().StartOffset());
continue;
}
LayoutUnit lspace, rspace;
DetermineOperatorSpacing(child, &lspace, &rspace);
const ComputedStyle& child_style = child.Style();
NGConstraintSpace child_space = CreateConstraintSpaceForMathChild(
Node(), ChildAvailableSize(), ConstraintSpace(), child);
......@@ -70,7 +93,7 @@ void NGMathRowLayoutAlgorithm::LayoutRowItems(
*max_row_block_baseline = std::max(*max_row_block_baseline, ascent);
// TODO(crbug.com/1125136): take into account italic correction.
// TODO(rbuis): Operators can add lspace and rspace.
inline_offset += lspace;
children->emplace_back(
To<NGBlockNode>(child), margins,
......@@ -79,6 +102,8 @@ void NGMathRowLayoutAlgorithm::LayoutRowItems(
inline_offset += fragment.InlineSize() + margins.inline_end;
inline_offset += rspace;
max_row_ascent = std::max(max_row_ascent, ascent + margins.block_start);
max_row_descent = std::max(
max_row_descent, fragment.BlockSize() + margins.block_end - ascent);
......@@ -150,11 +175,14 @@ MinMaxSizesResult NGMathRowLayoutAlgorithm::ComputeMinMaxSizes(
child_result.sizes += child_margins.InlineSum();
sizes += child_result.sizes;
LayoutUnit lspace, rspace;
DetermineOperatorSpacing(child, &lspace, &rspace);
sizes += lspace + rspace;
depends_on_percentage_block_size |=
child_result.depends_on_percentage_block_size;
// TODO(crbug.com/1125136): take into account italic correction.
// TODO(rbuis): Operators can add lspace and rspace.
}
// Due to negative margins, it is possible that we calculated a negative
......
......@@ -279,4 +279,24 @@ void MathMLOperatorElement::AddMathMaxSizeIfNeeded(
}
}
double MathMLOperatorElement::DefaultLeadingSpace() {
ComputeDictionaryCategory();
return static_cast<float>(
MathMLOperatorDictionaryCategories
[std::underlying_type_t<MathMLOperatorDictionaryCategory>(
properties_.dictionary_category)]
.leading_space_in_math_unit) *
kMathUnitFraction;
}
double MathMLOperatorElement::DefaultTrailingSpace() {
ComputeDictionaryCategory();
return static_cast<float>(
MathMLOperatorDictionaryCategories
[std::underlying_type_t<MathMLOperatorDictionaryCategory>(
properties_.dictionary_category)]
.trailing_space_in_math_unit) *
kMathUnitFraction;
}
} // namespace blink
......@@ -15,6 +15,9 @@ class Document;
enum class MathMLOperatorDictionaryCategory : uint8_t;
// Math units are 1/18em.
constexpr double kMathUnitFraction = 1.0 / 18.0;
class CORE_EXPORT MathMLOperatorElement final : public MathMLElement {
public:
explicit MathMLOperatorElement(Document&);
......@@ -38,6 +41,9 @@ class CORE_EXPORT MathMLOperatorElement final : public MathMLElement {
void AddMathMaxSizeIfNeeded(ComputedStyle&, const CSSToLengthConversionData&);
const OperatorContent& GetOperatorContent();
double DefaultLeadingSpace();
double DefaultTrailingSpace();
private:
base::Optional<OperatorContent> operator_content_;
// Operator properties calculated from dictionary and attributes.
......
......@@ -1247,13 +1247,9 @@ crbug.com/6606 external/wpt/mathml/presentation-markup/mrow/legacy-mrow-like-ele
crbug.com/6606 external/wpt/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/operators/mo-axis-height-1.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/operators/mo-form-dynamic.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/operators/mo-form-minus-plus.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/operators/mo-form.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/operators/mo-not-in-dictionary-lspace-rspace.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/operators/mo-paint-lspace-rspace.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/spaces/space-like-001.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/spaces/space-like-002.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/spaces/space-like-003.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/tables/table-001.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/tables/table-002.html [ Failure ]
crbug.com/6606 external/wpt/mathml/presentation-markup/tables/table-axis-height.html [ Failure ]
......@@ -2604,10 +2600,8 @@ crbug.com/626703 external/wpt/service-workers/service-worker/global-serviceworke
crbug.com/626703 external/wpt/workers/examples/onconnect.any.worker.html [ Timeout ]
crbug.com/626703 external/wpt/cookie-store/serviceworker_oncookiechange_eventhandler_single_subscription.tentative.https.any.worker.html [ Timeout ]
crbug.com/626703 external/wpt/workers/postMessage_block.https.html [ Timeout ]
crbug.com/626703 external/wpt/mathml/relations/css-styling/color-005.html [ Failure ]
crbug.com/626703 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.html [ Timeout ]
crbug.com/626703 external/wpt/uievents/order-of-events/focus-events/focus-management-expectations.html [ Timeout ]
crbug.com/626703 external/wpt/mathml/presentation-markup/operators/mo-form-dynamic-002.html [ Failure ]
crbug.com/626703 external/wpt/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic.html [ Failure ]
crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCRtpSender-replaceTrack.https.html [ Timeout ]
crbug.com/626703 [ Win ] external/wpt/webrtc/RTCRtpSender-replaceTrack.https.html [ Timeout ]
......
This is a testharness.js-based test.
FAIL Preferred width of mrow with mspace children assert_approx_equals: unknown expected 15 +/- 1 but got 30
FAIL Preferred width of mrow with mn and mo children assert_true: expected true got false
PASS Preferred width of mrow with mn and mo children
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Spacing inside <mfrac>. assert_true: expected true got false
FAIL Spacing around <mfrac>. assert_true: expected true got false
FAIL Spacing inside <msub>. assert_true: expected true got false
FAIL Spacing around <msub>. assert_true: expected true got false
FAIL Spacing inside <msup>. assert_true: expected true got false
FAIL Spacing around <msup>. assert_true: expected true got false
FAIL Spacing inside <msubsup>. assert_true: expected true got false
FAIL Spacing around <msubsup>. assert_true: expected true got false
FAIL Spacing inside <mmultiscripts>. assert_true: expected true got false
FAIL Spacing around <mmultiscripts>. assert_true: expected true got false
FAIL Spacing inside <munder>. assert_true: expected true got false
FAIL Spacing around <munder>. assert_true: expected true got false
FAIL Spacing inside <mover>. assert_true: expected true got false
FAIL Spacing around <mover>. assert_true: expected true got false
FAIL Spacing inside <munderover>. assert_true: expected true got false
FAIL Spacing around <munderover>. assert_true: expected true got false
FAIL Spacing inside <mroot>. assert_true: expected true got false
FAIL Spacing around <mroot>. assert_true: expected true got false
PASS Spacing inside <mfrac>.
FAIL Spacing around <mfrac>. assert_greater_than_equal: expected a number greater than or equal to 200 but got 27
PASS Spacing inside <msub>.
FAIL Spacing around <msub>. assert_greater_than_equal: expected a number greater than or equal to 200 but got 55
PASS Spacing inside <msup>.
FAIL Spacing around <msup>. assert_greater_than_equal: expected a number greater than or equal to 200 but got 55
PASS Spacing inside <msubsup>.
FAIL Spacing around <msubsup>. assert_greater_than_equal: expected a number greater than or equal to 200 but got 55
PASS Spacing inside <mmultiscripts>.
FAIL Spacing around <mmultiscripts>. assert_greater_than_equal: expected a number greater than or equal to 200 but got 85
PASS Spacing inside <munder>.
FAIL Spacing around <munder>. assert_greater_than_equal: expected a number greater than or equal to 200 but got 25
PASS Spacing inside <mover>.
FAIL Spacing around <mover>. assert_greater_than_equal: expected a number greater than or equal to 200 but got 25
PASS Spacing inside <munderover>.
FAIL Spacing around <munderover>. assert_greater_than_equal: expected a number greater than or equal to 200 but got 25
FAIL Spacing inside <mroot>. assert_less_than_equal: expected a number less than or equal to 100 but got 106.9375
FAIL Spacing around <mroot>. assert_less_than_equal: expected a number less than or equal to 100 but got 106.9375
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL operator spacing inside Mrow assert_true: expected true got false
FAIL operator spacing inside Sqrt assert_true: expected true got false
FAIL operator spacing inside Style assert_true: expected true got false
FAIL operator spacing inside Error assert_true: expected true got false
FAIL operator spacing inside Phantom assert_true: expected true got false
FAIL operator spacing inside Math assert_true: expected true got false
FAIL operator spacing inside Menclose assert_true: expected true got false
FAIL operator spacing inside Mpadded assert_true: expected true got false
FAIL operator spacing inside Unknown assert_true: expected true got false
PASS operator spacing inside Mrow
PASS operator spacing inside Sqrt
PASS operator spacing inside Style
PASS operator spacing inside Error
PASS operator spacing inside Phantom
PASS operator spacing inside Math
FAIL operator spacing inside Menclose assert_greater_than_equal: expected a number greater than or equal to 50 but got -8
PASS operator spacing inside Mpadded
FAIL operator spacing inside Unknown assert_greater_than_equal: expected a number greater than or equal to 50 but got -8
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL maction (embellished operator) assert_true: expected true got false
FAIL maction (embellished operator, from in-flow children) assert_true: expected true got false
FAIL maction (not embellished operator) assert_true: expected true got false
FAIL maction (not embellished operator, from in-flow children) assert_true: expected true got false
FAIL maction (not embellished operator, empty) assert_true: expected true got false
FAIL maction (embellished operator, one child) assert_true: expected true got false
FAIL maction (embellished operator, complex) assert_true: expected true got false
FAIL semantics (embellished operator) assert_true: expected true got false
FAIL semantics (embellished operator, from in-flow children) assert_true: expected true got false
FAIL semantics (not embellished operator) assert_true: expected true got false
FAIL semantics (not embellished operator, from in-flow children) assert_true: expected true got false
FAIL semantics (not embellished operator, empty) assert_true: expected true got false
FAIL semantics (embellished operator, one child) assert_true: expected true got false
FAIL semantics (embellished operator, complex) assert_true: expected true got false
FAIL maction (embellished operator) assert_approx_equals: expected 50 +/- 1 but got 0
FAIL maction (embellished operator, from in-flow children) assert_approx_equals: expected 50 +/- 1 but got 0
PASS maction (not embellished operator)
PASS maction (not embellished operator, from in-flow children)
PASS maction (not embellished operator, empty)
FAIL maction (embellished operator, one child) assert_approx_equals: expected 50 +/- 1 but got 0
FAIL maction (embellished operator, complex) assert_approx_equals: expected 50 +/- 1 but got 0
FAIL semantics (embellished operator) assert_approx_equals: expected 50 +/- 1 but got 0
FAIL semantics (embellished operator, from in-flow children) assert_approx_equals: expected 50 +/- 1 but got 0
PASS semantics (not embellished operator)
PASS semantics (not embellished operator, from in-flow children)
PASS semantics (not embellished operator, empty)
FAIL semantics (embellished operator, one child) assert_approx_equals: expected 50 +/- 1 but got 0
FAIL semantics (embellished operator, complex) assert_approx_equals: expected 50 +/- 1 but got 0
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL font-relative lspace refers to the core operator assert_approx_equals: baseSizePx * fontScalePercent * lspaceEm expected 100 +/- 1 but got 50
FAIL font-relative rspace refers to the core operator assert_approx_equals: baseSizePx * fontScalePercent * rspaceEm expected 400 +/- 1 but got 200
PASS font-relative lspace refers to the core operator
PASS font-relative rspace refers to the core operator
FAIL font-relative minsize refers to the core operator assert_approx_equals: baseSizePx * fontScalePercent * minsizeEm expected 400 +/- 1 but got 50
PASS font-relative maxsize refers to the core operator
Harness: the test ran to completion.
......
This is a testharness.js-based test.
FAIL Spacing around ≠ assert_true: expected true got false
FAIL Spacing around =⃒ assert_true: expected true got false
FAIL Spacing around |̸ assert_true: expected true got false
FAIL Spacing around |⃒ assert_true: expected true got false
PASS Spacing around ≠
PASS Spacing around =⃒
FAIL Spacing around |̸ assert_approx_equals: expected 66.65625 +/- 1 but got 26.65625
PASS Spacing around |⃒
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Operator dictionary chunk 1 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 2 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 3 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 4 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 5 - lspace/rspace assert_true: expected true got false
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Operator dictionary chunk 1 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 2 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 3 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 4 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 5 - lspace/rspace assert_true: expected true got false
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Operator dictionary chunk 1 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 2 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 3 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 4 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 5 - lspace/rspace assert_true: expected true got false
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Operator dictionary chunk 1 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 2 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 3 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 4 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 5 - lspace/rspace assert_true: expected true got false
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Operator dictionary chunk 1 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 2 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 3 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 4 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 5 - lspace/rspace assert_true: expected true got false
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Operator dictionary chunk 1 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 2 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 3 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 4 - lspace/rspace assert_true: expected true got false
FAIL Operator dictionary chunk 5 - lspace/rspace assert_true: expected true got false
Harness: the test ran to completion.
This is a testharness.js-based test.
PASS Spacing around ≠
PASS Spacing around =⃒
FAIL Spacing around |̸ assert_approx_equals: expected 66.65625 +/- 1 but got 26.671875
PASS Spacing around |⃒
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