mirror of
https://github.com/servo/servo.git
synced 2025-06-06 00:25:37 +00:00
layout: Support wavy
and double
for text-decoration-line
(#37079)
- Add support for `text-decoration-line: double`: Line drawing is done similar to how it works in Firefox and Chromium. A gap of half of line thickness is added between each line. - Fix support for `text-decoration-line: wavy`: Wavy lines rectangles were not calcualted properly, which meant they were rendered as solid lines. Now the amplitude of the wave is 1.5 times line thickness. Testing: A manual test is updated `tests/html/text_deco_simple.html` to cover more cases. In general, rendering of text-decorations is difficult to test via reftesting. Fixes #17887. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
0ea40d6365
commit
7f0cebd442
3 changed files with 84 additions and 20 deletions
|
@ -125,11 +125,15 @@ impl ToWebRender for ComputedTextDecorationStyle {
|
||||||
type Type = LineStyle;
|
type Type = LineStyle;
|
||||||
fn to_webrender(&self) -> Self::Type {
|
fn to_webrender(&self) -> Self::Type {
|
||||||
match *self {
|
match *self {
|
||||||
ComputedTextDecorationStyle::Solid => LineStyle::Solid,
|
ComputedTextDecorationStyle::Solid | ComputedTextDecorationStyle::Double => {
|
||||||
|
LineStyle::Solid
|
||||||
|
},
|
||||||
ComputedTextDecorationStyle::Dotted => LineStyle::Dotted,
|
ComputedTextDecorationStyle::Dotted => LineStyle::Dotted,
|
||||||
ComputedTextDecorationStyle::Dashed => LineStyle::Dashed,
|
ComputedTextDecorationStyle::Dashed => LineStyle::Dashed,
|
||||||
ComputedTextDecorationStyle::Wavy => LineStyle::Wavy,
|
ComputedTextDecorationStyle::Wavy => LineStyle::Wavy,
|
||||||
_ => LineStyle::Solid,
|
ComputedTextDecorationStyle::MozNone => {
|
||||||
|
unreachable!("Should never try to draw a moz-none text decoration")
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use base::id::ScrollTreeNodeId;
|
||||||
use clip::{Clip, ClipId};
|
use clip::{Clip, ClipId};
|
||||||
use compositing_traits::display_list::{CompositorDisplayListInfo, SpatialTreeNodeInfo};
|
use compositing_traits::display_list::{CompositorDisplayListInfo, SpatialTreeNodeInfo};
|
||||||
use embedder_traits::Cursor;
|
use embedder_traits::Cursor;
|
||||||
use euclid::{Point2D, SideOffsets2D, Size2D, UnknownUnit};
|
use euclid::{Point2D, SideOffsets2D, Size2D, UnknownUnit, Vector2D};
|
||||||
use fonts::GlyphStore;
|
use fonts::GlyphStore;
|
||||||
use gradient::WebRenderGradient;
|
use gradient::WebRenderGradient;
|
||||||
use range::Range as ServoRange;
|
use range::Range as ServoRange;
|
||||||
|
@ -21,7 +21,9 @@ use servo_geometry::MaxRect;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
use style::color::{AbsoluteColor, ColorSpace};
|
use style::color::{AbsoluteColor, ColorSpace};
|
||||||
use style::computed_values::border_image_outset::T as BorderImageOutset;
|
use style::computed_values::border_image_outset::T as BorderImageOutset;
|
||||||
use style::computed_values::text_decoration_style::T as ComputedTextDecorationStyle;
|
use style::computed_values::text_decoration_style::{
|
||||||
|
T as ComputedTextDecorationStyle, T as TextDecorationStyle,
|
||||||
|
};
|
||||||
use style::dom::OpaqueNode;
|
use style::dom::OpaqueNode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::properties::longhands::visibility::computed_value::T as Visibility;
|
use style::properties::longhands::visibility::computed_value::T as Visibility;
|
||||||
|
@ -737,6 +739,7 @@ impl Fragment {
|
||||||
let rect = fragment.rect.translate(containing_block.origin.to_vector());
|
let rect = fragment.rect.translate(containing_block.origin.to_vector());
|
||||||
let mut baseline_origin = rect.origin;
|
let mut baseline_origin = rect.origin;
|
||||||
baseline_origin.y += fragment.font_metrics.ascent;
|
baseline_origin.y += fragment.font_metrics.ascent;
|
||||||
|
|
||||||
let glyphs = glyphs(
|
let glyphs = glyphs(
|
||||||
&fragment.glyphs,
|
&fragment.glyphs,
|
||||||
baseline_origin,
|
baseline_origin,
|
||||||
|
@ -785,11 +788,13 @@ impl Fragment {
|
||||||
rect.origin.y += font_metrics.ascent - font_metrics.underline_offset;
|
rect.origin.y += font_metrics.ascent - font_metrics.underline_offset;
|
||||||
rect.size.height =
|
rect.size.height =
|
||||||
Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
|
Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
|
||||||
|
|
||||||
self.build_display_list_for_text_decoration(
|
self.build_display_list_for_text_decoration(
|
||||||
&parent_style,
|
&parent_style,
|
||||||
builder,
|
builder,
|
||||||
&rect,
|
&rect,
|
||||||
text_decoration,
|
text_decoration,
|
||||||
|
TextDecorationLine::UNDERLINE,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -804,6 +809,7 @@ impl Fragment {
|
||||||
builder,
|
builder,
|
||||||
&rect,
|
&rect,
|
||||||
text_decoration,
|
text_decoration,
|
||||||
|
TextDecorationLine::OVERLINE,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -896,6 +902,7 @@ impl Fragment {
|
||||||
builder,
|
builder,
|
||||||
&rect,
|
&rect,
|
||||||
text_decoration,
|
text_decoration,
|
||||||
|
TextDecorationLine::LINE_THROUGH,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -911,22 +918,46 @@ impl Fragment {
|
||||||
builder: &mut DisplayListBuilder,
|
builder: &mut DisplayListBuilder,
|
||||||
rect: &PhysicalRect<Au>,
|
rect: &PhysicalRect<Au>,
|
||||||
text_decoration: &FragmentTextDecoration,
|
text_decoration: &FragmentTextDecoration,
|
||||||
|
line: TextDecorationLine,
|
||||||
) {
|
) {
|
||||||
let rect = rect.to_webrender();
|
|
||||||
let wavy_line_thickness = (0.33 * rect.size().height).ceil();
|
|
||||||
if text_decoration.style == ComputedTextDecorationStyle::MozNone {
|
if text_decoration.style == ComputedTextDecorationStyle::MozNone {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut rect = rect.to_webrender();
|
||||||
|
let line_thickness = rect.height().ceil();
|
||||||
|
|
||||||
|
if text_decoration.style == ComputedTextDecorationStyle::Wavy {
|
||||||
|
rect = rect.inflate(0.0, line_thickness * 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
let common_properties = builder.common_properties(rect, parent_style);
|
let common_properties = builder.common_properties(rect, parent_style);
|
||||||
builder.wr().push_line(
|
builder.wr().push_line(
|
||||||
&common_properties,
|
&common_properties,
|
||||||
&rect,
|
&rect,
|
||||||
wavy_line_thickness,
|
line_thickness,
|
||||||
wr::LineOrientation::Horizontal,
|
wr::LineOrientation::Horizontal,
|
||||||
&rgba(text_decoration.color),
|
&rgba(text_decoration.color),
|
||||||
text_decoration.style.to_webrender(),
|
text_decoration.style.to_webrender(),
|
||||||
);
|
);
|
||||||
// XXX(ferjm) support text-decoration-style: double
|
|
||||||
|
if text_decoration.style == TextDecorationStyle::Double {
|
||||||
|
let half_height = (rect.height() / 2.0).floor().max(1.0);
|
||||||
|
let y_offset = match line {
|
||||||
|
TextDecorationLine::OVERLINE => -rect.height() - half_height,
|
||||||
|
_ => rect.height() + half_height,
|
||||||
|
};
|
||||||
|
let rect = rect.translate(Vector2D::new(0.0, y_offset));
|
||||||
|
let common_properties = builder.common_properties(rect, parent_style);
|
||||||
|
builder.wr().push_line(
|
||||||
|
&common_properties,
|
||||||
|
&rect,
|
||||||
|
line_thickness,
|
||||||
|
wr::LineOrientation::Horizontal,
|
||||||
|
&rgba(text_decoration.color),
|
||||||
|
text_decoration.style.to_webrender(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,46 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<p style="text-decoration:none;"> none </p>
|
|
||||||
<p style="text-decoration:underline;"> text underline </p>
|
<style>
|
||||||
<p style="text-decoration:overline;"> text underline </p>
|
p {
|
||||||
<p style="text-decoration:line-through;"> text underline </p>
|
font-family: "Times New Roman";
|
||||||
<p>
|
background: lightgrey;
|
||||||
<p style="font-size:40px; text-decoration:underline; font-family:Verdana;"> text underline pqrstg </p>
|
padding: 5px;
|
||||||
<p style="text-decoration:overline;"> text overline xxxxxxxxXXXXXXX</p>
|
margin: 5px;
|
||||||
<p style="font-size:50px; text-decoration:line-through;"> text line-through xxxxxxxxXXXXX</p>
|
}
|
||||||
<p style="text-decoration:blink;"> text blink </p>
|
</style>
|
||||||
|
|
||||||
|
<p style="text-decoration: none blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: underline blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: overline blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: line-through blue;">text-decoration: </p>
|
||||||
|
|
||||||
|
<p style="text-decoration: underline double blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: overline double blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: line-through double blue;">text-decoration: </p>
|
||||||
|
|
||||||
|
<p style="text-decoration: underline wavy blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: overline wavy blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: line-through wavy blue;">text-decoration: </p>
|
||||||
|
|
||||||
|
<p style="text-decoration: underline dashed blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: overline dashed blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: line-through dashed blue;">text-decoration: </p>
|
||||||
|
|
||||||
|
<p style="text-decoration: underline dotted blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: overline dotted blue;">text-decoration: </p>
|
||||||
|
<p style="text-decoration: line-through dotted blue;">text-decoration: </p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
for (paragraph of document.querySelectorAll("p")) {
|
||||||
|
paragraph.innerText += " " +
|
||||||
|
getComputedStyle(paragraph).textDecorationLine + " " +
|
||||||
|
getComputedStyle(paragraph).textDecorationStyle;
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue