Skip to content
Permalink
Browse files
[Painting] Underline thickness should be aligned with device pixels
https://bugs.webkit.org/show_bug.cgi?id=243611

Reviewed by Antti Koivisto.

Ceil the underline thickness to the nearest device pixel. It ensures that we always paint at least a hairline thick underline when applicable (i.e. 0.1px -> 0.5px on a 2x display).

* Source/WebCore/rendering/TextDecorationPainter.cpp:
(WebCore::TextDecorationPainter::paintBackgroundDecorations):
(WebCore::TextDecorationPainter::paintForegroundDecorations):
(WebCore::TextDecorationPainter::paintLineThrough):
* Source/WebCore/rendering/TextDecorationPainter.h:

Canonical link: https://commits.webkit.org/253182@main
  • Loading branch information
alanbaradlay committed Aug 6, 2022
1 parent 3cc8f9c commit 78731544fca9d442c084bde74a48972ca10ba8c7
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 7 deletions.
@@ -6,7 +6,7 @@
<link rel="match" href="-apple-color-filter-text-decoration-shadow-expected.html">

<meta name="assert" content="-apple-color-filter affects text decoration shadows">
<meta name="fuzzy" content="maxDifference=0-1; totalPixels=0-9430">
<meta name="fuzzy" content="maxDifference=0-1; totalPixels=0-9668">
<style type="text/css">
.test
{
@@ -202,6 +202,7 @@ TextDecorationPainter::TextDecorationPainter(GraphicsContext& context, OptionSet
, m_shadowColorFilter(colorFilter)
, m_textBox(textBox)
, m_font { font }
, m_deviceScaleFactor(textBox->renderer().document().deviceScaleFactor())
, m_styles { styles ? *WTFMove(styles) : stylesForRenderer(textBox->renderer(), decorations, isFirstLine, PseudoId::None) }
, m_lineStyle { isFirstLine ? textBox->renderer().firstLineStyle() : textBox->renderer().style() }
{
@@ -211,7 +212,7 @@ TextDecorationPainter::TextDecorationPainter(GraphicsContext& context, OptionSet
void TextDecorationPainter::paintBackgroundDecorations(const TextRun& textRun, const FloatPoint& textOrigin, const FloatPoint& boxOrigin)
{
const auto& fontMetrics = m_lineStyle.metricsOfPrimaryFont();
float textDecorationThickness = m_lineStyle.textDecorationThickness().resolve(m_lineStyle.computedFontSize(), fontMetrics);
auto textDecorationThickness = ceilToDevicePixel(m_lineStyle.textDecorationThickness().resolve(m_lineStyle.computedFontSize(), fontMetrics), m_deviceScaleFactor);
FloatPoint localOrigin = boxOrigin;

auto paintDecoration = [&] (TextDecorationLine decoration, TextDecorationStyle style, const Color& color, const FloatRect& rect) {
@@ -292,7 +293,7 @@ void TextDecorationPainter::paintBackgroundDecorations(const TextRun& textRun, c
if (m_decorations.contains(TextDecorationLine::Overline)) {
float wavyOffset = m_styles.overlineStyle == TextDecorationStyle::Wavy ? m_wavyOffset : 0;
FloatRect rect(localOrigin, FloatSize(m_width, textDecorationThickness));
float autoTextDecorationThickness = TextDecorationThickness::createWithAuto().resolve(m_lineStyle.computedFontSize(), fontMetrics);
float autoTextDecorationThickness = ceilToDevicePixel(TextDecorationThickness::createWithAuto().resolve(m_lineStyle.computedFontSize(), fontMetrics), m_deviceScaleFactor);
rect.move(0, autoTextDecorationThickness - textDecorationThickness - wavyOffset);
paintDecoration(TextDecorationLine::Overline, m_styles.overlineStyle, m_styles.overlineColor, rect);
}
@@ -314,15 +315,15 @@ void TextDecorationPainter::paintForegroundDecorations(const FloatPoint& boxOrig
if (!m_decorations.contains(TextDecorationLine::LineThrough))
return;

float textDecorationThickness = m_lineStyle.textDecorationThickness().resolve(m_lineStyle.computedFontSize(), m_lineStyle.metricsOfPrimaryFont());
auto textDecorationThickness = ceilToDevicePixel(m_lineStyle.textDecorationThickness().resolve(m_lineStyle.computedFontSize(), m_lineStyle.metricsOfPrimaryFont()), m_deviceScaleFactor);
paintLineThrough(m_styles.linethroughColor, textDecorationThickness, boxOrigin);
}

void TextDecorationPainter::paintLineThrough(const Color& color, float thickness, const FloatPoint& localOrigin)
{
const auto& fontMetrics = m_lineStyle.metricsOfPrimaryFont();
FloatRect rect(localOrigin, FloatSize(m_width, thickness));
float autoTextDecorationThickness = TextDecorationThickness::createWithAuto().resolve(m_lineStyle.computedFontSize(), fontMetrics);
auto autoTextDecorationThickness = ceilToDevicePixel(TextDecorationThickness::createWithAuto().resolve(m_lineStyle.computedFontSize(), fontMetrics), m_deviceScaleFactor);
auto center = 2 * fontMetrics.floatAscent() / 3 + autoTextDecorationThickness / 2;
rect.move(0, center - thickness / 2);

@@ -69,15 +69,16 @@ class TextDecorationPainter {

GraphicsContext& m_context;
OptionSet<TextDecorationLine> m_decorations;
float m_wavyOffset;
float m_wavyOffset { 0 };
float m_width { 0 };
FloatPoint m_boxOrigin;
bool m_isPrinting;
bool m_isPrinting { false };
bool m_isHorizontal { true };
const ShadowData* m_shadow { nullptr };
const FilterOperations* m_shadowColorFilter { nullptr };
InlineIterator::TextBoxIterator m_textBox;
const FontCascade& m_font;
float m_deviceScaleFactor { 0 };

Styles m_styles;
const RenderStyle& m_lineStyle;

0 comments on commit 7873154

Please sign in to comment.