aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/display_list
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/display_list')
-rw-r--r--components/layout/display_list/background.rs18
-rw-r--r--components/layout/display_list/conversions.rs8
-rw-r--r--components/layout/display_list/mod.rs130
-rw-r--r--components/layout/display_list/stacking_context.rs76
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,
);
}
}