Auto merge of #25888 - ferjm:text.decoration.2020, r=nox

Partial text decoration support for layout 2020

- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #25166
- [X] There are tests for these changes
This commit is contained in:
bors-servo 2020-03-23 11:18:18 -04:00 committed by GitHub
commit acd14672e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
84 changed files with 743 additions and 53 deletions

View file

@ -4,6 +4,7 @@
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize}; use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize};
use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode; use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
use style::computed_values::text_decoration_style::T as ComputedTextDecorationStyle;
use style::computed_values::transform_style::T as ComputedTransformStyle; use style::computed_values::transform_style::T as ComputedTransformStyle;
use style::values::computed::Filter as ComputedFilter; use style::values::computed::Filter as ComputedFilter;
use style::values::computed::Length; use style::values::computed::Length;
@ -100,3 +101,16 @@ impl ToWebRender for PhysicalSides<Length> {
) )
} }
} }
impl ToWebRender for ComputedTextDecorationStyle {
type Type = webrender_api::LineStyle;
fn to_webrender(&self) -> Self::Type {
match *self {
ComputedTextDecorationStyle::Solid => wr::LineStyle::Solid,
ComputedTextDecorationStyle::Dotted => wr::LineStyle::Dotted,
ComputedTextDecorationStyle::Dashed => wr::LineStyle::Dashed,
ComputedTextDecorationStyle::Wavy => wr::LineStyle::Wavy,
_ => wr::LineStyle::Solid,
}
}
}

View file

