[mathml] Add unit tests for OpenTypeMathSupport
A platform API for the OpenType MATH table has been added in [1] but
the code is not verified by blink_platform_unittests. This CL adds a
few tests for fonts with or without a MATH table as well as constants
related to script scale down, fractions and radicals. This is not
exhaustive but at least cover all the return statements of
OpenTypeMathSupport::HasMathData and OpenTypeMathSupport::MathConstant.
This also modifies the result of OpenTypeMathSupport::MathConstant
for fonts without a MATH table: Instead of returning HarfBuzz's zero
value, the function returns a null optional so that callers can decide
the default value to use.
[1] https://chromium-review.googlesource.com/c/chromium/src/+/2041485
Bug: 6606, 1050596
Change-Id: I4e7f329bbabb1759f6a1adeaa74b49912812ba8e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2073721
Commit-Queue: Frédéric Wang <fwang@igalia.com>
Reviewed-by: Dominik Röttsches <drott@chromium.org>
Cr-Commit-Position: refs/heads/master@{#744982}
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index f65dbbc..3913841 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1761,6 +1761,7 @@
"fonts/generic_font_family_settings_test.cc",
"fonts/mac/font_matcher_mac_test.mm",
"fonts/opentype/font_settings_test.cc",
+ "fonts/opentype/open_type_math_support_test.cc",
"fonts/opentype/open_type_vertical_data_test.cc",
"fonts/orientation_iterator_test.cc",
"fonts/script_run_iterator_test.cc",
@@ -2035,6 +2036,9 @@
# Required by some image decoder tests.
"image-decoders/testing/",
"//third_party/blink/web_tests/images/resources/",
+
+ # Required by some font tests.
+ "//third_party/blink/web_tests/external/wpt/fonts/",
]
}
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc
index 6debef8..e90a002b 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc
+++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc
@@ -38,7 +38,7 @@
base::Optional<float> OpenTypeMathSupport::MathConstant(
const HarfBuzzFace* harfbuzz_face,
MathConstants constant) {
- if (!harfbuzz_face)
+ if (!HasMathData(harfbuzz_face))
return base::nullopt;
hb_font_t* font =
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support_test.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support_test.cc
new file mode 100644
index 0000000..bdc468cf
--- /dev/null
+++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support_test.cc
@@ -0,0 +1,238 @@
+// 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/platform/fonts/opentype/open_type_math_support.h"
+#include "base/memory/scoped_refptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/fonts/font.h"
+#include "third_party/blink/renderer/platform/fonts/opentype/open_type_types.h"
+#include "third_party/blink/renderer/platform/testing/font_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+
+namespace blink {
+
+class OpenTypeMathSupportTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ font_description.SetComputedSize(10.0);
+ font = Font(font_description);
+ font.Update(nullptr);
+ }
+
+ void TearDown() override {}
+
+ Font CreateMathFont(const String& name, float size = 1000) {
+ FontDescription::VariantLigatures ligatures;
+ return blink::test::CreateTestFont(
+ "MathTestFont",
+ blink::test::BlinkWebTestsFontsTestDataPath(String("math/") + name),
+ size, &ligatures);
+ }
+
+ bool HasMathData(const String& name) {
+ return OpenTypeMathSupport::HasMathData(
+ CreateMathFont(name).PrimaryFont()->PlatformData().GetHarfBuzzFace());
+ }
+
+ base::Optional<float> MathConstant(
+ const String& name,
+ OpenTypeMathSupport::MathConstants constant) {
+ Font math = CreateMathFont(name);
+ return OpenTypeMathSupport::MathConstant(
+ math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), constant);
+ }
+
+ FontDescription font_description;
+ Font font;
+};
+
+TEST_F(OpenTypeMathSupportTest, HasMathData) {
+ // Null parameter.
+ EXPECT_FALSE(OpenTypeMathSupport::HasMathData(nullptr));
+
+ // Font without a MATH table.
+ EXPECT_FALSE(HasMathData("math-text.woff"));
+
+ // Font with a MATH table.
+ EXPECT_TRUE(HasMathData("axisheight5000-verticalarrow14000.woff"));
+}
+
+TEST_F(OpenTypeMathSupportTest, MathConstantNullOpt) {
+ Font math_text = CreateMathFont("math-text.woff");
+
+ for (int i = OpenTypeMathSupport::MathConstants::kScriptPercentScaleDown;
+ i <=
+ OpenTypeMathSupport::MathConstants::kRadicalDegreeBottomRaisePercent;
+ i++) {
+ auto math_constant = static_cast<OpenTypeMathSupport::MathConstants>(i);
+
+ // Null parameter.
+ EXPECT_FALSE(OpenTypeMathSupport::MathConstant(nullptr, math_constant));
+
+ // Font without a MATH table.
+ EXPECT_FALSE(OpenTypeMathSupport::MathConstant(
+ math_text.PrimaryFont()->PlatformData().GetHarfBuzzFace(),
+ math_constant));
+ }
+}
+
+// See third_party/blink/web_tests/external/wpt/mathml/tools/percentscaledown.py
+TEST_F(OpenTypeMathSupportTest, MathConstantPercentScaleDown) {
+ {
+ auto result = MathConstant(
+ "scriptpercentscaledown80-scriptscriptpercentscaledown0.woff",
+ OpenTypeMathSupport::MathConstants::kScriptPercentScaleDown);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, .8);
+ }
+
+ {
+ auto result = MathConstant(
+ "scriptpercentscaledown0-scriptscriptpercentscaledown40.woff",
+ OpenTypeMathSupport::MathConstants::kScriptScriptPercentScaleDown);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, .4);
+ }
+}
+
+// See third_party/blink/web_tests/external/wpt/mathml/tools/fractions.py
+TEST_F(OpenTypeMathSupportTest, MathConstantFractions) {
+ {
+ auto result = MathConstant(
+ "fraction-numeratorshiftup11000-axisheight1000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kFractionNumeratorShiftUp);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 11000);
+ }
+
+ {
+ auto result = MathConstant(
+ "fraction-numeratordisplaystyleshiftup2000-axisheight1000-"
+ "rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::
+ kFractionNumeratorDisplayStyleShiftUp);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 2000);
+ }
+
+ {
+ auto result = MathConstant(
+ "fraction-denominatorshiftdown3000-axisheight1000-rulethickness1000."
+ "woff",
+ OpenTypeMathSupport::MathConstants::kFractionDenominatorShiftDown);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 3000);
+ }
+
+ {
+ auto result = MathConstant(
+ "fraction-denominatordisplaystyleshiftdown6000-axisheight1000-"
+ "rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::
+ kFractionDenominatorDisplayStyleShiftDown);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 6000);
+ }
+
+ {
+ auto result = MathConstant(
+ "fraction-numeratorgapmin9000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kFractionNumeratorGapMin);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 9000);
+ }
+
+ {
+ auto result = MathConstant(
+ "fraction-numeratordisplaystylegapmin8000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kFractionNumDisplayStyleGapMin);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 8000);
+ }
+
+ {
+ auto result = MathConstant(
+ "fraction-rulethickness10000.woff",
+ OpenTypeMathSupport::MathConstants::kFractionRuleThickness);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 10000);
+ }
+
+ {
+ auto result = MathConstant(
+ "fraction-denominatorgapmin4000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kFractionDenominatorGapMin);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 4000);
+ }
+
+ {
+ auto result = MathConstant(
+ "fraction-denominatordisplaystylegapmin5000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kFractionDenomDisplayStyleGapMin);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 5000);
+ }
+}
+
+// See third_party/blink/web_tests/external/wpt/mathml/tools/radicals.py
+TEST_F(OpenTypeMathSupportTest, MathConstantRadicals) {
+ {
+ auto result = MathConstant(
+ "radical-degreebottomraisepercent25-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kRadicalDegreeBottomRaisePercent);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, .25);
+ }
+
+ {
+ auto result =
+ MathConstant("radical-verticalgap6000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kRadicalVerticalGap);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 6000);
+ }
+
+ {
+ auto result = MathConstant(
+ "radical-displaystyleverticalgap7000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kRadicalDisplayStyleVerticalGap);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 7000);
+ }
+
+ {
+ auto result =
+ MathConstant("radical-rulethickness8000.woff",
+ OpenTypeMathSupport::MathConstants::kRadicalRuleThickness);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 8000);
+ }
+
+ {
+ auto result =
+ MathConstant("radical-extraascender3000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kRadicalExtraAscender);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 3000);
+ }
+
+ {
+ auto result = MathConstant(
+ "radical-kernbeforedegree4000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kRadicalKernBeforeDegree);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, 4000);
+ }
+
+ {
+ auto result = MathConstant(
+ "radical-kernafterdegreeminus5000-rulethickness1000.woff",
+ OpenTypeMathSupport::MathConstants::kRadicalKernAfterDegree);
+ EXPECT_TRUE(result);
+ EXPECT_FLOAT_EQ(*result, -5000);
+ }
+}
+
+} // namespace blink
diff --git a/third_party/blink/renderer/platform/testing/unit_test_helpers.cc b/third_party/blink/renderer/platform/testing/unit_test_helpers.cc
index adb0162..1215543 100644
--- a/third_party/blink/renderer/platform/testing/unit_test_helpers.cc
+++ b/third_party/blink/renderer/platform/testing/unit_test_helpers.cc
@@ -131,6 +131,13 @@
return SharedBuffer::Create(buffer.data(), buffer.size());
}
+String BlinkWebTestsFontsTestDataPath(const String& relative_path) {
+ return FilePathToWebString(
+ WebTestsFilePath()
+ .Append(FILE_PATH_LITERAL("external/wpt/fonts"))
+ .Append(WebStringToFilePath(relative_path)));
+}
+
LineReader::LineReader(const String& text) : text_(text), index_(0) {}
bool LineReader::GetNextLine(String* line) {
diff --git a/third_party/blink/renderer/platform/testing/unit_test_helpers.h b/third_party/blink/renderer/platform/testing/unit_test_helpers.h
index 87d7159..a964623 100644
--- a/third_party/blink/renderer/platform/testing/unit_test_helpers.h
+++ b/third_party/blink/renderer/platform/testing/unit_test_helpers.h
@@ -75,6 +75,12 @@
// specified.
String AccessibilityTestDataPath(const String& relative_path = String());
+// Returns Blink web_tests fonts as an absolute path, i.e.
+// <blinkRootDir>/src/third_party/blink/web_tests/external/wpt/fonts/<relative_path>.
+// It returns the top fonts test directory if |relative_path| was not
+// specified.
+String BlinkWebTestsFontsTestDataPath(const String& relative_path = String());
+
scoped_refptr<SharedBuffer> ReadFromFile(const String& path);
class LineReader {