diff --git a/components/layout_2020/display_list.rs b/components/layout_2020/display_list.rs index f39a2f23b18..6bd6c60a663 100644 --- a/components/layout_2020/display_list.rs +++ b/components/layout_2020/display_list.rs @@ -5,15 +5,21 @@ use crate::fragments::{BoxFragment, Fragment}; use crate::geom::physical::{Rect, Vec2}; use embedder_traits::Cursor; -use euclid::{Point2D, SideOffsets2D}; +use euclid::{Point2D, SideOffsets2D, Size2D}; use gfx::text::glyph::GlyphStore; use std::sync::Arc; +use style::dom::OpaqueNode; use style::properties::ComputedValues; -use style::values::computed::{BorderStyle, Length}; -use webrender_api::{self as wr, units, CommonItemProperties, PrimitiveFlags}; +use style::values::computed::{BorderStyle, Length, LengthPercentage}; +use style::values::specified::ui::CursorKind; +use webrender_api::{self as wr, units}; + +// `webrender_api::display_item::ItemTag` is private +type ItemTag = (u64, u16); +type HitInfo = Option; pub struct DisplayListBuilder { - pipeline_id: wr::PipelineId, + current_space_and_clip: wr::SpaceAndClipInfo, pub wr: wr::DisplayListBuilder, pub is_contentful: bool, } @@ -21,11 +27,33 @@ pub struct DisplayListBuilder { impl DisplayListBuilder { pub fn new(pipeline_id: wr::PipelineId, viewport_size: wr::units::LayoutSize) -> Self { Self { - pipeline_id, + current_space_and_clip: wr::SpaceAndClipInfo::root_scroll(pipeline_id), is_contentful: false, wr: wr::DisplayListBuilder::new(pipeline_id, viewport_size), } } + + fn common_properties( + &self, + clip_rect: units::LayoutRect, + hit_info: HitInfo, + ) -> wr::CommonItemProperties { + wr::CommonItemProperties { + clip_rect, + clip_id: self.current_space_and_clip.clip_id, + spatial_id: self.current_space_and_clip.spatial_id, + hit_info, + // TODO(gw): Make use of the WR backface visibility functionality. + flags: wr::PrimitiveFlags::default(), + } + } + + fn clipping_and_scrolling_scope(&mut self, f: impl FnOnce(&mut Self) -> R) -> R { + let previous = self.current_space_and_clip; + let result = f(self); + self.current_space_and_clip = previous; + result + } } /// Contentful paint, for the purpose of @@ -60,19 +88,12 @@ impl Fragment { .translate(&containing_block.top_left); let mut baseline_origin = rect.top_left.clone(); baseline_origin.y += t.ascent; - let cursor = cursor(&t.parent_style, Cursor::Text); - let common = CommonItemProperties { - clip_rect: rect.clone().into(), - clip_id: wr::ClipId::root(builder.pipeline_id), - spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id), - hit_info: cursor.map(|cursor| (t.tag.0 as u64, cursor as u16)), - // TODO(gw): Make use of the WR backface visibility functionality. - flags: PrimitiveFlags::default(), - }; let glyphs = glyphs(&t.glyphs, baseline_origin); if glyphs.is_empty() { return; } + let hit_info = hit_info(&t.parent_style, t.tag, Cursor::Text); + let common = builder.common_properties(rect.clone().into(), hit_info); let color = t.parent_style.clone_color(); builder .wr @@ -85,14 +106,8 @@ impl Fragment { .rect .to_physical(i.style.writing_mode, containing_block) .translate(&containing_block.top_left); - let common = CommonItemProperties { - clip_rect: rect.clone().into(), - clip_id: wr::ClipId::root(builder.pipeline_id), - spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id), - hit_info: None, - // TODO(gw): Make use of the WR backface visibility functionality. - flags: PrimitiveFlags::default(), - }; + let hit_info = None; + let common = builder.common_properties(rect.clone().into(), hit_info); builder.wr.push_image( &common, rect.into(), @@ -122,18 +137,11 @@ impl BoxFragment { .to_physical(self.style.writing_mode, containing_block) .translate(&containing_block.top_left) .into(); - let cursor = cursor(&self.style, Cursor::Default); - let common = CommonItemProperties { - clip_rect: border_rect, - clip_id: wr::ClipId::root(builder.pipeline_id), - spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id), - hit_info: cursor.map(|cursor| (self.tag.0 as u64, cursor as u16)), - // TODO(gw): Make use of the WR backface visibility functionality. - flags: PrimitiveFlags::default(), - }; + let hit_info = hit_info(&self.style, self.tag, Cursor::Default); + let border_radius = self.border_radius(&border_rect); - self.background_display_items(builder, &common); - self.border_display_items(builder, &common, border_rect); + self.background_display_items(builder, hit_info, border_rect, &border_radius); + self.border_display_items(builder, hit_info, border_rect, border_radius); let content_rect = self .content_rect .to_physical(self.style.writing_mode, containing_block) @@ -143,24 +151,61 @@ impl BoxFragment { } } + fn border_radius(&self, border_rect: &units::LayoutRect) -> wr::BorderRadius { + let resolve = |radius: &LengthPercentage, box_size: f32| { + radius.percentage_relative_to(Length::new(box_size)).px() + }; + let corner = |corner: &style::values::computed::BorderCornerRadius| { + Size2D::new( + resolve(&corner.0.width.0, border_rect.size.width), + resolve(&corner.0.height.0, border_rect.size.height), + ) + }; + let b = self.style.get_border(); + wr::BorderRadius { + top_left: corner(&b.border_top_left_radius), + top_right: corner(&b.border_top_right_radius), + bottom_right: corner(&b.border_bottom_right_radius), + bottom_left: corner(&b.border_bottom_left_radius), + } + } + fn background_display_items( &self, builder: &mut DisplayListBuilder, - common: &CommonItemProperties, + hit_info: HitInfo, + border_rect: units::LayoutRect, + border_radius: &wr::BorderRadius, ) { let background_color = self .style .resolve_color(self.style.clone_background_color()); - if background_color.alpha > 0 || common.hit_info.is_some() { - builder.wr.push_rect(common, rgba(background_color)) + if background_color.alpha > 0 || hit_info.is_some() { + builder.clipping_and_scrolling_scope(|builder| { + if !border_radius.is_zero() { + builder.current_space_and_clip.clip_id = builder.wr.define_clip( + &builder.current_space_and_clip, + border_rect, + Some(wr::ComplexClipRegion { + rect: border_rect, + radii: *border_radius, + mode: wr::ClipMode::Clip, + }), + None, + ); + } + let common = builder.common_properties(border_rect, hit_info); + builder.wr.push_rect(&common, rgba(background_color)) + }); } } fn border_display_items( &self, builder: &mut DisplayListBuilder, - common: &CommonItemProperties, + hit_info: HitInfo, border_rect: units::LayoutRect, + radius: wr::BorderRadius, ) { let b = self.style.get_border(); let widths = SideOffsets2D::new( @@ -187,15 +232,18 @@ impl BoxFragment { BorderStyle::Outset => wr::BorderStyle::Outset, }, }; + let common = builder.common_properties(border_rect, hit_info); let details = wr::BorderDetails::Normal(wr::NormalBorder { top: side(b.border_top_style, b.border_top_color), right: side(b.border_right_style, b.border_right_color), bottom: side(b.border_bottom_style, b.border_bottom_color), left: side(b.border_left_style, b.border_left_color), - radius: wr::BorderRadius::zero(), + radius, do_aa: true, }); - builder.wr.push_border(common, border_rect, widths, details) + builder + .wr + .push_border(&common, border_rect, widths, details) } } @@ -233,16 +281,21 @@ fn glyphs(glyph_runs: &[Arc], mut origin: Vec2) -> Vec Option { +fn hit_info(style: &ComputedValues, tag: OpaqueNode, auto_cursor: Cursor) -> HitInfo { use style::computed_values::pointer_events::T as PointerEvents; - use style::values::specified::ui::CursorKind; - let inherited_ui = values.get_inherited_ui(); + let inherited_ui = style.get_inherited_ui(); if inherited_ui.pointer_events == PointerEvents::None { - return None; + None + } else { + let cursor = cursor(inherited_ui.cursor.keyword, auto_cursor); + Some((tag.0 as u64, cursor as u16)) } - Some(match inherited_ui.cursor.keyword { - CursorKind::Auto => default, +} + +fn cursor(kind: CursorKind, auto_cursor: Cursor) -> Cursor { + match kind { + CursorKind::Auto => auto_cursor, CursorKind::None => Cursor::None, CursorKind::Default => Cursor::Default, CursorKind::Pointer => Cursor::Pointer, @@ -278,5 +331,5 @@ fn cursor(values: &ComputedValues, default: Cursor) -> Option { CursorKind::AllScroll => Cursor::AllScroll, CursorKind::ZoomIn => Cursor::ZoomIn, CursorKind::ZoomOut => Cursor::ZoomOut, - }) + } } diff --git a/components/style/properties/longhands/border.mako.rs b/components/style/properties/longhands/border.mako.rs index 09cbea19a7f..f281fa1a30d 100644 --- a/components/style/properties/longhands/border.mako.rs +++ b/components/style/properties/longhands/border.mako.rs @@ -75,7 +75,7 @@ "BorderCornerRadius", "computed::BorderCornerRadius::zero()", "parse", - engines="gecko servo-2013", + engines="gecko servo-2013 servo-2020", extra_prefixes=prefixes, spec=maybe_logical_spec(corner, "radius"), boxed=True, diff --git a/components/style/properties/shorthands/border.mako.rs b/components/style/properties/shorthands/border.mako.rs index d584e568aed..1f77b905021 100644 --- a/components/style/properties/shorthands/border.mako.rs +++ b/components/style/properties/shorthands/border.mako.rs @@ -239,7 +239,7 @@ pub fn parse_border<'i, 't>( <%helpers:shorthand name="border-radius" - engines="gecko servo-2013" + engines="gecko servo-2013 servo-2020" sub_properties="${' '.join( 'border-%s-radius' % (corner) for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']