aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2017-07-27 11:25:59 +0200
committerMartin Robinson <mrobinson@igalia.com>2017-08-03 17:52:02 +0200
commitdaf638bc3f1deebb23cc4375f872a1b1b4bc543c (patch)
tree87ea0fd8ab332146fcd829c0410d7b9a99d033b8
parent46f6e68bad7aafc380976bfddd9e76bfaa86229e (diff)
downloadservo-daf638bc3f1deebb23cc4375f872a1b1b4bc543c.tar.gz
servo-daf638bc3f1deebb23cc4375f872a1b1b4bc543c.zip
Fix fixed position items with parents with CSS clips
In order to properly handle CSS clipping, we need to keep track of what the different kinds of clips that we have. On one hand, clipping due to overflow rules should respect the containing block hierarchy, while CSS clipping should respect the flow tree hierarchy. In order to represent the complexity of items that are scrolled via one clip/scroll frame and clipped by another we keep track of that status with a ClipAndScrollInfo.
-rw-r--r--components/gfx/display_list/mod.rs44
-rw-r--r--components/gfx_traits/lib.rs2
-rw-r--r--components/layout/display_list_builder.rs130
-rw-r--r--components/layout/flow.rs16
-rw-r--r--components/layout/table_colgroup.rs3
-rw-r--r--components/layout/traversal.rs7
-rw-r--r--components/layout/webrender_helpers.rs25
-rw-r--r--components/msg/constellation_msg.rs4
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json25
-rw-r--r--tests/wpt/mozilla/tests/css/fixed_position_css_clip.html40
-rw-r--r--tests/wpt/mozilla/tests/css/fixed_position_css_clip_ref.html24
11 files changed, 214 insertions, 106 deletions
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs
index ba34abea28d..8fa0c33df49 100644
--- a/components/gfx/display_list/mod.rs
+++ b/components/gfx/display_list/mod.rs
@@ -33,8 +33,8 @@ use style::values::computed::Filter;
use style_traits::cursor::Cursor;
use text::TextRun;
use text::glyph::ByteIndex;
-use webrender_api::{self, ClipId, ColorF, GradientStop, LocalClip, MixBlendMode, ScrollPolicy};
-use webrender_api::{ScrollSensitivity, TransformStyle, WebGLContextId};
+use webrender_api::{self, ClipAndScrollInfo, ClipId, ColorF, GradientStop, LocalClip};
+use webrender_api::{MixBlendMode, ScrollPolicy, ScrollSensitivity, TransformStyle, WebGLContextId};
pub use style::dom::OpaqueNode;
@@ -152,7 +152,7 @@ impl DisplayList {
match item {
&DisplayItem::PushStackingContext(ref context_item) => {
self.text_index_stacking_context(&context_item.stacking_context,
- item.base().scroll_root_id,
+ item.scroll_node_id(),
node,
traversal,
point,
@@ -229,7 +229,7 @@ impl DisplayList {
match item {
&DisplayItem::PushStackingContext(ref context_item) => {
self.hit_test_stacking_context(&context_item.stacking_context,
- item.base().scroll_root_id,
+ item.scroll_node_id(),
traversal,
point,
offset_lookup,
@@ -286,10 +286,10 @@ impl DisplayList {
pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
print_tree.new_level("Items".to_owned());
for item in &self.list {
- print_tree.add_item(format!("{:?} StackingContext: {:?} ScrollRoot: {:?}",
+ print_tree.add_item(format!("{:?} StackingContext: {:?} {:?}",
item,
item.base().stacking_context_id,
- item.scroll_root_id()));
+ item.clip_and_scroll_info()));
}
print_tree.end_level();
}
@@ -438,8 +438,8 @@ pub struct StackingContext {
/// The scroll policy of this layer.
pub scroll_policy: ScrollPolicy,
- /// The id of the parent scrolling area that contains this StackingContext.
- pub parent_scroll_id: ClipId,
+ /// The clip and scroll info for this StackingContext.
+ pub parent_clip_and_scroll_info: ClipAndScrollInfo,
}
impl StackingContext {
@@ -456,7 +456,7 @@ impl StackingContext {
transform_style: TransformStyle,
perspective: Option<Transform3D<f32>>,
scroll_policy: ScrollPolicy,
- parent_scroll_id: ClipId)
+ parent_clip_and_scroll_info: ClipAndScrollInfo)
-> StackingContext {
StackingContext {
id: id,
@@ -470,7 +470,7 @@ impl StackingContext {
transform_style: transform_style,
perspective: perspective,
scroll_policy: scroll_policy,
- parent_scroll_id: parent_scroll_id,
+ parent_clip_and_scroll_info: parent_clip_and_scroll_info,
}
}
@@ -487,13 +487,13 @@ impl StackingContext {
TransformStyle::Flat,
None,
ScrollPolicy::Scrollable,
- pipeline_id.root_scroll_node())
+ pipeline_id.root_clip_and_scroll_info())
}
pub fn to_display_list_items(self, pipeline_id: PipelineId) -> (DisplayItem, DisplayItem) {
let mut base_item = BaseDisplayItem::empty(pipeline_id);
base_item.stacking_context_id = self.id;
- base_item.scroll_root_id = self.parent_scroll_id;
+ base_item.clip_and_scroll_info = self.parent_clip_and_scroll_info;
let pop_item = DisplayItem::PopStackingContext(Box::new(
PopStackingContextItem {
@@ -631,8 +631,8 @@ pub struct BaseDisplayItem {
/// The id of the stacking context this item belongs to.
pub stacking_context_id: StackingContextId,
- /// The id of the scroll root this item belongs to.
- pub scroll_root_id: ClipId,
+ /// The clip and scroll info for this item.
+ pub clip_and_scroll_info: ClipAndScrollInfo,
}
impl BaseDisplayItem {
@@ -642,7 +642,7 @@ impl BaseDisplayItem {
local_clip: LocalClip,
section: DisplayListSection,
stacking_context_id: StackingContextId,
- scroll_root_id: ClipId)
+ clip_and_scroll_info: ClipAndScrollInfo)
-> BaseDisplayItem {
BaseDisplayItem {
bounds: *bounds,
@@ -650,7 +650,7 @@ impl BaseDisplayItem {
local_clip: local_clip,
section: section,
stacking_context_id: stacking_context_id,
- scroll_root_id: scroll_root_id,
+ clip_and_scroll_info: clip_and_scroll_info,
}
}
@@ -665,7 +665,7 @@ impl BaseDisplayItem {
local_clip: LocalClip::from(max_rect().to_rectf()),
section: DisplayListSection::Content,
stacking_context_id: StackingContextId::root(),
- scroll_root_id: pipeline_id.root_scroll_node(),
+ clip_and_scroll_info: pipeline_id.root_clip_and_scroll_info(),
}
}
}
@@ -1265,8 +1265,12 @@ impl DisplayItem {
}
}
- pub fn scroll_root_id(&self) -> ClipId {
- self.base().scroll_root_id
+ pub fn scroll_node_id(&self) -> ClipId {
+ self.base().clip_and_scroll_info.scroll_node_id
+ }
+
+ pub fn clip_and_scroll_info(&self) -> ClipAndScrollInfo {
+ self.base().clip_and_scroll_info
}
pub fn stacking_context_id(&self) -> StackingContextId {
@@ -1297,7 +1301,7 @@ impl DisplayItem {
// test elements with `border-radius`, for example.
let base_item = self.base();
- let scroll_offset = offset_lookup.full_offset_for_scroll_root(&base_item.scroll_root_id);
+ let scroll_offset = offset_lookup.full_offset_for_scroll_root(&self.scroll_node_id());
let point = Point2D::new(point.x - Au::from_f32_px(scroll_offset.x),
point.y - Au::from_f32_px(scroll_offset.y));
diff --git a/components/gfx_traits/lib.rs b/components/gfx_traits/lib.rs
index f035df15f1b..b83dc08c52d 100644
--- a/components/gfx_traits/lib.rs
+++ b/components/gfx_traits/lib.rs
@@ -32,7 +32,7 @@ impl Epoch {
pub struct StackingContextId(
/// The identifier for this StackingContext, derived from the Flow's memory address
/// and fragment type. As a space optimization, these are combined into a single word.
- u64
+ pub u64
);
impl StackingContextId {
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index f8b26899b57..5e238a683fe 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -71,8 +71,8 @@ use style_traits::CSSPixel;
use style_traits::ToCss;
use style_traits::cursor::Cursor;
use table_cell::CollapsedBordersForCell;
-use webrender_api::{ClipId, ColorF, ComplexClipRegion, GradientStop, LocalClip, RepeatMode};
-use webrender_api::{LineStyle, ScrollPolicy, ScrollSensitivity, TransformStyle};
+use webrender_api::{ClipAndScrollInfo, ClipId, ColorF, ComplexClipRegion, GradientStop, LineStyle};
+use webrender_api::{LocalClip, RepeatMode, ScrollPolicy, ScrollSensitivity, TransformStyle};
use webrender_helpers::{ToBorderRadius, ToMixBlendMode, ToRectF, ToTransformStyle};
trait ResolvePercentage {
@@ -169,14 +169,14 @@ pub struct DisplayListBuildState<'a> {
/// recursively building and processing the display list.
pub current_stacking_context_id: StackingContextId,
- /// The current scroll root id, used to keep track of state when
+ /// The current clip and scroll info, used to keep track of state when
/// recursively building and processing the display list.
- pub current_scroll_root_id: ClipId,
+ pub current_clip_and_scroll_info: ClipAndScrollInfo,
- /// The scroll root id of the first ancestor which defines a containing block.
+ /// The clip and scroll info of the first ancestor which defines a containing block.
/// This is necessary because absolutely positioned items should be clipped
/// by their containing block's scroll root.
- pub containing_block_scroll_root_id: ClipId,
+ pub containing_block_clip_and_scroll_info: ClipAndScrollInfo,
/// Vector containing iframe sizes, used to inform the constellation about
/// new iframe sizes
@@ -196,6 +196,7 @@ pub struct DisplayListBuildState<'a> {
impl<'a> DisplayListBuildState<'a> {
pub fn new(layout_context: &'a LayoutContext) -> DisplayListBuildState<'a> {
+ let root_clip_info = ClipAndScrollInfo::simple(layout_context.id.root_scroll_node());
DisplayListBuildState {
layout_context: layout_context,
root_stacking_context: StackingContext::root(layout_context.id),
@@ -204,8 +205,8 @@ impl<'a> DisplayListBuildState<'a> {
scroll_root_parents: HashMap::new(),
processing_scroll_root_element: false,
current_stacking_context_id: StackingContextId::root(),
- current_scroll_root_id: layout_context.id.root_scroll_node(),
- containing_block_scroll_root_id: layout_context.id.root_scroll_node(),
+ current_clip_and_scroll_info: root_clip_info,
+ containing_block_clip_and_scroll_info: root_clip_info,
iframe_sizes: Vec::new(),
clip_stack: Vec::new(),
containing_block_clip_stack: Vec::new(),
@@ -249,6 +250,12 @@ impl<'a> DisplayListBuildState<'a> {
*self.scroll_root_parents.get(&scroll_root_id).unwrap()
}
+ fn is_background_or_border_of_scroll_root(&self, section: DisplayListSection) -> bool {
+ (section == DisplayListSection::BackgroundAndBorders ||
+ section == DisplayListSection::BlockBackgroundsAndBorders) &&
+ self.processing_scroll_root_element
+ }
+
fn create_base_display_item(&self,
bounds: &Rect<Au>,
clip: LocalClip,
@@ -256,12 +263,10 @@ impl<'a> DisplayListBuildState<'a> {
cursor: Option<Cursor>,
section: DisplayListSection)
-> BaseDisplayItem {
- let scroll_root_id = if (section == DisplayListSection::BackgroundAndBorders ||
- section == DisplayListSection::BlockBackgroundsAndBorders) &&
- self.processing_scroll_root_element {
- self.parent_scroll_root_id(self.current_scroll_root_id)
+ let clip_and_scroll_info = if self.is_background_or_border_of_scroll_root(section) {
+ ClipAndScrollInfo::simple(self.parent_scroll_root_id(self.current_clip_and_scroll_info.scroll_node_id))
} else {
- self.current_scroll_root_id
+ self.current_clip_and_scroll_info
};
BaseDisplayItem::new(&bounds,
@@ -272,7 +277,7 @@ impl<'a> DisplayListBuildState<'a> {
clip,
section,
self.current_stacking_context_id,
- scroll_root_id)
+ clip_and_scroll_info)
}
pub fn to_display_list(mut self) -> DisplayList {
@@ -548,7 +553,7 @@ pub trait FragmentDisplayListBuilding {
base_flow: &BaseFlow,
scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode,
- parent_scroll_id: ClipId)
+ parent_clip_and_scroll_info: ClipAndScrollInfo)
-> StackingContext;
@@ -2029,7 +2034,7 @@ impl FragmentDisplayListBuilding for Fragment {
base_flow: &BaseFlow,
scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode,
- parent_scroll_id: ClipId)
+ parent_clip_and_scroll_info: ClipAndScrollInfo)
-> StackingContext {
let border_box =
self.stacking_relative_border_box(&base_flow.stacking_relative_position,
@@ -2069,7 +2074,7 @@ impl FragmentDisplayListBuilding for Fragment {
self.style().get_used_transform_style().to_transform_style(),
self.perspective_matrix(&border_box),
scroll_policy,
- parent_scroll_id)
+ parent_clip_and_scroll_info)
}
fn build_display_list_for_text_fragment(&self,
@@ -2255,7 +2260,7 @@ pub trait BlockFlowDisplayListBuilding {
state: &mut DisplayListBuildState,
preserved_state: &mut PreservedDisplayListState,
stacking_context_type: BlockStackingContextType)
- -> ClipId;
+ -> ClipAndScrollInfo;
fn setup_scroll_root_for_overflow(&mut self,
state: &mut DisplayListBuildState,
border_box: &Rect<Au>);
@@ -2265,11 +2270,11 @@ pub trait BlockFlowDisplayListBuilding {
stacking_relative_border_box: &Rect<Au>);
fn create_pseudo_stacking_context_for_block(&mut self,
parent_stacking_context_id: StackingContextId,
- parent_scroll_root_id: ClipId,
+ parent_clip_and_scroll_info: ClipAndScrollInfo,
state: &mut DisplayListBuildState);
fn create_real_stacking_context_for_block(&mut self,
parent_stacking_context_id: StackingContextId,
- parent_scroll_root_id: ClipId,
+ parent_clip_and_scroll_info: ClipAndScrollInfo,
state: &mut DisplayListBuildState);
fn build_display_list_for_block(&mut self,
state: &mut DisplayListBuildState,
@@ -2283,8 +2288,8 @@ pub trait BlockFlowDisplayListBuilding {
/// TODO(mrobinson): It would be nice to use RAII here to avoid having to call restore.
pub struct PreservedDisplayListState {
stacking_context_id: StackingContextId,
- scroll_root_id: ClipId,
- containing_block_scroll_root_id: ClipId,
+ clip_and_scroll_info: ClipAndScrollInfo,
+ containing_block_clip_and_scroll_info: ClipAndScrollInfo,
clips_pushed: usize,
containing_block_clips_pushed: usize,
transform_style: TransformStyle,
@@ -2294,8 +2299,8 @@ impl PreservedDisplayListState {
fn new(state: &mut DisplayListBuildState) -> PreservedDisplayListState {
PreservedDisplayListState {
stacking_context_id: state.current_stacking_context_id,
- scroll_root_id: state.current_scroll_root_id,
- containing_block_scroll_root_id: state.containing_block_scroll_root_id,
+ clip_and_scroll_info: state.current_clip_and_scroll_info,
+ containing_block_clip_and_scroll_info: state.containing_block_clip_and_scroll_info,
clips_pushed: 0,
containing_block_clips_pushed: 0,
transform_style: state.current_transform_style,
@@ -2310,8 +2315,8 @@ impl PreservedDisplayListState {
fn restore(self, state: &mut DisplayListBuildState) {
state.current_stacking_context_id = self.stacking_context_id;
- state.current_scroll_root_id = self.scroll_root_id;
- state.containing_block_scroll_root_id = self.containing_block_scroll_root_id;
+ state.current_clip_and_scroll_info = self.clip_and_scroll_info;
+ state.containing_block_clip_and_scroll_info = self.containing_block_clip_and_scroll_info;
let truncate_length = state.clip_stack.len() - self.clips_pushed;
state.clip_stack.truncate(truncate_length);
@@ -2417,14 +2422,12 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
// We are getting the id of the scroll root that contains us here, not the id of
// any scroll root that we create. If we create a scroll root, its id will be
- // stored in state.current_scroll_root_id. If we should create a stacking context,
- // we don't want it to be clipped by its own scroll root.
- let containing_scroll_root_id = self.setup_clipping_for_block(state,
- &mut preserved_state,
- block_stacking_context_type);
-
+ // stored in state.current_clip_and_scroll_info. If we create a stacking context,
+ // we don't want it to be contained by its own scroll root.
+ let containing_clip_and_scroll_info =
+ self.setup_clipping_for_block(state, &mut preserved_state, block_stacking_context_type);
if establishes_containing_block_for_absolute(self.positioning()) {
- state.containing_block_scroll_root_id = state.current_scroll_root_id;
+ state.containing_block_clip_and_scroll_info = state.current_clip_and_scroll_info;
}
match block_stacking_context_type {
@@ -2433,12 +2436,12 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
}
BlockStackingContextType::PseudoStackingContext => {
self.create_pseudo_stacking_context_for_block(preserved_state.stacking_context_id,
- containing_scroll_root_id,
+ containing_clip_and_scroll_info,
state);
}
BlockStackingContextType::StackingContext => {
self.create_real_stacking_context_for_block(preserved_state.stacking_context_id,
- containing_scroll_root_id,
+ containing_clip_and_scroll_info,
state);
}
}
@@ -2450,22 +2453,22 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
state: &mut DisplayListBuildState,
preserved_state: &mut PreservedDisplayListState,
stacking_context_type: BlockStackingContextType)
- -> ClipId {
+ -> ClipAndScrollInfo {
// If this block is absolutely positioned, we should be clipped and positioned by
// the scroll root of our nearest ancestor that establishes a containing block.
- let containing_scroll_root_id = match self.positioning() {
+ let containing_clip_and_scroll_info = match self.positioning() {
position::T::absolute => {
preserved_state.switch_to_containing_block_clip(state);
- state.current_scroll_root_id = state.containing_block_scroll_root_id;
- state.containing_block_scroll_root_id
+ state.current_clip_and_scroll_info = state.containing_block_clip_and_scroll_info;
+ state.containing_block_clip_and_scroll_info
}
position::T::fixed => {
preserved_state.push_clip(state, &max_rect(), position::T::fixed);
- state.current_scroll_root_id
+ state.current_clip_and_scroll_info
}
- _ => state.current_scroll_root_id,
+ _ => state.current_clip_and_scroll_info,
};
- self.base.scroll_root_id = Some(containing_scroll_root_id);
+ self.base.clip_and_scroll_info = Some(containing_clip_and_scroll_info);
let coordinate_system = if self.fragment.establishes_stacking_context() {
CoordinateSystem::Own
@@ -2489,11 +2492,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
match self.positioning() {
position::T::absolute | position::T::relative | position::T::fixed =>
- state.containing_block_scroll_root_id = state.current_scroll_root_id,
+ state.containing_block_clip_and_scroll_info = state.current_clip_and_scroll_info,
_ => {}
}
- containing_scroll_root_id
+ containing_clip_and_scroll_info
}
fn setup_scroll_root_for_overflow(&mut self,
@@ -2542,7 +2545,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
let content_size = self.base.overflow.scroll.origin + self.base.overflow.scroll.size;
let content_size = Size2D::new(content_size.x, content_size.y);
- let parent_id = self.scroll_root_id(state.layout_context.id);
+ let parent_id = self.clip_and_scroll_info(state.layout_context.id).scroll_node_id;
state.add_scroll_root(
ScrollRoot {
id: new_scroll_root_id,
@@ -2554,8 +2557,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
self.base.stacking_context_id
);
- self.base.scroll_root_id = Some(new_scroll_root_id);
- state.current_scroll_root_id = new_scroll_root_id;
+ let new_clip_and_scroll_info = ClipAndScrollInfo::simple(new_scroll_root_id);
+ self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info);
+ state.current_clip_and_scroll_info = new_clip_and_scroll_info;
}
/// Adds a scroll root for a block to take the `clip` property into account
@@ -2570,6 +2574,13 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
_ => return,
};
+ // CSS `clip` should only apply to position:absolute or positione:fixed elements.
+ // CSS Masking Appendix A: "Applies to: Absolutely positioned elements."
+ match self.positioning() {
+ position::T::absolute | position::T::fixed => {}
+ _ => return,
+ }
+
let clip_origin = Point2D::new(stacking_relative_border_box.origin.x +
style_clip_rect.left.unwrap_or(Au(0)),
stacking_relative_border_box.origin.y +
@@ -2595,7 +2606,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
let clip_rect = Rect::new(clip_origin, clip_size);
preserved_state.push_clip(state, &clip_rect, self.positioning());
- let parent_id = self.scroll_root_id(state.layout_context.id);
+ let parent_id = self.clip_and_scroll_info(state.layout_context.id).scroll_node_id;
state.add_scroll_root(
ScrollRoot {
id: new_scroll_root_id,
@@ -2607,13 +2618,14 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
self.base.stacking_context_id
);
- self.base.scroll_root_id = Some(new_scroll_root_id);
- state.current_scroll_root_id = new_scroll_root_id;
+ let new_clip_and_scroll_info = ClipAndScrollInfo::new(new_scroll_root_id, new_scroll_root_id);
+ self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info);
+ state.current_clip_and_scroll_info = new_clip_and_scroll_info;
}
fn create_pseudo_stacking_context_for_block(&mut self,
parent_stacking_context_id: StackingContextId,
- parent_scroll_root_id: ClipId,
+ parent_clip_and_scroll_info: ClipAndScrollInfo,
state: &mut DisplayListBuildState) {
let creation_mode = if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) ||
self.fragment.style.get_box().position != position::T::static_ {
@@ -2627,7 +2639,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
&self.base,
ScrollPolicy::Scrollable,
creation_mode,
- parent_scroll_root_id);
+ parent_clip_and_scroll_info);
state.add_stacking_context(parent_stacking_context_id, new_context);
self.base.collect_stacking_contexts_for_children(state);
@@ -2647,7 +2659,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
fn create_real_stacking_context_for_block(&mut self,
parent_stacking_context_id: StackingContextId,
- parent_scroll_root_id: ClipId,
+ parent_clip_and_scroll_info: ClipAndScrollInfo,
state: &mut DisplayListBuildState) {
let scroll_policy = if self.is_fixed() {
ScrollPolicy::Fixed
@@ -2660,7 +2672,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
&self.base,
scroll_policy,
StackingContextCreationMode::Normal,
- parent_scroll_root_id);
+ parent_clip_and_scroll_info);
state.add_stacking_context(parent_stacking_context_id, stacking_context);
self.base.collect_stacking_contexts_for_children(state);
@@ -2715,13 +2727,13 @@ pub trait InlineFlowDisplayListBuilding {
impl InlineFlowDisplayListBuilding for InlineFlow {
fn collect_stacking_contexts_for_inline(&mut self, state: &mut DisplayListBuildState) {
self.base.stacking_context_id = state.current_stacking_context_id;
- self.base.scroll_root_id = Some(state.current_scroll_root_id);
+ self.base.clip_and_scroll_info = Some(state.current_clip_and_scroll_info);
self.base.clip = state.clip_stack.last().cloned().unwrap_or_else(max_rect);
for mut fragment in self.fragments.fragments.iter_mut() {
- let previous_containing_block_scroll_root_id = state.containing_block_scroll_root_id;
+ let previous_cb_clip_scroll_info = state.containing_block_clip_and_scroll_info;
if establishes_containing_block_for_absolute(fragment.style.get_box().position) {
- state.containing_block_scroll_root_id = state.current_scroll_root_id;
+ state.containing_block_clip_and_scroll_info = state.current_clip_and_scroll_info;
}
match fragment.specific {
@@ -2745,14 +2757,14 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
&self.base,
ScrollPolicy::Scrollable,
StackingContextCreationMode::Normal,
- state.current_scroll_root_id);
+ state.current_clip_and_scroll_info);
state.add_stacking_context(current_stacking_context_id,
stacking_context);
}
_ => fragment.stacking_context_id = state.current_stacking_context_id,
}
- state.containing_block_scroll_root_id = previous_containing_block_scroll_root_id;
+ state.containing_block_clip_and_scroll_info = previous_cb_clip_scroll_info;
}
}
diff --git a/components/layout/flow.rs b/components/layout/flow.rs
index 846b7be8326..3ce36ad1a7c 100644
--- a/components/layout/flow.rs
+++ b/components/layout/flow.rs
@@ -63,7 +63,7 @@ use table_colgroup::TableColGroupFlow;
use table_row::TableRowFlow;
use table_rowgroup::TableRowGroupFlow;
use table_wrapper::TableWrapperFlow;
-use webrender_api::ClipId;
+use webrender_api::ClipAndScrollInfo;
/// Virtual methods that make up a float context.
///
@@ -431,12 +431,12 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
/// children of this flow.
fn print_extra_flow_children(&self, _: &mut PrintTree) { }
- fn scroll_root_id(&self, pipeline_id: PipelineId) -> ClipId {
- match base(self).scroll_root_id {
- Some(id) => id,
+ fn clip_and_scroll_info(&self, pipeline_id: PipelineId) -> ClipAndScrollInfo {
+ match base(self).clip_and_scroll_info {
+ Some(info) => info,
None => {
- warn!("Tried to access scroll root id on Flow before assignment");
- pipeline_id.root_scroll_node()
+ debug_assert!(false, "Tried to access scroll root id on Flow before assignment");
+ pipeline_id.root_clip_and_scroll_info()
}
}
}
@@ -969,7 +969,7 @@ pub struct BaseFlow {
/// list construction.
pub stacking_context_id: StackingContextId,
- pub scroll_root_id: Option<ClipId>,
+ pub clip_and_scroll_info: Option<ClipAndScrollInfo>,
}
impl fmt::Debug for BaseFlow {
@@ -1111,7 +1111,7 @@ impl BaseFlow {
writing_mode: writing_mode,
thread_id: 0,
stacking_context_id: StackingContextId::root(),
- scroll_root_id: None,
+ clip_and_scroll_info: None,
}
}
diff --git a/components/layout/table_colgroup.rs b/components/layout/table_colgroup.rs
index 97d0ef89022..10a87903403 100644
--- a/components/layout/table_colgroup.rs
+++ b/components/layout/table_colgroup.rs
@@ -94,10 +94,9 @@ impl Flow for TableColGroupFlow {
fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
self.base.stacking_context_id = state.current_stacking_context_id;
- self.base.scroll_root_id = Some(state.current_scroll_root_id);
+ self.base.clip_and_scroll_info = Some(state.current_clip_and_scroll_info);
}
-
fn repair_style(&mut self, _: &::ServoArc<ComputedValues>) {}
fn compute_overflow(&self) -> Overflow {
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs
index f821b4a2806..7ca56d22f9a 100644
--- a/components/layout/traversal.rs
+++ b/components/layout/traversal.rs
@@ -222,8 +222,9 @@ impl<'a> BuildDisplayList<'a> {
let parent_stacking_context_id = self.state.current_stacking_context_id;
self.state.current_stacking_context_id = flow::base(flow).stacking_context_id;
- let parent_scroll_root_id = self.state.current_scroll_root_id;
- self.state.current_scroll_root_id = flow.scroll_root_id(self.state.layout_context.id);
+ let parent_clip_and_scroll_info = self.state.current_clip_and_scroll_info;
+ self.state.current_clip_and_scroll_info =
+ flow.clip_and_scroll_info(self.state.layout_context.id);
if self.should_process() {
flow.build_display_list(&mut self.state);
@@ -235,7 +236,7 @@ impl<'a> BuildDisplayList<'a> {
}
self.state.current_stacking_context_id = parent_stacking_context_id;
- self.state.current_scroll_root_id = parent_scroll_root_id;
+ self.state.current_clip_and_scroll_info = parent_clip_and_scroll_info;
}
#[inline]
diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs
index d33638d08d2..13bde487675 100644
--- a/components/layout/webrender_helpers.rs
+++ b/components/layout/webrender_helpers.rs
@@ -16,8 +16,8 @@ use msg::constellation_msg::PipelineId;
use style::computed_values::{image_rendering, mix_blend_mode, transform_style};
use style::values::computed::{BorderStyle, Filter};
use style::values::generics::effects::Filter as GenericFilter;
-use webrender_api::{self, ClipId, ComplexClipRegion, DisplayListBuilder, ExtendMode};
-use webrender_api::LayoutTransform;
+use webrender_api::{self, ClipAndScrollInfo, ComplexClipRegion, DisplayListBuilder};
+use webrender_api::{ExtendMode, LayoutTransform};
pub trait WebRenderDisplayListConverter {
fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder;
@@ -26,7 +26,7 @@ pub trait WebRenderDisplayListConverter {
trait WebRenderDisplayItemConverter {
fn convert_to_webrender(&self,
builder: &mut DisplayListBuilder,
- current_scroll_root_id: &mut ClipId);
+ current_clip_and_scroll_info: &mut ClipAndScrollInfo);
}
trait ToBorderStyle {
@@ -222,16 +222,15 @@ impl ToTransformStyle for transform_style::T {
impl WebRenderDisplayListConverter for DisplayList {
fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder {
let traversal = DisplayListTraversal::new(self);
- let webrender_pipeline_id = pipeline_id.to_webrender();
- let mut builder = DisplayListBuilder::with_capacity(webrender_pipeline_id,
+ let mut builder = DisplayListBuilder::with_capacity(pipeline_id.to_webrender(),
self.bounds().size.to_sizef(),
1024 * 1024); // 1 MB of space
- let mut current_scroll_root_id = ClipId::root_scroll_node(webrender_pipeline_id);
- builder.push_clip_id(current_scroll_root_id);
+ let mut current_clip_and_scroll_info = pipeline_id.root_clip_and_scroll_info();
+ builder.push_clip_and_scroll_info(current_clip_and_scroll_info);
for item in traversal {
- item.convert_to_webrender(&mut builder, &mut current_scroll_root_id);
+ item.convert_to_webrender(&mut builder, &mut current_clip_and_scroll_info);
}
builder
}
@@ -240,12 +239,12 @@ impl WebRenderDisplayListConverter for DisplayList {
impl WebRenderDisplayItemConverter for DisplayItem {
fn convert_to_webrender(&self,
builder: &mut DisplayListBuilder,
- current_scroll_root_id: &mut ClipId) {
- let scroll_root_id = self.base().scroll_root_id;
- if scroll_root_id != *current_scroll_root_id {
+ current_clip_and_scroll_info: &mut ClipAndScrollInfo) {
+ let clip_and_scroll_info = self.base().clip_and_scroll_info;
+ if clip_and_scroll_info != *current_clip_and_scroll_info {
builder.pop_clip_id();
- builder.push_clip_id(scroll_root_id);
- *current_scroll_root_id = scroll_root_id;
+ builder.push_clip_and_scroll_info(clip_and_scroll_info);
+ *current_clip_and_scroll_info = clip_and_scroll_info;
}
match *self {
diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs
index 5522a324b08..0d7c10786d1 100644
--- a/components/msg/constellation_msg.rs
+++ b/components/msg/constellation_msg.rs
@@ -248,6 +248,10 @@ impl PipelineId {
pub fn root_scroll_node(&self) -> webrender_api::ClipId {
webrender_api::ClipId::root_scroll_node(self.to_webrender())
}
+
+ pub fn root_clip_and_scroll_info(&self) -> webrender_api::ClipAndScrollInfo {
+ webrender_api::ClipAndScrollInfo::simple(self.root_scroll_node())
+ }
}
impl fmt::Display for PipelineId {
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index 43f8f110edd..155f9a504d4 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -1583,6 +1583,18 @@
{}
]
],
+ "css/fixed_position_css_clip.html": [
+ [
+ "/_mozilla/css/fixed_position_css_clip.html",
+ [
+ [
+ "/_mozilla/css/fixed_position_css_clip_ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"css/fixed_width_overrides_child_intrinsic_width_a.html": [
[
"/_mozilla/css/fixed_width_overrides_child_intrinsic_width_a.html",
@@ -8179,6 +8191,11 @@
{}
]
],
+ "css/fixed_position_css_clip_ref.html": [
+ [
+ {}
+ ]
+ ],
"css/fixed_width_overrides_child_intrinsic_width_ref.html": [
[
{}
@@ -23064,6 +23081,14 @@
"fe23d2dc9a4507b3b632518a53f21900d0e4d1d7",
"support"
],
+ "css/fixed_position_css_clip.html": [
+ "2bf1fb572a72fbb4a7a35b8c8b08960b48ccf408",
+ "reftest"
+ ],
+ "css/fixed_position_css_clip_ref.html": [
+ "ad0341fc9f843177ccf53a1667b5016c234b7651",
+ "support"
+ ],
"css/fixed_width_overrides_child_intrinsic_width_a.html": [
"88cf78524712525ad4252c8a420c9b9f545b2621",
"reftest"
diff --git a/tests/wpt/mozilla/tests/css/fixed_position_css_clip.html b/tests/wpt/mozilla/tests/css/fixed_position_css_clip.html
new file mode 100644
index 00000000000..e8979e3b15f
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/fixed_position_css_clip.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fixed position elements should be clipped by parent CSS clips</title>
+ <link rel="match" href="fixed_position_css_clip_ref.html">
+ <style>
+ body {
+ margin: 0px;
+ }
+
+ #base {
+ position: absolute;
+ left; 0px;
+ top: 0px;
+ background: red;
+ width: 100px;
+ height: 100px;
+ clip: rect(0, auto, auto, 0);
+ }
+
+ #fixed {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: green;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="base">
+ <!-- Even though this fixed position child is positioned and clipped by the
+ containing block, it should also be clipped by the CSS clip of its
+ non-containing block parent. -->
+ <div id="fixed"></div>
+ </div>
+ </body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/fixed_position_css_clip_ref.html b/tests/wpt/mozilla/tests/css/fixed_position_css_clip_ref.html
new file mode 100644
index 00000000000..2eb73b74768
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/fixed_position_css_clip_ref.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fixed position elements should be clipped by parent CSS clips</title>
+ <style>
+ body {
+ margin: 0px;
+ }
+
+ #box {
+ left; 0px;
+ top: 0px;
+ background: green;
+ width: 100px;
+ height: 100px;
+ clip: rect(0, auto, auto, 0);
+ }
+ </style>
+ </head>
+ <body>
+ <div id="box">
+ </body>
+</html>