@ -4,7 +4,7 @@
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::display_list::conversions::ToWebRender; use crate::display_list::conversions::ToWebRender;
use crate::fragments::{BoxFragment, Fragment}; use crate::fragments::{BoxFragment, Fragment, TextFragment};
use crate::geom::{PhysicalPoint, PhysicalRect}; use crate::geom::{PhysicalPoint, PhysicalRect};
use crate::replaced::IntrinsicSizes; use crate::replaced::IntrinsicSizes;
use embedder_traits::Cursor; use embedder_traits::Cursor;
@ -13,10 +13,11 @@ use gfx::text::glyph::GlyphStore;
use mitochondria::OnceCell; use mitochondria::OnceCell;
use net_traits::image_cache::UsePlaceholder; use net_traits::image_cache::UsePlaceholder;
use std::sync::Arc; use std::sync::Arc;
use style::computed_values::text_decoration_style::T as ComputedTextDecorationStyle;
use style::dom::OpaqueNode; use style::dom::OpaqueNode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{BorderStyle, Length, LengthPercentage}; use style::values::computed::{BorderStyle, Length, LengthPercentage};
use style::values::specified::text::TextDecorationLine;
use style::values::specified::ui::CursorKind; use style::values::specified::ui::CursorKind;
use webrender_api::{self as wr, units}; use webrender_api::{self as wr, units};
@ -80,30 +81,6 @@ impl Fragment {
Fragment::Box(b) => BuilderForBoxFragment::new(b, containing_block).build(builder), Fragment::Box(b) => BuilderForBoxFragment::new(b, containing_block).build(builder),
Fragment::AbsoluteOrFixedPositioned(_) => {}, Fragment::AbsoluteOrFixedPositioned(_) => {},
Fragment::Anonymous(_) => {}, Fragment::Anonymous(_) => {},
Fragment::Text(t) => {
builder.is_contentful = true;
let rect = t
.rect
.to_physical(t.parent_style.writing_mode, containing_block)
.translate(containing_block.origin.to_vector());
let mut baseline_origin = rect.origin.clone();
baseline_origin.y += t.ascent;
let glyphs = glyphs(&t.glyphs, baseline_origin);
if glyphs.is_empty() {
return;
}
let mut common = builder.common_properties(rect.clone().to_webrender());
common.hit_info = hit_info(&t.parent_style, t.tag, Cursor::Text);
let color = t.parent_style.clone_color();
builder.wr.push_text(
&common,
rect.to_webrender(),
&glyphs,
t.font_key,
rgba(color),
None,
);
},
Fragment::Image(i) => { Fragment::Image(i) => {
builder.is_contentful = true; builder.is_contentful = true;
let rect = i let rect = i
@ -120,8 +97,111 @@ impl Fragment {
wr::ColorF::WHITE, wr::ColorF::WHITE,
); );
}, },
Fragment::Text(t) => {
self.build_display_list_for_text_fragment(t, builder, containing_block)
},
} }
} }
fn build_display_list_for_text_fragment(
&self,
fragment: &TextFragment,
builder: &mut DisplayListBuilder,
containing_block: &PhysicalRect<Length>,
) {
// NB: The order of painting text components (CSS Text Decoration Module Level 3) is:
// shadows, underline, overline, text, text-emphasis, and then line-through.
builder.is_contentful = true;
let rect = fragment
.rect
.to_physical(fragment.parent_style.writing_mode, containing_block)
.translate(containing_block.origin.to_vector());
let mut baseline_origin = rect.origin.clone();
baseline_origin.y += fragment.font_metrics.ascent;
let glyphs = glyphs(&fragment.glyphs, baseline_origin);
if glyphs.is_empty() {
return;
}
let mut common = builder.common_properties(rect.to_webrender());
common.hit_info = hit_info(&fragment.parent_style, fragment.tag, Cursor::Text);
let color = fragment.parent_style.clone_color();
let font_metrics = &fragment.font_metrics;
// Underline.
if fragment
.text_decoration_line
.contains(TextDecorationLine::UNDERLINE)
{
let mut rect = rect;
rect.origin.y = rect.origin.y + font_metrics.ascent - font_metrics.underline_offset;
rect.size.height = font_metrics.underline_size;
self.build_display_list_for_text_decoration(fragment, builder, &rect, color);
}
// Overline.
if fragment
.text_decoration_line
.contains(TextDecorationLine::OVERLINE)
{
let mut rect = rect;
rect.size.height = font_metrics.underline_size;
self.build_display_list_for_text_decoration(fragment, builder, &rect, color);
}
// Text.
builder.wr.push_text(
&common,
rect.to_webrender(),
&glyphs,
fragment.font_key,
rgba(color),
None,
);
// Line-through.
if fragment
.text_decoration_line
.contains(TextDecorationLine::LINE_THROUGH)
{
let mut rect = rect;
rect.origin.y = rect.origin.y + font_metrics.ascent - font_metrics.strikeout_offset;
// XXX(ferjm) This does not work on MacOS #942
rect.size.height = font_metrics.strikeout_size;
self.build_display_list_for_text_decoration(fragment, builder, &rect, color);
}
}
fn build_display_list_for_text_decoration(
&self,
fragment: &TextFragment,
builder: &mut DisplayListBuilder,
rect: &PhysicalRect<Length>,
color: cssparser::RGBA,
) {
let rect = rect.to_webrender();
let wavy_line_thickness = (0.33 * rect.size.height).ceil();
let text_decoration_color = fragment
.parent_style
.clone_text_decoration_color()
.to_rgba(color);
let text_decoration_style = fragment.parent_style.clone_text_decoration_style();
if text_decoration_style == ComputedTextDecorationStyle::MozNone {
return;
}
builder.wr.push_line(
&builder.common_properties(rect),
&rect,
wavy_line_thickness,
wr::LineOrientation::Horizontal,
&rgba(text_decoration_color),
text_decoration_style.to_webrender(),
);
// XXX(ferjm) support text-decoration-style: double
}
} }
struct BuilderForBoxFragment<'a> { struct BuilderForBoxFragment<'a> {

View file

@ -19,6 +19,7 @@ use servo_arc::Arc;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::selector_parser::PseudoElement; use style::selector_parser::PseudoElement;
use style::values::specified::text::TextDecorationLine;
impl BlockFormattingContext { impl BlockFormattingContext {
pub fn construct<'dom>( pub fn construct<'dom>(
@ -27,9 +28,16 @@ impl BlockFormattingContext {
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
contents: NonReplacedContents, contents: NonReplacedContents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine,
) -> (Self, BoxContentSizes) { ) -> (Self, BoxContentSizes) {
let (contents, contains_floats, inline_content_sizes) = let (contents, contains_floats, inline_content_sizes) = BlockContainer::construct(
BlockContainer::construct(context, node, style, contents, content_sizes); context,
node,
style,
contents,
content_sizes,
propagated_text_decoration_line,
);
// FIXME: add contribution to `inline_content_sizes` of floats in this formatting context // FIXME: add contribution to `inline_content_sizes` of floats in this formatting context
// https://dbaron.org/css/intrinsic/#intrinsic // https://dbaron.org/css/intrinsic/#intrinsic
let bfc = Self { let bfc = Self {
@ -52,6 +60,7 @@ enum BlockLevelCreator {
Independent { Independent {
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
propagated_text_decoration_line: TextDecorationLine,
}, },
OutOfFlowAbsolutelyPositionedBox { OutOfFlowAbsolutelyPositionedBox {
display_inside: DisplayInside, display_inside: DisplayInside,
@ -72,7 +81,7 @@ enum BlockLevelCreator {
/// Deferring allows using rayons `into_par_iter`. /// Deferring allows using rayons `into_par_iter`.
enum IntermediateBlockContainer { enum IntermediateBlockContainer {
InlineFormattingContext(InlineFormattingContext), InlineFormattingContext(InlineFormattingContext),
Deferred(NonReplacedContents), Deferred(NonReplacedContents, TextDecorationLine),
} }
/// A builder for a block container. /// A builder for a block container.
@ -140,13 +149,16 @@ impl BlockContainer {
block_container_style: &Arc<ComputedValues>, block_container_style: &Arc<ComputedValues>,
contents: NonReplacedContents, contents: NonReplacedContents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) { ) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
let text_decoration_line =
propagated_text_decoration_line | block_container_style.clone_text_decoration_line();
let mut builder = BlockContainerBuilder { let mut builder = BlockContainerBuilder {
context, context,
root, root,
block_container_style, block_container_style,
block_level_boxes: Vec::new(), block_level_boxes: Vec::new(),
ongoing_inline_formatting_context: InlineFormattingContext::default(), ongoing_inline_formatting_context: InlineFormattingContext::new(text_decoration_line),
ongoing_inline_boxes_stack: Vec::new(), ongoing_inline_boxes_stack: Vec::new(),
anonymous_style: None, anonymous_style: None,
contains_floats: ContainsFloats::No, contains_floats: ContainsFloats::No,
@ -439,6 +451,8 @@ where
display_inside, display_inside,
contents, contents,
ContentSizesRequest::inline_if(!style.inline_size_is_length()), ContentSizesRequest::inline_if(!style.inline_size_is_length()),
// Text decorations are not propagated to atomic inline-level descendants.
TextDecorationLine::NONE,
), ),
)) ))
}; };
@ -494,6 +508,9 @@ where
.push(ArcRefCell::new(fragmented_inline)); .push(ArcRefCell::new(fragmented_inline));
} }
let propagated_text_decoration_line =
self.ongoing_inline_formatting_context.text_decoration_line;
// We found a block level element, so the ongoing inline formatting // We found a block level element, so the ongoing inline formatting
// context needs to be ended. // context needs to be ended.
self.end_ongoing_inline_formatting_context(); self.end_ongoing_inline_formatting_context();
@ -501,11 +518,12 @@ where
let kind = match contents.try_into() { let kind = match contents.try_into() {
Ok(contents) => match display_inside { Ok(contents) => match display_inside {
DisplayInside::Flow => BlockLevelCreator::SameFormattingContextBlock( DisplayInside::Flow => BlockLevelCreator::SameFormattingContextBlock(
IntermediateBlockContainer::Deferred(contents), IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line),
), ),
_ => BlockLevelCreator::Independent { _ => BlockLevelCreator::Independent {
display_inside, display_inside,
contents: contents.into(), contents: contents.into(),
propagated_text_decoration_line,
}, },
}, },
Err(contents) => { Err(contents) => {
@ -513,6 +531,7 @@ where
BlockLevelCreator::Independent { BlockLevelCreator::Independent {
display_inside, display_inside,
contents, contents,
propagated_text_decoration_line,
} }
}, },
}; };
@ -680,6 +699,7 @@ where
BlockLevelCreator::Independent { BlockLevelCreator::Independent {
display_inside, display_inside,
contents, contents,
propagated_text_decoration_line,
} => { } => {
let content_sizes = ContentSizesRequest::inline_if( let content_sizes = ContentSizesRequest::inline_if(
max_assign_in_flow_outer_content_sizes_to.is_some() && max_assign_in_flow_outer_content_sizes_to.is_some() &&
@ -692,6 +712,7 @@ where
display_inside, display_inside,
contents, contents,
content_sizes, content_sizes,
propagated_text_decoration_line,
); );
if let Some(to) = max_assign_in_flow_outer_content_sizes_to { if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&contents.content_sizes.outer_inline(&contents.style)) to.max_assign(&contents.content_sizes.outer_inline(&contents.style))
@ -742,8 +763,15 @@ impl IntermediateBlockContainer {
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) { ) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
match self { match self {
IntermediateBlockContainer::Deferred(contents) => { IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line) => {
BlockContainer::construct(context, node, style, contents, content_sizes) BlockContainer::construct(
context,
node,
style,
contents,
content_sizes,
propagated_text_decoration_line,
)
}, },
IntermediateBlockContainer::InlineFormattingContext(ifc) => { IntermediateBlockContainer::InlineFormattingContext(ifc) => {
let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context)); let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context));

View file

@ -9,6 +9,7 @@ use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, DisplayInside}; use crate::style_ext::{ComputedValuesExt, DisplayInside};
use servo_arc::Arc; use servo_arc::Arc;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::specified::text::TextDecorationLine;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub(crate) struct FloatBox { pub(crate) struct FloatBox {
@ -43,6 +44,8 @@ impl FloatBox {
display_inside, display_inside,
contents, contents,
content_sizes, content_sizes,
// Text decorations are not propagated to any out-of-flow descendants
TextDecorationLine::NONE,
), ),
} }
} }

