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.
This commit is contained in:
Martin Robinson 2017-07-27 11:25:59 +02:00
parent 46f6e68bad
commit daf638bc3f
11 changed files with 214 additions and 106 deletions

View file

@ -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));

View file

@ -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 {

View file

@ -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;
}
}

View file

@ -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,
}
}

View file

@ -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 {

View file

@ -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]

View file

@ -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 {

View file

@ -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 {

View file

@ -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"

View file

@ -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>

View file

@ -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>