diff options
Diffstat (limited to 'components/layout/display_list')
-rw-r--r-- | components/layout/display_list/background.rs | 18 | ||||
-rw-r--r-- | components/layout/display_list/conversions.rs | 8 | ||||
-rw-r--r-- | components/layout/display_list/mod.rs | 130 | ||||
-rw-r--r-- | components/layout/display_list/stacking_context.rs | 76 |
4 files changed, 176 insertions, 56 deletions
diff --git a/components/layout/display_list/background.rs b/components/layout/display_list/background.rs index 563bce28450..f1099fdab2b 100644 --- a/components/layout/display_list/background.rs +++ b/components/layout/display_list/background.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use app_units::Au; -use euclid::{Point2D, Size2D, Vector2D}; +use euclid::{Size2D, Vector2D}; use style::computed_values::background_attachment::SingleComputedValue as BackgroundAttachment; use style::computed_values::background_clip::single_value::T as Clip; use style::computed_values::background_origin::single_value::T as Origin; @@ -15,7 +15,6 @@ use style::values::specified::background::{ }; use webrender_api::{self as wr, units}; use wr::ClipChainId; -use wr::units::LayoutSize; use crate::replaced::NaturalSizes; @@ -66,8 +65,7 @@ impl<'a> BackgroundPainter<'a> { if &BackgroundAttachment::Fixed == get_cyclic(&background.background_attachment.0, layer_index) { - let viewport_size = builder.compositor_info.viewport_size; - return units::LayoutRect::from_origin_and_size(Point2D::origin(), viewport_size); + return builder.compositor_info.viewport_size.into(); } match get_cyclic(&background.background_clip.0, layer_index) { @@ -132,6 +130,7 @@ impl<'a> BackgroundPainter<'a> { pub(super) fn positioning_area( &self, fragment_builder: &'a super::BuilderForBoxFragment, + builder: &mut super::DisplayListBuilder, layer_index: usize, ) -> units::LayoutRect { if let Some(positioning_area_override) = self.positioning_area_override { @@ -150,14 +149,7 @@ impl<'a> BackgroundPainter<'a> { Origin::PaddingBox => *fragment_builder.padding_rect(), Origin::BorderBox => fragment_builder.border_rect, }, - BackgroundAttachment::Fixed => { - // This isn't the viewport size because that rects larger than the viewport might be - // transformed down into areas smaller than the viewport. - units::LayoutRect::from_origin_and_size( - Point2D::origin(), - LayoutSize::new(f32::MAX, f32::MAX), - ) - }, + BackgroundAttachment::Fixed => builder.compositor_info.viewport_size.into(), } } } @@ -170,7 +162,7 @@ pub(super) fn layout_layer( natural_sizes: NaturalSizes, ) -> Option<BackgroundLayer> { let painting_area = painter.painting_area(fragment_builder, builder, layer_index); - let positioning_area = painter.positioning_area(fragment_builder, layer_index); + let positioning_area = painter.positioning_area(fragment_builder, builder, layer_index); let common = painter.common_properties(fragment_builder, builder, layer_index, painting_area); // https://drafts.csswg.org/css-backgrounds/#background-size diff --git a/components/layout/display_list/conversions.rs b/components/layout/display_list/conversions.rs index 6d78a17e886..a2517c863f1 100644 --- a/components/layout/display_list/conversions.rs +++ b/components/layout/display_list/conversions.rs @@ -125,11 +125,15 @@ impl ToWebRender for ComputedTextDecorationStyle { type Type = LineStyle; fn to_webrender(&self) -> Self::Type { match *self { - ComputedTextDecorationStyle::Solid => LineStyle::Solid, + ComputedTextDecorationStyle::Solid | ComputedTextDecorationStyle::Double => { + LineStyle::Solid + }, ComputedTextDecorationStyle::Dotted => LineStyle::Dotted, ComputedTextDecorationStyle::Dashed => LineStyle::Dashed, ComputedTextDecorationStyle::Wavy => LineStyle::Wavy, - _ => LineStyle::Solid, + ComputedTextDecorationStyle::MozNone => { + unreachable!("Should never try to draw a moz-none text decoration") + }, } } } diff --git a/components/layout/display_list/mod.rs b/components/layout/display_list/mod.rs index 95689cf1186..3716ff35b2c 100644 --- a/components/layout/display_list/mod.rs +++ b/components/layout/display_list/mod.rs @@ -11,7 +11,7 @@ use base::id::ScrollTreeNodeId; use clip::{Clip, ClipId}; use compositing_traits::display_list::{CompositorDisplayListInfo, SpatialTreeNodeInfo}; use embedder_traits::Cursor; -use euclid::{Point2D, SideOffsets2D, Size2D, UnknownUnit}; +use euclid::{Point2D, SideOffsets2D, Size2D, UnknownUnit, Vector2D}; use fonts::GlyphStore; use gradient::WebRenderGradient; use range::Range as ServoRange; @@ -21,7 +21,9 @@ use servo_geometry::MaxRect; use style::Zero; use style::color::{AbsoluteColor, ColorSpace}; 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::properties::ComputedValues; use style::properties::longhands::visibility::computed_value::T as Visibility; @@ -572,6 +574,7 @@ impl Fragment { section: StackingContextSection, is_hit_test_for_scrollable_overflow: bool, is_collapsed_table_borders: bool, + text_decorations: &Arc<Vec<FragmentTextDecoration>>, ) { let spatial_id = builder.spatial_id(builder.current_scroll_node_id); let clip_chain_id = builder.clip_chain_id(builder.current_clip_id); @@ -683,9 +686,12 @@ impl Fragment { .get_inherited_box() .visibility { - Visibility::Visible => { - self.build_display_list_for_text_fragment(text, builder, containing_block) - }, + Visibility::Visible => self.build_display_list_for_text_fragment( + text, + builder, + containing_block, + text_decorations, + ), Visibility::Hidden => (), Visibility::Collapse => (), } @@ -723,6 +729,7 @@ impl Fragment { fragment: &TextFragment, builder: &mut DisplayListBuilder, containing_block: &PhysicalRect<Au>, + text_decorations: &Arc<Vec<FragmentTextDecoration>>, ) { // NB: The order of painting text components (CSS Text Decoration Module Level 3) is: // shadows, underline, overline, text, text-emphasis, and then line-through. @@ -732,6 +739,7 @@ impl Fragment { let rect = fragment.rect.translate(containing_block.origin.to_vector()); let mut baseline_origin = rect.origin; baseline_origin.y += fragment.font_metrics.ascent; + let glyphs = glyphs( &fragment.glyphs, baseline_origin, @@ -774,23 +782,36 @@ impl Fragment { ); } - if fragment - .text_decoration_line - .contains(TextDecorationLine::UNDERLINE) - { - let mut rect = rect; - rect.origin.y += font_metrics.ascent - font_metrics.underline_offset; - rect.size.height = Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx)); - self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color); + for text_decoration in text_decorations.iter() { + if text_decoration.line.contains(TextDecorationLine::UNDERLINE) { + let mut rect = rect; + rect.origin.y += font_metrics.ascent - font_metrics.underline_offset; + rect.size.height = + Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx)); + + self.build_display_list_for_text_decoration( + &parent_style, + builder, + &rect, + text_decoration, + TextDecorationLine::UNDERLINE, + ); + } } - if fragment - .text_decoration_line - .contains(TextDecorationLine::OVERLINE) - { - let mut rect = rect; - rect.size.height = Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx)); - self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color); + for text_decoration in text_decorations.iter() { + if text_decoration.line.contains(TextDecorationLine::OVERLINE) { + let mut rect = rect; + rect.size.height = + Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx)); + self.build_display_list_for_text_decoration( + &parent_style, + builder, + &rect, + text_decoration, + TextDecorationLine::OVERLINE, + ); + } } // TODO: This caret/text selection implementation currently does not account for vertical text @@ -867,14 +888,23 @@ impl Fragment { None, ); - if fragment - .text_decoration_line - .contains(TextDecorationLine::LINE_THROUGH) - { - let mut rect = rect; - rect.origin.y += font_metrics.ascent - font_metrics.strikeout_offset; - rect.size.height = Au::from_f32_px(font_metrics.strikeout_size.to_nearest_pixel(dppx)); - self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color); + for text_decoration in text_decorations.iter() { + if text_decoration + .line + .contains(TextDecorationLine::LINE_THROUGH) + { + let mut rect = rect; + rect.origin.y += font_metrics.ascent - font_metrics.strikeout_offset; + rect.size.height = + Au::from_f32_px(font_metrics.strikeout_size.to_nearest_pixel(dppx)); + self.build_display_list_for_text_decoration( + &parent_style, + builder, + &rect, + text_decoration, + TextDecorationLine::LINE_THROUGH, + ); + } } if !shadows.0.is_empty() { @@ -887,27 +917,47 @@ impl Fragment { parent_style: &ServoArc<ComputedValues>, builder: &mut DisplayListBuilder, rect: &PhysicalRect<Au>, - color: &AbsoluteColor, + text_decoration: &FragmentTextDecoration, + line: TextDecorationLine, ) { - let rect = rect.to_webrender(); - let wavy_line_thickness = (0.33 * rect.size().height).ceil(); - let text_decoration_color = parent_style - .clone_text_decoration_color() - .resolve_to_absolute(color); - let text_decoration_style = parent_style.clone_text_decoration_style(); - if text_decoration_style == ComputedTextDecorationStyle::MozNone { + if text_decoration.style == ComputedTextDecorationStyle::MozNone { 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); builder.wr().push_line( &common_properties, &rect, - wavy_line_thickness, + line_thickness, wr::LineOrientation::Horizontal, - &rgba(text_decoration_color), - text_decoration_style.to_webrender(), + &rgba(text_decoration.color), + 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(), + ); + } } } diff --git a/components/layout/display_list/stacking_context.rs b/components/layout/display_list/stacking_context.rs index bcd882e3fcc..d22a2b6656a 100644 --- a/components/layout/display_list/stacking_context.rs +++ b/components/layout/display_list/stacking_context.rs @@ -5,6 +5,7 @@ use core::f32; use std::cell::RefCell; use std::mem; +use std::sync::Arc; use app_units::Au; use base::id::ScrollTreeNodeId; @@ -18,13 +19,15 @@ use euclid::default::{Point2D, Rect, Size2D}; use log::warn; use servo_config::opts::DebugOptions; use style::Zero; +use style::color::AbsoluteColor; use style::computed_values::float::T as ComputedFloat; use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode; use style::computed_values::overflow_x::T as ComputedOverflow; use style::computed_values::position::T as ComputedPosition; +use style::computed_values::text_decoration_style::T as TextDecorationStyle; use style::values::computed::angle::Angle; use style::values::computed::basic_shape::ClipPath; -use style::values::computed::{ClipRectOrAuto, Length}; +use style::values::computed::{ClipRectOrAuto, Length, TextDecorationLine}; use style::values::generics::box_::Perspective; use style::values::generics::transform::{self, GenericRotate, GenericScale, GenericTranslate}; use style::values::specified::box_::DisplayOutside; @@ -168,12 +171,14 @@ impl StackingContextTree { }; let mut root_stacking_context = StackingContext::create_root(root_scroll_node_id, debug); + let text_decorations = Default::default(); for fragment in &fragment_tree.root_fragments { fragment.build_stacking_context_tree( &mut stacking_context_tree, &containing_block_info, &mut root_stacking_context, StackingContextBuildMode::SkipHoisted, + &text_decorations, ); } root_stacking_context.sort(); @@ -246,6 +251,14 @@ impl StackingContextTree { } } +/// The text decorations for a Fragment, collecting during [`StackingContextTree`] construction. +#[derive(Clone, Debug)] +pub(crate) struct FragmentTextDecoration { + pub line: TextDecorationLine, + pub color: AbsoluteColor, + pub style: TextDecorationStyle, +} + /// A piece of content that directly belongs to a section of a stacking context. /// /// This is generally part of a fragment, like its borders or foreground, but it @@ -261,6 +274,7 @@ pub(crate) enum StackingContextContent { fragment: Fragment, is_hit_test_for_scrollable_overflow: bool, is_collapsed_table_borders: bool, + text_decorations: Arc<Vec<FragmentTextDecoration>>, }, /// An index into [StackingContext::atomic_inline_stacking_containers]. @@ -292,6 +306,7 @@ impl StackingContextContent { fragment, is_hit_test_for_scrollable_overflow, is_collapsed_table_borders, + text_decorations, } => { builder.current_scroll_node_id = *scroll_node_id; builder.current_reference_frame_scroll_node_id = *reference_frame_scroll_node_id; @@ -302,6 +317,7 @@ impl StackingContextContent { *section, *is_hit_test_for_scrollable_overflow, *is_collapsed_table_borders, + text_decorations, ); }, Self::AtomicInlineStackingContainer { index } => { @@ -800,6 +816,7 @@ impl Fragment { containing_block_info: &ContainingBlockInfo, stacking_context: &mut StackingContext, mode: StackingContextBuildMode, + text_decorations: &Arc<Vec<FragmentTextDecoration>>, ) { let containing_block = containing_block_info.get_containing_block_for_fragment(self); let fragment_clone = self.clone(); @@ -812,6 +829,11 @@ impl Fragment { return; } + let text_decorations = match self { + Fragment::Float(..) => &Default::default(), + _ => text_decorations, + }; + // If this fragment has a transform applied that makes it take up no space // then we don't need to create any stacking contexts for it. let has_non_invertible_transform = fragment @@ -828,6 +850,7 @@ impl Fragment { containing_block, containing_block_info, stacking_context, + text_decorations, ); }, Fragment::AbsoluteOrFixedPositioned(fragment) => { @@ -842,6 +865,7 @@ impl Fragment { containing_block_info, stacking_context, StackingContextBuildMode::IncludeHoisted, + &Default::default(), ); }, Fragment::Positioning(fragment) => { @@ -851,6 +875,7 @@ impl Fragment { containing_block, containing_block_info, stacking_context, + text_decorations, ); }, Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => { @@ -867,6 +892,7 @@ impl Fragment { fragment: fragment_clone, is_hit_test_for_scrollable_overflow: false, is_collapsed_table_borders: false, + text_decorations: text_decorations.clone(), }); }, } @@ -929,6 +955,7 @@ impl BoxFragment { containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, parent_stacking_context: &mut StackingContext, + text_decorations: &Arc<Vec<FragmentTextDecoration>>, ) { self.build_stacking_context_tree_maybe_creating_reference_frame( fragment, @@ -936,6 +963,7 @@ impl BoxFragment { containing_block, containing_block_info, parent_stacking_context, + text_decorations, ); } @@ -946,6 +974,7 @@ impl BoxFragment { containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, parent_stacking_context: &mut StackingContext, + text_decorations: &Arc<Vec<FragmentTextDecoration>>, ) { let reference_frame_data = match self.reference_frame_data_if_necessary(&containing_block.rect) { @@ -957,6 +986,7 @@ impl BoxFragment { containing_block, containing_block_info, parent_stacking_context, + text_decorations, ); }, }; @@ -999,6 +1029,7 @@ impl BoxFragment { &adjusted_containing_block, &new_containing_block_info, parent_stacking_context, + text_decorations, ); } @@ -1009,6 +1040,7 @@ impl BoxFragment { containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, parent_stacking_context: &mut StackingContext, + text_decorations: &Arc<Vec<FragmentTextDecoration>>, ) { let context_type = match self.get_stacking_context_type() { Some(context_type) => context_type, @@ -1019,6 +1051,7 @@ impl BoxFragment { containing_block, containing_block_info, parent_stacking_context, + text_decorations, ); return; }, @@ -1072,6 +1105,7 @@ impl BoxFragment { containing_block, containing_block_info, &mut child_stacking_context, + text_decorations, ); let mut stolen_children = vec![]; @@ -1097,6 +1131,7 @@ impl BoxFragment { containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, stacking_context: &mut StackingContext, + text_decorations: &Arc<Vec<FragmentTextDecoration>>, ) { let mut new_scroll_node_id = containing_block.scroll_node_id; let mut new_clip_id = containing_block.clip_id; @@ -1164,6 +1199,7 @@ impl BoxFragment { fragment: fragment.clone(), is_hit_test_for_scrollable_overflow: false, is_collapsed_table_borders: false, + text_decorations: text_decorations.clone(), }); }; @@ -1198,6 +1234,7 @@ impl BoxFragment { fragment: fragment.clone(), is_hit_test_for_scrollable_overflow: true, is_collapsed_table_borders: false, + text_decorations: text_decorations.clone(), }); } } @@ -1239,12 +1276,46 @@ impl BoxFragment { containing_block_info.new_for_non_absolute_descendants(&for_non_absolute_descendants) }; + // Text decorations are not propagated to atomic inline-level descendants. + // From https://drafts.csswg.org/css2/#lining-striking-props: + // > Note that text decorations are not propagated to floating and absolutely + // > positioned descendants, nor to the contents of atomic inline-level descendants + // > such as inline blocks and inline tables. + let text_decorations = match self.is_atomic_inline_level() || + self.base + .flags + .contains(FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER) + { + true => &Default::default(), + false => text_decorations, + }; + + let new_text_decoration; + let text_decorations = match self.style.clone_text_decoration_line() { + TextDecorationLine::NONE => text_decorations, + line => { + let mut new_vector = (**text_decorations).clone(); + let color = &self.style.get_inherited_text().color; + new_vector.push(FragmentTextDecoration { + line, + color: self + .style + .clone_text_decoration_color() + .resolve_to_absolute(color), + style: self.style.clone_text_decoration_style(), + }); + new_text_decoration = Arc::new(new_vector); + &new_text_decoration + }, + }; + for child in &self.children { child.build_stacking_context_tree( stacking_context_tree, &new_containing_block_info, stacking_context, StackingContextBuildMode::SkipHoisted, + text_decorations, ); } @@ -1263,6 +1334,7 @@ impl BoxFragment { fragment: fragment.clone(), is_hit_test_for_scrollable_overflow: false, is_collapsed_table_borders: true, + text_decorations: text_decorations.clone(), }); } } @@ -1646,6 +1718,7 @@ impl PositioningFragment { containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, stacking_context: &mut StackingContext, + text_decorations: &Arc<Vec<FragmentTextDecoration>>, ) { let rect = self .rect @@ -1660,6 +1733,7 @@ impl PositioningFragment { &new_containing_block_info, stacking_context, StackingContextBuildMode::SkipHoisted, + text_decorations, ); } } |