View file

@ -9,7 +9,7 @@ use crate::flow::FlowLayout;
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{ use crate::fragments::{
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins, AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
DebugId, Fragment, TextFragment, DebugId, FontMetrics, Fragment, TextFragment,
}; };
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{ use crate::positioned::{
@ -26,12 +26,14 @@ use style::dom::OpaqueNode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, Percentage}; use style::values::computed::{Length, LengthPercentage, Percentage};
use style::values::specified::text::TextAlignKeyword; use style::values::specified::text::TextAlignKeyword;
use style::values::specified::text::TextDecorationLine;
use style::Zero; use style::Zero;
use webrender_api::FontInstanceKey; use webrender_api::FontInstanceKey;
#[derive(Debug, Default, Serialize)] #[derive(Debug, Default, Serialize)]
pub(crate) struct InlineFormattingContext { pub(crate) struct InlineFormattingContext {
pub(super) inline_level_boxes: Vec<ArcRefCell<InlineLevelBox>>, pub(super) inline_level_boxes: Vec<ArcRefCell<InlineLevelBox>>,
pub(super) text_decoration_line: TextDecorationLine,
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@ -68,6 +70,11 @@ struct InlineNestingLevelState<'box_tree> {
inline_start: Length, inline_start: Length,
max_block_size_of_fragments_so_far: Length, max_block_size_of_fragments_so_far: Length,
positioning_context: Option<PositioningContext>, positioning_context: Option<PositioningContext>,
/// Indicates whether this nesting level have text decorations in effect.
/// From https://drafts.csswg.org/css-text-decor/#line-decoration
// "When specified on or propagated to a block container that establishes
// an IFC..."
text_decoration_line: TextDecorationLine,
} }
struct PartialInlineBoxFragment<'box_tree> { struct PartialInlineBoxFragment<'box_tree> {
@ -122,6 +129,13 @@ struct Lines {
} }
impl InlineFormattingContext { impl InlineFormattingContext {
pub(super) fn new(text_decoration_line: TextDecorationLine) -> InlineFormattingContext {
InlineFormattingContext {
inline_level_boxes: Default::default(),
text_decoration_line,
}
}
// This works on an already-constructed `InlineFormattingContext`, // This works on an already-constructed `InlineFormattingContext`,
// Which would have to change if/when // Which would have to change if/when
// `BlockContainer::construct` parallelize their construction. // `BlockContainer::construct` parallelize their construction.
@ -256,8 +270,10 @@ impl InlineFormattingContext {
inline_start: Length::zero(), inline_start: Length::zero(),
max_block_size_of_fragments_so_far: Length::zero(), max_block_size_of_fragments_so_far: Length::zero(),
positioning_context: None, positioning_context: None,
text_decoration_line: self.text_decoration_line,
}, },
}; };
loop { loop {
if let Some(child) = ifc.current_nesting_level.remaining_boxes.next() { if let Some(child) = ifc.current_nesting_level.remaining_boxes.next() {
match &*child.borrow() { match &*child.borrow() {
@ -385,6 +401,7 @@ impl Lines {
block: line_block_size, block: line_block_size,
}; };
self.next_line_block_position += size.block; self.next_line_block_position += size.block;
self.fragments self.fragments
.push(Fragment::Anonymous(AnonymousFragment::new( .push(Fragment::Anonymous(AnonymousFragment::new(
Rect { start_corner, size }, Rect { start_corner, size },
@ -423,6 +440,8 @@ impl InlineBox {
start_corner += &relative_adjustement(&style, ifc.containing_block) start_corner += &relative_adjustement(&style, ifc.containing_block)
} }
let positioning_context = PositioningContext::new_for_style(&style); let positioning_context = PositioningContext::new_for_style(&style);
let text_decoration_line =
ifc.current_nesting_level.text_decoration_line | style.clone_text_decoration_line();
PartialInlineBoxFragment { PartialInlineBoxFragment {
tag: self.tag, tag: self.tag,
style, style,
@ -441,6 +460,7 @@ impl InlineBox {
inline_start: ifc.inline_position, inline_start: ifc.inline_position,
max_block_size_of_fragments_so_far: Length::zero(), max_block_size_of_fragments_so_far: Length::zero(),
positioning_context, positioning_context,
text_decoration_line: text_decoration_line,
}, },
), ),
} }
@ -631,8 +651,7 @@ fn layout_atomic(
} }
struct BreakAndShapeResult { struct BreakAndShapeResult {
font_ascent: Au, font_metrics: FontMetrics,
font_line_gap: Au,
font_key: FontInstanceKey, font_key: FontInstanceKey,
runs: Vec<GlyphRun>, runs: Vec<GlyphRun>,
break_at_start: bool, break_at_start: bool,
@ -699,8 +718,7 @@ impl TextRun {
); );
BreakAndShapeResult { BreakAndShapeResult {
font_ascent: font.metrics.ascent, font_metrics: (&font.metrics).into(),
font_line_gap: font.metrics.line_gap,
font_key: font.font_key, font_key: font.font_key,
runs, runs,
break_at_start, break_at_start,
@ -712,8 +730,7 @@ impl TextRun {
use style::values::generics::text::LineHeight; use style::values::generics::text::LineHeight;
let BreakAndShapeResult { let BreakAndShapeResult {
font_ascent, font_metrics,
font_line_gap,
font_key, font_key,
runs, runs,
break_at_start: _, break_at_start: _,
@ -750,7 +767,7 @@ impl TextRun {
} }
} }
let line_height = match self.parent_style.get_inherited_text().line_height { let line_height = match self.parent_style.get_inherited_text().line_height {
LineHeight::Normal => font_line_gap.into(), LineHeight::Normal => font_metrics.line_gap,
LineHeight::Number(n) => font_size * n.0, LineHeight::Number(n) => font_size * n.0,
LineHeight::Length(l) => l.0, LineHeight::Length(l) => l.0,
}; };
@ -775,9 +792,10 @@ impl TextRun {
debug_id: DebugId::new(), debug_id: DebugId::new(),
parent_style: self.parent_style.clone(), parent_style: self.parent_style.clone(),
rect, rect,
ascent: font_ascent.into(), font_metrics,
font_key, font_key,
glyphs, glyphs,
text_decoration_line: ifc.current_nesting_level.text_decoration_line,
})); }));
if runs.is_empty() { if runs.is_empty() {
break; break;

View file

@ -104,6 +104,7 @@ fn construct_for_root_element<'dom>(
))], ))],
) )
} else { } else {
let propagated_text_decoration_line = style.clone_text_decoration_line();
( (
ContainsFloats::No, ContainsFloats::No,
vec![ArcRefCell::new(BlockLevelBox::Independent( vec![ArcRefCell::new(BlockLevelBox::Independent(
@ -114,6 +115,7 @@ fn construct_for_root_element<'dom>(
display_inside, display_inside,
contents, contents,
ContentSizesRequest::None, ContentSizesRequest::None,
propagated_text_decoration_line,
), ),
))], ))],
) )

