mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
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:
commit
acd14672e1
84 changed files with 743 additions and 53 deletions
|
@ -4,6 +4,7 @@
|
|||
|
||||
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize};
|
||||
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::values::computed::Filter as ComputedFilter;
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::display_list::conversions::ToWebRender;
|
||||
use crate::fragments::{BoxFragment, Fragment};
|
||||
use crate::fragments::{BoxFragment, Fragment, TextFragment};
|
||||
use crate::geom::{PhysicalPoint, PhysicalRect};
|
||||
use crate::replaced::IntrinsicSizes;
|
||||
use embedder_traits::Cursor;
|
||||
|
@ -13,10 +13,11 @@ use gfx::text::glyph::GlyphStore;
|
|||
use mitochondria::OnceCell;
|
||||
use net_traits::image_cache::UsePlaceholder;
|
||||
use std::sync::Arc;
|
||||
use style::computed_values::text_decoration_style::T as ComputedTextDecorationStyle;
|
||||
use style::dom::OpaqueNode;
|
||||
use style::properties::ComputedValues;
|
||||
|
||||
use style::values::computed::{BorderStyle, Length, LengthPercentage};
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
use style::values::specified::ui::CursorKind;
|
||||
use webrender_api::{self as wr, units};
|
||||
|
||||
|
@ -80,30 +81,6 @@ impl Fragment {
|
|||
Fragment::Box(b) => BuilderForBoxFragment::new(b, containing_block).build(builder),
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => {},
|
||||
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) => {
|
||||
builder.is_contentful = true;
|
||||
let rect = i
|
||||
|
@ -120,8 +97,111 @@ impl Fragment {
|
|||
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> {
|
||||
|
|
|
@ -19,6 +19,7 @@ use servo_arc::Arc;
|
|||
use std::convert::{TryFrom, TryInto};
|
||||
use style::properties::ComputedValues;
|
||||
use style::selector_parser::PseudoElement;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
|
||||
impl BlockFormattingContext {
|
||||
pub fn construct<'dom>(
|
||||
|
@ -27,9 +28,16 @@ impl BlockFormattingContext {
|
|||
style: &Arc<ComputedValues>,
|
||||
contents: NonReplacedContents,
|
||||
content_sizes: ContentSizesRequest,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
) -> (Self, BoxContentSizes) {
|
||||
let (contents, contains_floats, inline_content_sizes) =
|
||||
BlockContainer::construct(context, node, style, contents, content_sizes);
|
||||
let (contents, contains_floats, inline_content_sizes) = BlockContainer::construct(
|
||||
context,
|
||||
node,
|
||||
style,
|
||||
contents,
|
||||
content_sizes,
|
||||
propagated_text_decoration_line,
|
||||
);
|
||||
// FIXME: add contribution to `inline_content_sizes` of floats in this formatting context
|
||||
// https://dbaron.org/css/intrinsic/#intrinsic
|
||||
let bfc = Self {
|
||||
|
@ -52,6 +60,7 @@ enum BlockLevelCreator {
|
|||
Independent {
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
},
|
||||
OutOfFlowAbsolutelyPositionedBox {
|
||||
display_inside: DisplayInside,
|
||||
|
@ -72,7 +81,7 @@ enum BlockLevelCreator {
|
|||
/// Deferring allows using rayon’s `into_par_iter`.
|
||||
enum IntermediateBlockContainer {
|
||||
InlineFormattingContext(InlineFormattingContext),
|
||||
Deferred(NonReplacedContents),
|
||||
Deferred(NonReplacedContents, TextDecorationLine),
|
||||
}
|
||||
|
||||
/// A builder for a block container.
|
||||
|
@ -140,13 +149,16 @@ impl BlockContainer {
|
|||
block_container_style: &Arc<ComputedValues>,
|
||||
contents: NonReplacedContents,
|
||||
content_sizes: ContentSizesRequest,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
|
||||
let text_decoration_line =
|
||||
propagated_text_decoration_line | block_container_style.clone_text_decoration_line();
|
||||
let mut builder = BlockContainerBuilder {
|
||||
context,
|
||||
root,
|
||||
block_container_style,
|
||||
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(),
|
||||
anonymous_style: None,
|
||||
contains_floats: ContainsFloats::No,
|
||||
|
@ -439,6 +451,8 @@ where
|
|||
display_inside,
|
||||
contents,
|
||||
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));
|
||||
}
|
||||
|
||||
let propagated_text_decoration_line =
|
||||
self.ongoing_inline_formatting_context.text_decoration_line;
|
||||
|
||||
// We found a block level element, so the ongoing inline formatting
|
||||
// context needs to be ended.
|
||||
self.end_ongoing_inline_formatting_context();
|
||||
|
@ -501,11 +518,12 @@ where
|
|||
let kind = match contents.try_into() {
|
||||
Ok(contents) => match display_inside {
|
||||
DisplayInside::Flow => BlockLevelCreator::SameFormattingContextBlock(
|
||||
IntermediateBlockContainer::Deferred(contents),
|
||||
IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line),
|
||||
),
|
||||
_ => BlockLevelCreator::Independent {
|
||||
display_inside,
|
||||
contents: contents.into(),
|
||||
propagated_text_decoration_line,
|
||||
},
|
||||
},
|
||||
Err(contents) => {
|
||||
|
@ -513,6 +531,7 @@ where
|
|||
BlockLevelCreator::Independent {
|
||||
display_inside,
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -680,6 +699,7 @@ where
|
|||
BlockLevelCreator::Independent {
|
||||
display_inside,
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
} => {
|
||||
let content_sizes = ContentSizesRequest::inline_if(
|
||||
max_assign_in_flow_outer_content_sizes_to.is_some() &&
|
||||
|
@ -692,6 +712,7 @@ where
|
|||
display_inside,
|
||||
contents,
|
||||
content_sizes,
|
||||
propagated_text_decoration_line,
|
||||
);
|
||||
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
|
||||
to.max_assign(&contents.content_sizes.outer_inline(&contents.style))
|
||||
|
@ -742,8 +763,15 @@ impl IntermediateBlockContainer {
|
|||
content_sizes: ContentSizesRequest,
|
||||
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
|
||||
match self {
|
||||
IntermediateBlockContainer::Deferred(contents) => {
|
||||
BlockContainer::construct(context, node, style, contents, content_sizes)
|
||||
IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line) => {
|
||||
BlockContainer::construct(
|
||||
context,
|
||||
node,
|
||||
style,
|
||||
contents,
|
||||
content_sizes,
|
||||
propagated_text_decoration_line,
|
||||
)
|
||||
},
|
||||
IntermediateBlockContainer::InlineFormattingContext(ifc) => {
|
||||
let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context));
|
||||
|
|
|
@ -9,6 +9,7 @@ use crate::sizing::ContentSizesRequest;
|
|||
use crate::style_ext::{ComputedValuesExt, DisplayInside};
|
||||
use servo_arc::Arc;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(crate) struct FloatBox {
|
||||
|
@ -43,6 +44,8 @@ impl FloatBox {
|
|||
display_inside,
|
||||
contents,
|
||||
content_sizes,
|
||||
// Text decorations are not propagated to any out-of-flow descendants
|
||||
TextDecorationLine::NONE,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::flow::FlowLayout;
|
|||
use crate::formatting_contexts::IndependentFormattingContext;
|
||||
use crate::fragments::{
|
||||
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
|
||||
DebugId, Fragment, TextFragment,
|
||||
DebugId, FontMetrics, Fragment, TextFragment,
|
||||
};
|
||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||
use crate::positioned::{
|
||||
|
@ -26,12 +26,14 @@ use style::dom::OpaqueNode;
|
|||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{Length, LengthPercentage, Percentage};
|
||||
use style::values::specified::text::TextAlignKeyword;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
use style::Zero;
|
||||
use webrender_api::FontInstanceKey;
|
||||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
pub(crate) struct InlineFormattingContext {
|
||||
pub(super) inline_level_boxes: Vec<ArcRefCell<InlineLevelBox>>,
|
||||
pub(super) text_decoration_line: TextDecorationLine,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
|
@ -68,6 +70,11 @@ struct InlineNestingLevelState<'box_tree> {
|
|||
inline_start: Length,
|
||||
max_block_size_of_fragments_so_far: Length,
|
||||
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> {
|
||||
|
@ -122,6 +129,13 @@ struct Lines {
|
|||
}
|
||||
|
||||
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`,
|
||||
// Which would have to change if/when
|
||||
// `BlockContainer::construct` parallelize their construction.
|
||||
|
@ -256,8 +270,10 @@ impl InlineFormattingContext {
|
|||
inline_start: Length::zero(),
|
||||
max_block_size_of_fragments_so_far: Length::zero(),
|
||||
positioning_context: None,
|
||||
text_decoration_line: self.text_decoration_line,
|
||||
},
|
||||
};
|
||||
|
||||
loop {
|
||||
if let Some(child) = ifc.current_nesting_level.remaining_boxes.next() {
|
||||
match &*child.borrow() {
|
||||
|
@ -385,6 +401,7 @@ impl Lines {
|
|||
block: line_block_size,
|
||||
};
|
||||
self.next_line_block_position += size.block;
|
||||
|
||||
self.fragments
|
||||
.push(Fragment::Anonymous(AnonymousFragment::new(
|
||||
Rect { start_corner, size },
|
||||
|
@ -423,6 +440,8 @@ impl InlineBox {
|
|||
start_corner += &relative_adjustement(&style, ifc.containing_block)
|
||||
}
|
||||
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 {
|
||||
tag: self.tag,
|
||||
style,
|
||||
|
@ -441,6 +460,7 @@ impl InlineBox {
|
|||
inline_start: ifc.inline_position,
|
||||
max_block_size_of_fragments_so_far: Length::zero(),
|
||||
positioning_context,
|
||||
text_decoration_line: text_decoration_line,
|
||||
},
|
||||
),
|
||||
}
|
||||
|
@ -631,8 +651,7 @@ fn layout_atomic(
|
|||
}
|
||||
|
||||
struct BreakAndShapeResult {
|
||||
font_ascent: Au,
|
||||
font_line_gap: Au,
|
||||
font_metrics: FontMetrics,
|
||||
font_key: FontInstanceKey,
|
||||
runs: Vec<GlyphRun>,
|
||||
break_at_start: bool,
|
||||
|
@ -699,8 +718,7 @@ impl TextRun {
|
|||
);
|
||||
|
||||
BreakAndShapeResult {
|
||||
font_ascent: font.metrics.ascent,
|
||||
font_line_gap: font.metrics.line_gap,
|
||||
font_metrics: (&font.metrics).into(),
|
||||
font_key: font.font_key,
|
||||
runs,
|
||||
break_at_start,
|
||||
|
@ -712,8 +730,7 @@ impl TextRun {
|
|||
use style::values::generics::text::LineHeight;
|
||||
|
||||
let BreakAndShapeResult {
|
||||
font_ascent,
|
||||
font_line_gap,
|
||||
font_metrics,
|
||||
font_key,
|
||||
runs,
|
||||
break_at_start: _,
|
||||
|
@ -750,7 +767,7 @@ impl TextRun {
|
|||
}
|
||||
}
|
||||
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::Length(l) => l.0,
|
||||
};
|
||||
|
@ -775,9 +792,10 @@ impl TextRun {
|
|||
debug_id: DebugId::new(),
|
||||
parent_style: self.parent_style.clone(),
|
||||
rect,
|
||||
ascent: font_ascent.into(),
|
||||
font_metrics,
|
||||
font_key,
|
||||
glyphs,
|
||||
text_decoration_line: ifc.current_nesting_level.text_decoration_line,
|
||||
}));
|
||||
if runs.is_empty() {
|
||||
break;
|
||||
|
|
|
@ -104,6 +104,7 @@ fn construct_for_root_element<'dom>(
|
|||
))],
|
||||
)
|
||||
} else {
|
||||
let propagated_text_decoration_line = style.clone_text_decoration_line();
|
||||
(
|
||||
ContainsFloats::No,
|
||||
vec![ArcRefCell::new(BlockLevelBox::Independent(
|
||||
|
@ -114,6 +115,7 @@ fn construct_for_root_element<'dom>(
|
|||
display_inside,
|
||||
contents,
|
||||
ContentSizesRequest::None,
|
||||
propagated_text_decoration_line,
|
||||
),
|
||||
))],
|
||||
)
|
||||
|
|
|
@ -16,6 +16,7 @@ use std::convert::TryInto;
|
|||
use style::dom::OpaqueNode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::Length;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
|
||||
/// https://drafts.csswg.org/css-display/#independent-formatting-context
|
||||
#[derive(Debug, Serialize)]
|
||||
|
@ -62,6 +63,7 @@ impl IndependentFormattingContext {
|
|||
display_inside: DisplayInside,
|
||||
contents: Contents,
|
||||
content_sizes: ContentSizesRequest,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
) -> Self {
|
||||
match contents.try_into() {
|
||||
Ok(non_replaced) => match display_inside {
|
||||
|
@ -72,6 +74,7 @@ impl IndependentFormattingContext {
|
|||
&style,
|
||||
non_replaced,
|
||||
content_sizes,
|
||||
propagated_text_decoration_line,
|
||||
);
|
||||
Self {
|
||||
tag: node.as_opaque(),
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::geom::{PhysicalPoint, PhysicalRect};
|
|||
#[cfg(debug_assertions)]
|
||||
use crate::layout_debug;
|
||||
use crate::positioned::HoistedFragmentId;
|
||||
use gfx::font::FontMetrics as GfxFontMetrics;
|
||||
use gfx::text::glyph::GlyphStore;
|
||||
use gfx_traits::print_tree::PrintTree;
|
||||
#[cfg(not(debug_assertions))]
|
||||
|
@ -18,6 +19,7 @@ use style::dom::OpaqueNode;
|
|||
use style::logical_geometry::WritingMode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::Length;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
use style::Zero;
|
||||
use webrender_api::{FontInstanceKey, ImageKey};
|
||||
|
||||
|
@ -86,6 +88,29 @@ pub(crate) struct AnonymousFragment {
|
|||
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)]
|
||||
pub(crate) struct TextFragment {
|
||||
pub debug_id: DebugId,
|
||||
|
@ -93,10 +118,12 @@ pub(crate) struct TextFragment {
|
|||
#[serde(skip_serializing)]
|
||||
pub parent_style: ServoArc<ComputedValues>,
|
||||
pub rect: Rect<Length>,
|
||||
pub ascent: Length,
|
||||
pub font_metrics: FontMetrics,
|
||||
#[serde(skip_serializing)]
|
||||
pub font_key: FontInstanceKey,
|
||||
pub glyphs: Vec<Arc<GlyphStore>>,
|
||||
/// A flag that represents the _used_ value of the text-decoration property.
|
||||
pub text_decoration_line: TextDecorationLine,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
|
@ -17,6 +17,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||
use style::computed_values::position::T as Position;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
use style::Zero;
|
||||
|
||||
static HOISTED_FRAGMENT_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
|
@ -104,6 +105,8 @@ impl AbsolutelyPositionedBox {
|
|||
display_inside,
|
||||
contents,
|
||||
content_sizes,
|
||||
// Text decorations are not propagated to any out-of-flow descendants.
|
||||
TextDecorationLine::NONE,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ ${helpers.predefined_type(
|
|||
"TextDecorationLine",
|
||||
"specified::TextDecorationLine::none()",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.2020.unimplemented",
|
||||
initial_specified_value="specified::TextDecorationLine::none()",
|
||||
animation_value_type="discrete",
|
||||
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line",
|
||||
|
@ -42,7 +41,7 @@ ${helpers.predefined_type(
|
|||
${helpers.single_keyword(
|
||||
"text-decoration-style",
|
||||
"solid double dotted dashed wavy -moz-none",
|
||||
engines="gecko",
|
||||
engines="gecko servo-2020",
|
||||
animation_value_type="discrete",
|
||||
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style",
|
||||
)}
|
||||
|
@ -51,7 +50,7 @@ ${helpers.predefined_type(
|
|||
"text-decoration-color",
|
||||
"Color",
|
||||
"computed_value::T::currentcolor()",
|
||||
engines="gecko",
|
||||
engines="gecko servo-2020",
|
||||
initial_specified_value="specified::Color::currentcolor()",
|
||||
animation_value_type="AnimatedColor",
|
||||
ignored_when_colors_disabled=True,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||
|
||||
<%helpers:shorthand name="text-decoration"
|
||||
engines="gecko servo-2013"
|
||||
engines="gecko servo-2013 servo-2020"
|
||||
flags="SHORTHAND_IN_GETCS"
|
||||
sub_properties="text-decoration-line
|
||||
${' text-decoration-style text-decoration-color text-decoration-thickness' if engine == 'gecko' else ''}"
|
||||
|
|
|
@ -217,7 +217,7 @@ impl ToComputedValue for TextOverflow {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||
#[derive(MallocSizeOf, Serialize, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||
#[value_info(other_values = "none,underline,overline,line-through,blink")]
|
||||
#[repr(C)]
|
||||
/// 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 {
|
||||
/// none | [ underline || overline || line-through || blink ]
|
||||
fn parse<'i, 't>(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue