Commit 013ee755 authored by Dominik Röttsches's avatar Dominik Röttsches Committed by Commit Bot

Use text-decoration-thickness value in underline painting

Parsing of text-decoration-thickness was added in [1], use the parsed
value in text decoration thickness painting.

Add a WPT ref test that compares text-decoration-thickness value from a
variable font (keyword value 'from-font' for text-decoration-thickness)
with the identical rendering achieved by using a static font with thick
and thin underline metadata.

Add a second WPT ref test that compares a fixed
text-decoration-thickness value to the from-font values of a font with
thick and thin underlines.

[1] https://chromium-review.googlesource.com/c/chromium/src/+/2178888

Bug: 785230
Change-Id: I626a321a38c77e106215b640dcf85c20f7a0ad93
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2218119
Commit-Queue: Dominik Röttsches <drott@chromium.org>
Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#775116}
parent 25560c2d
......@@ -157,6 +157,7 @@ const InterpolationTypes& CSSInterpolationTypesMap::Get(
case CSSPropertyID::kShapeMargin:
case CSSPropertyID::kStrokeDashoffset:
case CSSPropertyID::kStrokeWidth:
case CSSPropertyID::kTextDecorationThickness:
case CSSPropertyID::kTop:
case CSSPropertyID::kVerticalAlign:
case CSSPropertyID::kWebkitBorderHorizontalSpacing:
......
......@@ -37,10 +37,12 @@ int NGTextDecorationOffset::ComputeUnderlineOffsetForUnder(
int offset_int = offset.Floor();
// Gaps are not needed for TextTop because it generally has internal
// leadings.
// leadings. Overline needs to grow upwards, hence subtract thickness.
if (position_type == FontVerticalPositionType::TextTop)
return offset_int;
return !IsLineOverSide(position_type) ? offset_int + 1 : offset_int - 1;
return offset_int - floorf(text_decoration_thickness);
return !IsLineOverSide(position_type)
? offset_int + 1
: offset_int - 1 - floorf(text_decoration_thickness);
}
} // namespace blink
......@@ -27,10 +27,12 @@ int TextDecorationOffset::ComputeUnderlineOffsetForUnder(
int offset_int = (farthest - logical_top).Floor();
// Gaps are not needed for TextTop because it generally has internal
// leadings.
// leadings. Overline needs to grow upwards, hence subtract thickness.
if (position_type == FontVerticalPositionType::TextTop)
return offset_int;
return !IsLineOverSide(position_type) ? offset_int + 1 : offset_int - 1;
return offset_int - floorf(text_decoration_thickness);
return !IsLineOverSide(position_type)
? offset_int + 1
: offset_int - 1 - floorf(text_decoration_thickness);
}
} // namespace blink
......@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/shadow_list.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
#include "third_party/blink/renderer/platform/geometry/length_functions.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
......@@ -20,6 +21,13 @@
namespace blink {
// We usually use the text decoration thickness to determine how far
// ink-skipped text decorations should be away from the glyph
// contours. Cap this at 5 CSS px in each direction when thickness
// growths larger than that. A value of 13 closely matches FireFox'
// implementation.
constexpr float kDecorationClipMaxDilation = 13;
TextPainterBase::TextPainterBase(GraphicsContext& context,
const Font& font,
const PhysicalOffset& text_origin,
......@@ -264,10 +272,18 @@ void TextPainterBase::PaintDecorationsOnlyLineThrough(
for (const AppliedTextDecoration& decoration : decorations) {
TextDecoration lines = decoration.Lines();
if (EnumHasFlags(lines, TextDecoration::kLineThrough)) {
const float line_through_offset = 2 * decoration_info.baseline / 3;
// For increased line thickness, the line-through decoration needs to grow
// in both directions from its origin, subtract half the thickness to keep
// it centered at the same origin.
const float line_through_offset =
2 * decoration_info.baseline / 3 - decoration_info.thickness / 2;
// Floor double_offset in order to avoid double-line gap to appear
// of different size depending on position where the double line
// is drawn because of rounding downstream in
// GraphicsContext::DrawLineForText.
AppliedDecorationPainter decoration_painter(
context, decoration_info, line_through_offset, decoration,
decoration_info.double_offset, 0);
floorf(decoration_info.double_offset), 0);
// No skip: ink for line-through,
// compare https://github.com/w3c/csswg-drafts/issues/711
decoration_painter.Paint();
......@@ -326,17 +342,41 @@ static bool ShouldSetDecorationAntialias(const ComputedStyle& style) {
float ComputeDecorationThickness(const ComputedStyle* style,
const SimpleFontData* font_data) {
// TODO(https://crbug.com/785230): Implement text-decoration-thickness setting
// and the from-font keyword here. We previously tried reading
// font_data->FontMetrics().UnderlineThickness() here but that never returned
// anything other than 0. Removed no-op implementation until we implement
// from-font behavior here. Keep font_data argument for now as this will be
// needed for the from-font implementation.
// Set the thickness of the line to be 10% (or something else ?)of the
// computed font size and not less than 1px. Using computedFontSize should
// take care of zoom as well.
return std::max(1.f, style->ComputedFontSize() / 10.f);
DCHECK(style);
const TextDecorationThickness& style_thickness =
style->GetTextDecorationThickness();
float auto_underline_thickness =
std::max(1.f, style->ComputedFontSize() / 10.f);
if (style_thickness.IsAuto())
return auto_underline_thickness;
// In principle we would not need to test for font_data if
// |style_thickness.Thickness()| is fixed, but a null font_data here
// would be a rare / error situation anyway, so practically, we can
// early out here.
if (!font_data)
return auto_underline_thickness;
if (style_thickness.IsFromFont()) {
base::Optional<float> underline_thickness_font_metric =
font_data->GetFontMetrics().UnderlineThickness().value();
if (!underline_thickness_font_metric)
return auto_underline_thickness;
return std::max(1.f, underline_thickness_font_metric.value());
}
DCHECK(!style_thickness.IsFromFont());
const Length& style_thickness_length = style_thickness.Thickness();
float font_size = font_data->PlatformData().size();
float text_decoration_thickness_pixels =
FloatValueForLength(style_thickness_length, font_size);
return std::max(1.f, text_decoration_thickness_pixels);
}
} // anonymous namespace
......@@ -399,10 +439,11 @@ void TextPainterBase::PaintDecorationUnderOrOverLine(
if (decoration_info.style->TextDecorationSkipInk() ==
ETextDecorationSkipInk::kAuto) {
FloatRect decoration_bounds = decoration_painter.Bounds();
ClipDecorationsStripe(-decoration_info.baseline + decoration_bounds.Y() -
decoration_info.local_origin.Y(),
decoration_bounds.Height(),
decoration_info.thickness);
ClipDecorationsStripe(
-decoration_info.baseline + decoration_bounds.Y() -
decoration_info.local_origin.Y(),
decoration_bounds.Height(),
std::min(decoration_info.thickness, kDecorationClipMaxDilation));
}
decoration_painter.Paint();
}
......
......@@ -22,6 +22,7 @@ class TextDecorationThickness {
bool IsFromFont() const { return thickness_from_font_; }
Length Thickness() const;
bool IsAuto() const { return !thickness_from_font_ && thickness_.IsAuto(); }
bool operator==(const TextDecorationThickness&) const;
......
......@@ -734,8 +734,22 @@ crbug.com/1067242 [ Mac10.11 ] external/wpt/css/css-text-decor/text-underline-po
crbug.com/1067242 [ Mac10.12 ] external/wpt/css/css-text-decor/text-underline-position-from-font-variable.html [ Failure ]
crbug.com/1067242 [ Mac10.13 ] external/wpt/css/css-text-decor/text-underline-position-from-font-variable.html [ Failure ]
crbug.com/1067242 [ Retina ] external/wpt/css/css-text-decor/text-underline-position-from-font-variable.html [ Failure ]
crbug.com/785230 [ Win7 ] external/wpt/css/css-text-decor/text-decoration-thickness-fixed.html [ Failure ]
crbug.com/785230 [ Mac10.10 ] external/wpt/css/css-text-decor/text-decoration-thickness-fixed.html [ Failure ]
crbug.com/785230 [ Mac10.11 ] external/wpt/css/css-text-decor/text-decoration-thickness-fixed.html [ Failure ]
crbug.com/785230 [ Mac10.12 ] external/wpt/css/css-text-decor/text-decoration-thickness-fixed.html [ Failure ]
crbug.com/785230 [ Mac10.13 ] external/wpt/css/css-text-decor/text-decoration-thickness-fixed.html [ Failure ]
crbug.com/785230 [ Retina ] external/wpt/css/css-text-decor/text-decoration-thickness-fixed.html [ Failure ]
crbug.com/785230 [ Win7 ] external/wpt/css/css-text-decor/text-decoration-thickness-from-font-variable.html [ Failure ]
crbug.com/785230 [ Mac10.10 ] external/wpt/css/css-text-decor/text-decoration-thickness-from-font-variable.html [ Failure ]
crbug.com/785230 [ Mac10.11 ] external/wpt/css/css-text-decor/text-decoration-thickness-from-font-variable.html [ Failure ]
crbug.com/785230 [ Mac10.12 ] external/wpt/css/css-text-decor/text-decoration-thickness-from-font-variable.html [ Failure ]
crbug.com/785230 [ Mac10.13 ] external/wpt/css/css-text-decor/text-decoration-thickness-from-font-variable.html [ Failure ]
crbug.com/785230 [ Retina ] external/wpt/css/css-text-decor/text-decoration-thickness-from-font-variable.html [ Failure ]
# Windows 10 bots are not on high enough a Windows version to render variable fonts in DirectWrite
crbug.com/1068947 [ Win10 ] external/wpt/css/css-text-decor/text-underline-position-from-font-variable.html [ Failure ]
crbug.com/1068947 [ Win10 ] external/wpt/css/css-text-decor/text-decoration-thickness-fixed.html [ Failure ]
crbug.com/1068947 [ Win10 ] external/wpt/css/css-text-decor/text-decoration-thickness-from-font-variable.html [ Failure ]
# Tentative mansonry tests
crbug.com/1076027 external/wpt/css/css-grid/masonry.tentative/* [ Skip ]
......@@ -2584,8 +2598,6 @@ crbug.com/1012242 external/wpt/webvtt/rendering/cues-with-video/processing-model
crbug.com/965409 external/wpt/css/css-font-loading/fontface-descriptor-updates.html [ Failure ]
# Implement text-decoration-thickness and text-decoration-offset
crbug.com/785230 external/wpt/css/css-text-decor/text-decoration-thickness-001.html [ Failure ]
crbug.com/785230 external/wpt/css/css-text-decor/text-decoration-thickness-linethrough-001.html [ Failure ]
crbug.com/785230 external/wpt/css/css-text-decor/text-decoration-thickness-overline-001.html [ Failure ]
crbug.com/785230 external/wpt/css/css-text-decor/text-decoration-thickness-scroll-001.html [ Failure ]
crbug.com/785230 external/wpt/css/css-text-decor/text-decoration-thickness-underline-001.html [ Failure ]
......@@ -2593,6 +2605,9 @@ crbug.com/785230 external/wpt/css/css-text-decor/text-decoration-thickness-verti
crbug.com/785230 external/wpt/css/css-text-decor/text-decoration-thickness-vertical-002.html [ Failure ]
crbug.com/785230 external/wpt/css/css-text-decor/text-underline-offset-002.html [ Failure ]
# Linux draws antialiasing differently when overlaying two text layers.
crbug.com/785230 [ Linux ] external/wpt/css/css-text-decor/text-decoration-thickness-ink-skip-dilation.html [ Failure ]
# Implement support for percentage values in scale
crbug.com/1029997 external/wpt/css/css-transforms/transform-scale-percent-001.html [ Failure ]
......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Text Decoration Test: text-decoration-thickness respects variable font properties</title>
<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
<meta name="assert" content="text-decoration-thickness fixed values match thick and thin values from font.">
<link rel="author" title="Dominik Röttsches" href="mailto:drott@chromium.org">
<style>
@font-face {
font-family: underline-thin;
src: url(../resources/UnderlineTest-Thin.ttf);
}
@font-face {
font-family: underline-thick;
src: url(../resources/UnderlineTest-Thick.ttf);
}
.test {
text-underline-position: from-font;
font-size: 64px;
line-height: 1.8;
}
.thin_underline {
text-decoration: underline;
font-family: underline-thin;
text-decoration-thickness: from-font;
}
.thick_underline {
text-decoration: underline;
font-family: underline-thick;
text-decoration-thickness: from-font;
}
</style>
</head>
<body>
<p>Test passes if underlines are thin, thick, thin, thick in this order and match the reference rendering.</p>
<div class="test"><span class="thin_underline">aagaa</span></div>
<div class="test"><span class="thick_underline">aagaa</span></div>
<div class="test"><span class="thin_underline">aagaa</span></div>
<div class="test"><span class="thick_underline">aagaa</span></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Text Decoration Test: text-decoration-thickness respects variable font properties</title>
<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
<meta name="assert" content="text-decoration-thickness from-font respects MVAR table of variable fonts for variable metrics">
<link rel="author" title="Dominik Röttsches" href="mailto:drott@chromium.org">
<style>
@font-face {
font-family: underline-thin;
src: url(../resources/UnderlineTest-Thin.ttf);
}
@font-face {
font-family: underline-thick;
src: url(../resources/UnderlineTest-Thick.ttf);
}
.test {
text-underline-position: from-font;
font-size: 64px;
line-height: 1.8;
}
.thin_underline {
text-decoration: underline;
font-family: underline-thin;
text-decoration-thickness: from-font;
}
.thick_underline {
text-decoration: underline;
font-family: underline-thick;
text-decoration-thickness: from-font;
}
</style>
</head>
<body>
<p>Test passes if the underline on the first line is thin and thick on the second line.</p>
<div class="test"><span class="thin_underline">aagaa</span></div>
<div class="test"><span class="thick_underline">aagaa</span></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Text Decoration Test: Ink skipping extends only a small distance away from glyph</title>
<link rel="author" title="Dominik Röttsches" href="mailto:drott@chromium.org">
<style>
@font-face {
font-family: underline-variable;
src: url(../resources/UnderlineTest-VF.ttf);
}
.test_green {
text-decoration: underline;
font-family: underline-variable;
text-underline-position: from-font;
text-decoration-thickness: 25px;
font-size: 64px;
text-decoration-color: green;
}
.overlap {
position: absolute;
left: 20px;
top: 25px;
}
</style>
</head>
<body>
<p>Test passes if no blips of red underline show near the descender of the g glyph.</p>
<div class="test">
<div class="test_green overlap">aaaaagaaaaa</div>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Text Decoration Test: text-decoration-thickness respects variable font properties</title>
<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
<meta name="assert" content="text-decoration-thickness fixed values match thick and thin values from font.">
<link rel="author" title="Dominik Röttsches" href="mailto:drott@chromium.org">
<link rel="match" href="reference/text-decoration-thickness-fixed-ref.html">
<style>
@font-face {
font-family: underline-variable;
src: url(resources/UnderlineTest-VF.ttf);
}
.test {
text-underline-position: from-font;
font-size: 64px;
line-height: 1.8;
}
.thin_underline {
font-family: underline-variable;
text-decoration: underline;
text-decoration-thickness: 0.2px;
}
.thick_underline {
font-family: underline-variable;
text-decoration: underline;
text-decoration-thickness: 6.3px;
}
.thin_underline_percent {
font-family: underline-variable;
text-decoration: underline;
text-decoration-thickness: 0.3152%;
}
.thick_underline_percent {
font-family: underline-variable;
text-decoration: underline;
text-decoration-thickness: 9.84375%;
}
</style>
</head>
<body>
<p>Test passes if underlines are thin, thick, thin, thick in this order and match the reference rendering.</p>
<div class="test"><span class="thin_underline">aagaa</span></div>
<div class="test"><span class="thick_underline">aagaa</span></div>
<div class="test"><span class="thin_underline_percent">aagaa</span></div>
<div class="test"><span class="thick_underline_percent">aagaa</span></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Text Decoration Test: text-decoration-thickness respects variable font properties</title>
<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property">
<meta name="assert" content="text-decoration-thickness from-font respects MVAR table of variable fonts for variable metrics">
<link rel="author" title="Dominik Röttsches" href="mailto:drott@chromium.org">
<link rel="match" href="reference/text-decoration-thickness-from-font-variable-ref.html">
<style>
@font-face {
font-family: underline-variable;
src: url(resources/UnderlineTest-VF.ttf);
}
.test {
text-underline-position: from-font;
font-size: 64px;
line-height: 1.8;
}
.thin_underline {
text-decoration: underline;
text-decoration-thickness: from-font;
font-family: underline-variable, sans-serif;
font-variation-settings: 'UNDS' 1;
}
.thick_underline {
text-decoration: underline;
text-decoration-thickness: from-font;
font-family: underline-variable, sans-serif;
font-variation-settings: 'UNDS' 1000;
}
</style>
</head>
<body>
<p>Test passes if the underline on the first line is thin and thick on the second line.</p>
<div class="test"><span class="thin_underline">aagaa</span></div>
<div class="test"><span class="thick_underline">aagaa</span></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Text Decoration Test: Ink skipping extends only a small distance away from glyph</title>
<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-skip-ink-property">
<meta name="assert" content="Ink skipping gap is capped at a small distance and does not continuously grow with text-decoration-thickness.">
<link rel="author" title="Dominik Röttsches" href="mailto:drott@chromium.org">
<link rel="match" href="reference/text-decoration-thickness-ink-skip-dilation-ref.html">
<style>
@font-face {
font-family: underline-variable;
src: url(resources/UnderlineTest-VF.ttf);
}
.test_red {
font-family: underline-variable;
font-size: 64px;
}
.underline {
text-decoration: underline;
text-underline-position: from-font;
text-decoration-thickness: 13px;
text-decoration-color: red;
}
.test_green {
text-decoration: underline;
font-family: underline-variable;
text-underline-position: from-font;
text-decoration-thickness: 25px;;
font-size: 64px;
text-decoration-color: green;
}
.overlap {
position: absolute;
left: 20px;
top: 25px;
}
</style>
</head>
<body>
<p>Test passes if no blips of red underline show near the descender of the g glyph.</p>
<div class="test">
<div class="test_red overlap">a<span class="underline">aaaagaaaa</span>a</div>
<div class="test_green overlap">aaaaagaaaaa</div>
</div>
</div>
</body>
</html>
Tests that watchPosition does not report position changes when the page is not visible.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
* Page is visible
device moved to (52.478, 0.834)
Page is notified of the position change
PASS isPageVisible is true
PASS position.coords.latitude is 52.478
PASS position.coords.longitude is 0.834
device moved to (53.478, 1.834)
Page is notified of the position change
PASS isPageVisible is true
PASS position.coords.latitude is 53.478
PASS position.coords.longitude is 1.834
* Hiding page
FAIL Error callback invoked unexpectedly
PASS successfullyParsed is true
TEST COMPLETE
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