View file

@ -16,6 +16,7 @@ use std::convert::TryInto;
use style::dom::OpaqueNode; use style::dom::OpaqueNode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::Length; use style::values::computed::Length;
use style::values::specified::text::TextDecorationLine;
/// https://drafts.csswg.org/css-display/#independent-formatting-context /// https://drafts.csswg.org/css-display/#independent-formatting-context
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@ -62,6 +63,7 @@ impl IndependentFormattingContext {
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine,
) -> Self { ) -> Self {
match contents.try_into() { match contents.try_into() {
Ok(non_replaced) => match display_inside { Ok(non_replaced) => match display_inside {
@ -72,6 +74,7 @@ impl IndependentFormattingContext {
&style, &style,
non_replaced, non_replaced,
content_sizes, content_sizes,
propagated_text_decoration_line,
); );
Self { Self {
tag: node.as_opaque(), tag: node.as_opaque(),

View file

@ -7,6 +7,7 @@ use crate::geom::{PhysicalPoint, PhysicalRect};
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use crate::layout_debug; use crate::layout_debug;
use crate::positioned::HoistedFragmentId; use crate::positioned::HoistedFragmentId;
use gfx::font::FontMetrics as GfxFontMetrics;
use gfx::text::glyph::GlyphStore; use gfx::text::glyph::GlyphStore;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
@ -18,6 +19,7 @@ use style::dom::OpaqueNode;
use style::logical_geometry::WritingMode; use style::logical_geometry::WritingMode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::Length; use style::values::computed::Length;
use style::values::specified::text::TextDecorationLine;
use style::Zero; use style::Zero;
use webrender_api::{FontInstanceKey, ImageKey}; use webrender_api::{FontInstanceKey, ImageKey};
@ -86,6 +88,29 @@ pub(crate) struct AnonymousFragment {
pub scrollable_overflow: PhysicalRect<Length>, pub scrollable_overflow: PhysicalRect<Length>,
} }
#[derive(Clone, Copy, Serialize)]
pub(crate) struct FontMetrics {
pub ascent: Length,
pub line_gap: Length,
pub underline_offset: Length,
pub underline_size: Length,
pub strikeout_offset: Length,
pub strikeout_size: Length,
}
impl From<&GfxFontMetrics> for FontMetrics {
fn from(metrics: &GfxFontMetrics) -> FontMetrics {
FontMetrics {
ascent: metrics.ascent.into(),
line_gap: metrics.line_gap.into(),
underline_offset: metrics.underline_offset.into(),
underline_size: metrics.underline_size.into(),
strikeout_offset: metrics.strikeout_offset.into(),
strikeout_size: metrics.strikeout_size.into(),
}
}
}
#[derive(Serialize)] #[derive(Serialize)]
pub(crate) struct TextFragment { pub(crate) struct TextFragment {
pub debug_id: DebugId, pub debug_id: DebugId,
@ -93,10 +118,12 @@ pub(crate) struct TextFragment {
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub parent_style: ServoArc<ComputedValues>, pub parent_style: ServoArc<ComputedValues>,
pub rect: Rect<Length>, pub rect: Rect<Length>,
pub ascent: Length, pub font_metrics: FontMetrics,
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub font_key: FontInstanceKey, pub font_key: FontInstanceKey,
pub glyphs: Vec<Arc<GlyphStore>>, pub glyphs: Vec<Arc<GlyphStore>>,
/// A flag that represents the _used_ value of the text-decoration property.
pub text_decoration_line: TextDecorationLine,
} }
#[derive(Serialize)] #[derive(Serialize)]

View file

@ -17,6 +17,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use style::computed_values::position::T as Position; use style::computed_values::position::T as Position;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
use style::values::specified::text::TextDecorationLine;
use style::Zero; use style::Zero;
static HOISTED_FRAGMENT_ID_COUNTER: AtomicUsize = AtomicUsize::new(0); static HOISTED_FRAGMENT_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
@ -104,6 +105,8 @@ impl AbsolutelyPositionedBox {
display_inside, display_inside,
contents, contents,
content_sizes, content_sizes,
// Text decorations are not propagated to any out-of-flow descendants.
TextDecorationLine::NONE,
), ),
} }
} }

View file

@ -32,7 +32,6 @@ ${helpers.predefined_type(
"TextDecorationLine", "TextDecorationLine",
"specified::TextDecorationLine::none()", "specified::TextDecorationLine::none()",
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_specified_value="specified::TextDecorationLine::none()", initial_specified_value="specified::TextDecorationLine::none()",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line", spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line",
@ -42,7 +41,7 @@ ${helpers.predefined_type(
${helpers.single_keyword( ${helpers.single_keyword(
"text-decoration-style", "text-decoration-style",
"solid double dotted dashed wavy -moz-none", "solid double dotted dashed wavy -moz-none",
engines="gecko", engines="gecko servo-2020",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style", spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style",
)} )}
@ -51,7 +50,7 @@ ${helpers.predefined_type(
"text-decoration-color", "text-decoration-color",
"Color", "Color",
"computed_value::T::currentcolor()", "computed_value::T::currentcolor()",
engines="gecko", engines="gecko servo-2020",
initial_specified_value="specified::Color::currentcolor()", initial_specified_value="specified::Color::currentcolor()",
animation_value_type="AnimatedColor", animation_value_type="AnimatedColor",
ignored_when_colors_disabled=True, ignored_when_colors_disabled=True,

View file

@ -5,7 +5,7 @@
<%namespace name="helpers" file="/helpers.mako.rs" /> <%namespace name="helpers" file="/helpers.mako.rs" />
<%helpers:shorthand name="text-decoration" <%helpers:shorthand name="text-decoration"
engines="gecko servo-2013" engines="gecko servo-2013 servo-2020"
flags="SHORTHAND_IN_GETCS" flags="SHORTHAND_IN_GETCS"
sub_properties="text-decoration-line sub_properties="text-decoration-line
${' text-decoration-style text-decoration-color text-decoration-thickness' if engine == 'gecko' else ''}" ${' text-decoration-style text-decoration-color text-decoration-thickness' if engine == 'gecko' else ''}"

View file

@ -217,7 +217,7 @@ impl ToComputedValue for TextOverflow {
} }
bitflags! { bitflags! {
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)] #[derive(MallocSizeOf, Serialize, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
#[value_info(other_values = "none,underline,overline,line-through,blink")] #[value_info(other_values = "none,underline,overline,line-through,blink")]
#[repr(C)] #[repr(C)]
/// Specified keyword values for the text-decoration-line property. /// Specified keyword values for the text-decoration-line property.
@ -244,6 +244,12 @@ bitflags! {
} }
} }
impl Default for TextDecorationLine {
fn default() -> Self {
TextDecorationLine::NONE
}
}
impl Parse for TextDecorationLine { impl Parse for TextDecorationLine {
/// none | [ underline || overline || line-through || blink ] /// none | [ underline || overline || line-through || blink ]
fn parse<'i, 't>( fn parse<'i, 't>(

View file

@ -15,6 +15,8 @@ skip: true
skip: false skip: false
[css-color] [css-color]
skip: false skip: false
[css-text-decor]
skip: false
[css-transforms] [css-transforms]
skip: false skip: false
[filter-effects] [filter-effects]

View file

@ -0,0 +1,2 @@
[content-070.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[content-082.xht]
expected: FAIL

View file

@ -0,0 +1,55 @@
[inheritance.html]
[Property text-emphasis-style inherits]
expected: FAIL
[Property text-emphasis-style has initial value none]
expected: FAIL
[Property text-decoration-style has initial value solid]
expected: FAIL
[Property text-underline-position has initial value auto]
expected: FAIL
[Property text-decoration-line has initial value none]
expected: FAIL
[Property text-emphasis-color has initial value rgba(2, 3, 4, 0.5)]
expected: FAIL
[Property text-shadow has initial value none]
expected: FAIL
[Property text-decoration-color has initial value rgba(2, 3, 4, 0.5)]
expected: FAIL
[Property text-decoration-skip-ink inherits]
expected: FAIL
[Property text-decoration-skip-ink has initial value auto]
expected: FAIL
[Property text-decoration-line does not inherit]
expected: FAIL
[Property text-underline-position inherits]
expected: FAIL
[Property text-emphasis-position inherits]
expected: FAIL
[Property text-decoration-color does not inherit]
expected: FAIL
[Property text-emphasis-position has initial value over right]
expected: FAIL
[Property text-decoration-style does not inherit]
expected: FAIL
[Property text-shadow inherits]
expected: FAIL
[Property text-emphasis-color inherits]
expected: FAIL

View file

@ -0,0 +1,10 @@
[text-decoration-color-computed.html]
[Property text-decoration-color value 'inherit']
expected: FAIL
[Property text-decoration-color value 'rgb(0, 0, 255)']
expected: FAIL
[Property text-decoration-color value 'currentcolor']
expected: FAIL

View file

@ -0,0 +1,37 @@
[text-decoration-computed.html]
[Property text-decoration value 'auto']
expected: FAIL
[Property text-decoration value 'currentcolor']
expected: FAIL
[Property text-decoration value 'double overline underline']
expected: FAIL
[Property text-decoration value 'line-through']
expected: FAIL
[Property text-decoration value 'underline dashed rgb(0, 255, 0)']
expected: FAIL
[Property text-decoration value 'underline overline line-through red']
expected: FAIL
[Property text-decoration value 'rgba(10, 20, 30, 0.4) dotted']
expected: FAIL
[Property text-decoration value 'none']
expected: FAIL
[Property text-decoration value '10px']
expected: FAIL
[Property text-decoration value 'underline red from-font']
expected: FAIL
[Property text-decoration value 'solid']
expected: FAIL
[Property text-decoration value 'from-font']
expected: FAIL

View file

@ -0,0 +1,55 @@
[text-decoration-line-computed.html]
[Property text-decoration-line value 'underline overline']
expected: FAIL
[Property text-decoration-line value 'overline blink']
expected: FAIL
[Property text-decoration-line value 'underline line-through blink']
expected: FAIL
[Property text-decoration-line value 'underline overline blink']
expected: FAIL
[Property text-decoration-line value 'blink']
expected: FAIL
[Property text-decoration-line value 'line-through blink']
expected: FAIL
[Property text-decoration-line value 'underline']
expected: FAIL
[Property text-decoration-line value 'underline line-through']
expected: FAIL
[Property text-decoration-line value 'overline line-through blink']
expected: FAIL
[Property text-decoration-line value 'line-through']
expected: FAIL
[Property text-decoration-line value 'underline blink']
expected: FAIL
[Property text-decoration-line value 'overline line-through']
expected: FAIL
[Property text-decoration-line value 'spelling-error']
expected: FAIL
[Property text-decoration-line value 'underline overline line-through']
expected: FAIL
[Property text-decoration-line value 'none']
expected: FAIL
[Property text-decoration-line value 'grammar-error']
expected: FAIL
[Property text-decoration-line value 'underline overline line-through blink']
expected: FAIL
[Property text-decoration-line value 'overline']
expected: FAIL

View file

@ -0,0 +1,7 @@
[text-decoration-line-valid.html]
[e.style['text-decoration-line'\] = "spelling-error" should set the property value]
expected: FAIL
[e.style['text-decoration-line'\] = "grammar-error" should set the property value]
expected: FAIL

View file

@ -0,0 +1,13 @@
[text-decoration-shorthand.html]
[e.style['text-decoration'\] = "overline dotted green" should set text-decoration-line]
expected: FAIL
[e.style['text-decoration'\] = "overline dotted green" should set text-decoration-style]
expected: FAIL
[e.style['text-decoration'\] = "overline dotted green" should set text-decoration-color]
expected: FAIL
[e.style['text-decoration'\] = "overline dotted green" should not set unrelated longhands]
expected: FAIL

View file

@ -0,0 +1,7 @@
[text-decoration-skip-ink-computed.html]
[Property text-decoration-skip-ink value 'none']
expected: FAIL
[Property text-decoration-skip-ink value 'auto']
expected: FAIL

View file

@ -0,0 +1,7 @@
[text-decoration-skip-ink-valid.html]
[e.style['text-decoration-skip-ink'\] = "none" should set the property value]
expected: FAIL
[e.style['text-decoration-skip-ink'\] = "auto" should set the property value]
expected: FAIL

View file

@ -0,0 +1,16 @@
[text-decoration-style-computed.html]
[Property text-decoration-style value 'wavy']
expected: FAIL
[Property text-decoration-style value 'dashed']
expected: FAIL
[Property text-decoration-style value 'dotted']
expected: FAIL
[Property text-decoration-style value 'double']
expected: FAIL
[Property text-decoration-style value 'solid']
expected: FAIL

View file

@ -0,0 +1,40 @@
[text-decoration-valid.html]
[e.style['text-decoration'\] = "underline auto" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "auto" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "underline dashed green" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "10px" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "double overline underline" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "rgba(10, 20, 30, 0.4) dotted" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "solid" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "line-through 20px" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "underline overline line-through red" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "overline 3em" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "currentcolor" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "from-font" should set the property value]
expected: FAIL
[e.style['text-decoration'\] = "overline green from-font" should set the property value]
expected: FAIL

View file

@ -0,0 +1,22 @@
[text-shadow-computed.html]
[Property text-shadow value 'calc(0.5em + 10px) calc(0.5em + 10px) calc(0.5em + 10px)']
expected: FAIL
[Property text-shadow value '10px 20px, 30px 40px']
expected: FAIL
[Property text-shadow value 'lime 10px 20px 30px, red 40px 50px']
expected: FAIL
[Property text-shadow value 'calc(-0.5em + 10px) calc(-0.5em + 10px) calc(-0.5em + 10px)']
expected: FAIL
[Property text-shadow value 'red 10px 20px 30px']
expected: FAIL
[Property text-shadow value 'none']
expected: FAIL
[Property text-shadow value '10px 20px']
expected: FAIL

View file

@ -0,0 +1,31 @@
[text-shadow-valid.html]
[e.style['text-shadow'\] = "rgb(255, 0, 0) 10px 20px" should set the property value]
expected: FAIL
[e.style['text-shadow'\] = "lime 10px 20px 30px, blue 40px 50px" should set the property value]
expected: FAIL
[e.style['text-shadow'\] = "10px 20px 30px" should set the property value]
expected: FAIL
[e.style['text-shadow'\] = "10px -20px 30px" should set the property value]
expected: FAIL
[e.style['text-shadow'\] = "-10px 20px 30px" should set the property value]
expected: FAIL
[e.style['text-shadow'\] = "10px 20px 30px lime" should set the property value]
expected: FAIL
[e.style['text-shadow'\] = "10px 20px" should set the property value]
expected: FAIL
[e.style['text-shadow'\] = "none" should set the property value]
expected: FAIL
[e.style['text-shadow'\] = "10px 20px, 30px 40px" should set the property value]
expected: FAIL
[e.style['text-shadow'\] = "calc(1em + 2px) calc(3em + 4px) calc(5em + 6px)" should set the property value]
expected: FAIL

View file

@ -0,0 +1,16 @@
[text-underline-position-computed.html]
[Property text-underline-position value 'under left']
expected: FAIL
[Property text-underline-position value 'left']
expected: FAIL
[Property text-underline-position value 'under']
expected: FAIL
[Property text-underline-position value 'right']
expected: FAIL
[Property text-underline-position value 'auto']
expected: FAIL

View file

@ -0,0 +1,19 @@
[text-underline-position-valid.html]
[e.style['text-underline-position'\] = "right under" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "under left" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "auto" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "left" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "right" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "under" should set the property value]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-color.html]
expected: FAIL

View file

@ -0,0 +1,4 @@
[text-decoration-serialization.tentative.html]
[text-decoration shorthand serialization]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-003.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-004.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-005.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-sidewayslr-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-sidewaysrl-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-upright-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-upright-002.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-vertical-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-skip-ink-vertical-002.html]
expected: FAIL

View file

@ -0,0 +1,7 @@
[text-decoration-skip-ink.html]
[Body must have text-decoration-skip-ink auto by default.]
expected: FAIL
[Property text-decoration-skip-ink must support values auto, none and all.]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-subelements-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-subelements-002.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-thickness-001.html]
expected: FAIL

View file

@ -0,0 +1,10 @@
[text-decoration-thickness-computed.html]
[Property text-decoration-thickness value 'auto']
expected: FAIL
[Property text-decoration-thickness value 'from-font']
expected: FAIL
[Property text-decoration-thickness value 'calc(10px - 8px)']
expected: FAIL

View file

@ -0,0 +1,4 @@
[text-decoration-thickness-initial.html]
[Initial value of text-decoration-thickness should be auto]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-thickness-linethrough-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-thickness-overline-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-thickness-scroll-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-thickness-underline-001.html]
expected: FAIL

View file

@ -0,0 +1,25 @@
[text-decoration-thickness-valid.html]
[e.style['text-decoration-thickness'\] = "from-font" should set the property value]
expected: FAIL
[e.style['text-decoration-thickness'\] = "2001em" should set the property value]
expected: FAIL
[e.style['text-decoration-thickness'\] = "-49em" should set the property value]
expected: FAIL
[e.style['text-decoration-thickness'\] = "auto" should set the property value]
expected: FAIL
[e.style['text-decoration-thickness'\] = "calc(-50em + 13px)" should set the property value]
expected: FAIL
[e.style['text-decoration-thickness'\] = "53px" should set the property value]
expected: FAIL
[e.style['text-decoration-thickness'\] = "calc(40em - 10px)" should set the property value]
expected: FAIL
[e.style['text-decoration-thickness'\] = "-10px" should set the property value]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-thickness-vertical-001.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-thickness-vertical-002.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-underline-position-vertical-ja.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-decoration-underline-position-vertical.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-color-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-position-above-left-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-position-above-left-002.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-position-above-right-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-position-above-right-002.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-position-below-left-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-position-below-left-002.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-position-below-right-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-position-below-right-002.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-002.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-006.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-007.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-008.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-010.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-012.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-021.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-filled-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-open-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-shape-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-emphasis-style-string-001.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-underline-offset-001.html]
expected: FAIL

View file

@ -0,0 +1,7 @@
[text-underline-offset-computed.html]
[Property text-underline-offset value 'auto']
expected: FAIL
[Property text-underline-offset value 'calc(10px - 8px)']
expected: FAIL

View file

@ -0,0 +1,4 @@
[text-underline-offset-initial.html]
[Initial value of text-underline-offset]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-underline-offset-scroll-001.html]
expected: FAIL

View file

@ -0,0 +1,22 @@
[text-underline-offset-valid.html]
[e.style['text-underline-offset'\] = "53px" should set the property value]
expected: FAIL
[e.style['text-underline-offset'\] = "calc(-13em + 50px)" should set the property value]
expected: FAIL
[e.style['text-underline-offset'\] = "2001em" should set the property value]
expected: FAIL
[e.style['text-underline-offset'\] = "auto" should set the property value]
expected: FAIL
[e.style['text-underline-offset'\] = "-10px" should set the property value]
expected: FAIL
[e.style['text-underline-offset'\] = "calc(40em - 10px)" should set the property value]
expected: FAIL
[e.style['text-underline-offset'\] = "-49em" should set the property value]
expected: FAIL

View file

@ -1,2 +0,0 @@
[text_decoration_smoke_a.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[text_decoration_underline_subpx_a.html]
expected: FAIL

View file

@ -2,4 +2,3 @@
bug: https://github.com/servo/servo/issues/25802 bug: https://github.com/servo/servo/issues/25802
[localeCompare should return the same as other browsers, even though it's implementation-dependent] [localeCompare should return the same as other browsers, even though it's implementation-dependent]
expected: FAIL expected: FAIL