Commit 6f1093f9 authored by Dominik Röttsches's avatar Dominik Röttsches Committed by Commit Bot

Refactor computing underline thickness as part of decoration info

Break out underline thickness computation into its own function as
preparation for computing underline thickness not only per current
ComputedStyle but for each of the ComputedStyle AppliedTextDecorations.

No functional change.

Bug: 1096038
Change-Id: I1384ec2a23735b6c8b3541e0535ca6ba5712beee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2249758Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Commit-Queue: Dominik Röttsches <drott@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779730}
parent b3d0d393
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
namespace blink { namespace blink {
namespace {
// We usually use the text decoration thickness to determine how far // We usually use the text decoration thickness to determine how far
// ink-skipped text decorations should be away from the glyph // ink-skipped text decorations should be away from the glyph
// contours. Cap this at 5 CSS px in each direction when thickness // contours. Cap this at 5 CSS px in each direction when thickness
...@@ -28,6 +30,92 @@ namespace blink { ...@@ -28,6 +30,92 @@ namespace blink {
// implementation. // implementation.
constexpr float kDecorationClipMaxDilation = 13; constexpr float kDecorationClipMaxDilation = 13;
static ResolvedUnderlinePosition ResolveUnderlinePosition(
const ComputedStyle& style,
FontBaseline baseline_type) {
// |auto| should resolve to |under| to avoid drawing through glyphs in
// scripts where it would not be appropriate (e.g., ideographs.)
// However, this has performance implications. For now, we only work with
// vertical text.
switch (baseline_type) {
case kAlphabeticBaseline:
if (style.TextUnderlinePosition() & kTextUnderlinePositionUnder)
return ResolvedUnderlinePosition::kUnder;
if (style.TextUnderlinePosition() & kTextUnderlinePositionFromFont)
return ResolvedUnderlinePosition::kNearAlphabeticBaselineFromFont;
return ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto;
case kIdeographicBaseline:
// Compute language-appropriate default underline position.
// https://drafts.csswg.org/css-text-decor-3/#default-stylesheet
UScriptCode script = style.GetFontDescription().GetScript();
if (script == USCRIPT_KATAKANA_OR_HIRAGANA || script == USCRIPT_HANGUL) {
if (style.TextUnderlinePosition() & kTextUnderlinePositionLeft) {
return ResolvedUnderlinePosition::kUnder;
}
return ResolvedUnderlinePosition::kOver;
}
if (style.TextUnderlinePosition() & kTextUnderlinePositionRight) {
return ResolvedUnderlinePosition::kOver;
}
return ResolvedUnderlinePosition::kUnder;
}
NOTREACHED();
return ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto;
}
static bool ShouldSetDecorationAntialias(const ComputedStyle& style) {
for (const auto& decoration : style.AppliedTextDecorations()) {
ETextDecorationStyle decoration_style = decoration.Style();
if (decoration_style == ETextDecorationStyle::kDotted ||
decoration_style == ETextDecorationStyle::kDashed)
return true;
}
return false;
}
float ComputeDecorationThickness(
const TextDecorationThickness text_decoration_thickness,
const ComputedStyle& style,
const SimpleFontData* font_data) {
float auto_underline_thickness =
std::max(1.f, style.ComputedFontSize() / 10.f);
if (text_decoration_thickness.IsAuto())
return auto_underline_thickness;
// In principle we would not need to test for font_data if
// |text_decoration_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 (text_decoration_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(!text_decoration_thickness.IsFromFont());
const Length& thickness_length = text_decoration_thickness.Thickness();
float font_size = font_data->PlatformData().size();
float text_decoration_thickness_pixels =
FloatValueForLength(thickness_length, font_size);
return std::max(1.f, text_decoration_thickness_pixels);
}
float DoubleOffsetFromThickness(float thickness_pixels) {
return thickness_pixels + 1.0f;
}
} // anonymous namespace
TextPainterBase::TextPainterBase(GraphicsContext& context, TextPainterBase::TextPainterBase(GraphicsContext& context,
const Font& font, const Font& font,
const PhysicalOffset& text_origin, const PhysicalOffset& text_origin,
...@@ -293,89 +381,6 @@ void TextPainterBase::PaintDecorationsOnlyLineThrough( ...@@ -293,89 +381,6 @@ void TextPainterBase::PaintDecorationsOnlyLineThrough(
context.ConcatCTM(Rotation(text_bounds_, kCounterclockwise)); context.ConcatCTM(Rotation(text_bounds_, kCounterclockwise));
} }
namespace {
static ResolvedUnderlinePosition ResolveUnderlinePosition(
const ComputedStyle& style,
FontBaseline baseline_type) {
// |auto| should resolve to |under| to avoid drawing through glyphs in
// scripts where it would not be appropriate (e.g., ideographs.)
// However, this has performance implications. For now, we only work with
// vertical text.
switch (baseline_type) {
case kAlphabeticBaseline:
if (style.TextUnderlinePosition() & kTextUnderlinePositionUnder)
return ResolvedUnderlinePosition::kUnder;
if (style.TextUnderlinePosition() & kTextUnderlinePositionFromFont)
return ResolvedUnderlinePosition::kNearAlphabeticBaselineFromFont;
return ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto;
case kIdeographicBaseline:
// Compute language-appropriate default underline position.
// https://drafts.csswg.org/css-text-decor-3/#default-stylesheet
UScriptCode script = style.GetFontDescription().GetScript();
if (script == USCRIPT_KATAKANA_OR_HIRAGANA || script == USCRIPT_HANGUL) {
if (style.TextUnderlinePosition() & kTextUnderlinePositionLeft) {
return ResolvedUnderlinePosition::kUnder;
}
return ResolvedUnderlinePosition::kOver;
}
if (style.TextUnderlinePosition() & kTextUnderlinePositionRight) {
return ResolvedUnderlinePosition::kOver;
}
return ResolvedUnderlinePosition::kUnder;
}
NOTREACHED();
return ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto;
}
static bool ShouldSetDecorationAntialias(const ComputedStyle& style) {
for (const auto& decoration : style.AppliedTextDecorations()) {
ETextDecorationStyle decoration_style = decoration.Style();
if (decoration_style == ETextDecorationStyle::kDotted ||
decoration_style == ETextDecorationStyle::kDashed)
return true;
}
return false;
}
float ComputeDecorationThickness(const ComputedStyle* style,
const SimpleFontData* font_data) {
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();
return std::max(1.f, underline_thickness_font_metric.value_or(
auto_underline_thickness));
}
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
void TextPainterBase::ComputeDecorationInfo( void TextPainterBase::ComputeDecorationInfo(
DecorationInfo& decoration_info, DecorationInfo& decoration_info,
const PhysicalOffset& box_origin, const PhysicalOffset& box_origin,
...@@ -399,28 +404,40 @@ void TextPainterBase::ComputeDecorationInfo( ...@@ -399,28 +404,40 @@ void TextPainterBase::ComputeDecorationInfo(
? decoration_info.font_data->GetFontMetrics().FloatAscent() ? decoration_info.font_data->GetFontMetrics().FloatAscent()
: 0; : 0;
if ((decoration_info.underline_position == decoration_info.thickness = ComputeUnderlineThickness(
decoration_info.underline_position, style.GetTextDecorationThickness(),
style, decorating_box_style);
decoration_info.double_offset =
DoubleOffsetFromThickness(decoration_info.thickness);
}
float TextPainterBase::ComputeUnderlineThickness(
const ResolvedUnderlinePosition& underline_position,
const TextDecorationThickness& applied_decoration_thickness,
const ComputedStyle& style,
const ComputedStyle* decorating_box_style) {
float thickness = 0;
if ((underline_position ==
ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto) || ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto) ||
decoration_info.underline_position == underline_position ==
ResolvedUnderlinePosition::kNearAlphabeticBaselineFromFont) { ResolvedUnderlinePosition::kNearAlphabeticBaselineFromFont) {
decoration_info.thickness = ComputeDecorationThickness( thickness = ComputeDecorationThickness(applied_decoration_thickness, style,
decoration_info.style, decoration_info.font_data); style.GetFont().PrimaryFont());
} else { } else {
// Compute decorating box. Position and thickness are computed from the // Compute decorating box. Position and thickness are computed from the
// decorating box. // decorating box.
// Only for non-Roman for now for the performance implications. // Only for non-Roman for now for the performance implications.
// https:// drafts.csswg.org/css-text-decor-3/#decorating-box // https:// drafts.csswg.org/css-text-decor-3/#decorating-box
if (decorating_box_style) { if (decorating_box_style) {
decoration_info.thickness = ComputeDecorationThickness( thickness = ComputeDecorationThickness(
decorating_box_style, decorating_box_style->GetFont().PrimaryFont()); applied_decoration_thickness, *decorating_box_style,
decorating_box_style->GetFont().PrimaryFont());
} else { } else {
decoration_info.thickness = ComputeDecorationThickness( thickness = ComputeDecorationThickness(
decoration_info.style, decoration_info.font_data); applied_decoration_thickness, style, style.GetFont().PrimaryFont());
} }
} }
return thickness;
// Offset between lines - always non-zero, so lines never cross each other.
decoration_info.double_offset = decoration_info.thickness + 1.f;
} }
void TextPainterBase::PaintDecorationUnderOrOverLine( void TextPainterBase::PaintDecorationUnderOrOverLine(
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/paint/decoration_info.h" #include "third_party/blink/renderer/core/paint/decoration_info.h"
#include "third_party/blink/renderer/core/paint/text_paint_style.h" #include "third_party/blink/renderer/core/paint/text_paint_style.h"
#include "third_party/blink/renderer/core/style/applied_text_decoration.h" #include "third_party/blink/renderer/core/style/applied_text_decoration.h"
#include "third_party/blink/renderer/core/style/text_decoration_thickness.h"
#include "third_party/blink/renderer/platform/fonts/font.h" #include "third_party/blink/renderer/platform/fonts/font.h"
#include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h" #include "third_party/blink/renderer/platform/transforms/affine_transform.h"
...@@ -75,6 +76,12 @@ class CORE_EXPORT TextPainterBase { ...@@ -75,6 +76,12 @@ class CORE_EXPORT TextPainterBase {
const ComputedStyle&, const ComputedStyle&,
const ComputedStyle* decorating_box_style); const ComputedStyle* decorating_box_style);
float ComputeUnderlineThickness(
const ResolvedUnderlinePosition& underline_position,
const TextDecorationThickness& applied_decoration_thickness,
const ComputedStyle&,
const ComputedStyle* decorating_box_style);
static Color TextColorForWhiteBackground(Color); static Color TextColorForWhiteBackground(Color);
static TextPaintStyle TextPaintingStyle(const Document&, static TextPaintStyle TextPaintingStyle(const Document&,
const ComputedStyle&, const ComputedStyle&,
......
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