Auto merge of #16073 - glennw:update-wr-glfns, r=mrobinson

Update WR (gl trait, scroll roots)

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16073)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-03-23 03:43:49 -07:00 committed by GitHub
commit c99289a928
23 changed files with 385 additions and 337 deletions

View file

@ -2233,10 +2233,11 @@ impl Flow for BlockFlow {
fn compute_overflow(&self) -> Overflow {
let flow_size = self.base.position.size.to_physical(self.base.writing_mode);
self.fragment.compute_overflow(&flow_size,
let overflow = self.fragment.compute_overflow(&flow_size,
&self.base
.early_absolute_position_info
.relative_containing_block_size)
.relative_containing_block_size);
overflow
}
fn iterate_through_fragment_border_boxes(&self,

View file

@ -120,12 +120,31 @@ fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
&arr[index % arr.len()]
}
#[derive(Debug)]
struct StackingContextInfo {
children: Vec<StackingContext>,
scroll_roots: Vec<ScrollRoot>,
}
impl StackingContextInfo {
fn new() -> StackingContextInfo {
StackingContextInfo {
children: Vec::new(),
scroll_roots: Vec::new(),
}
}
fn take_children(&mut self) -> Vec<StackingContext> {
mem::replace(&mut self.children, Vec::new())
}
}
pub struct DisplayListBuildState<'a> {
pub layout_context: &'a LayoutContext<'a>,
pub root_stacking_context: StackingContext,
pub items: HashMap<StackingContextId, Vec<DisplayItem>>,
pub stacking_context_children: HashMap<StackingContextId, Vec<StackingContext>>,
pub scroll_roots: HashMap<ScrollRootId, ScrollRoot>,
stacking_context_info: HashMap<StackingContextId, StackingContextInfo>,
pub scroll_root_parents: HashMap<ScrollRootId, ScrollRootId>,
pub processing_scroll_root_element: bool,
/// The current stacking context id, used to keep track of state when building.
@ -147,8 +166,8 @@ impl<'a> DisplayListBuildState<'a> {
layout_context: layout_context,
root_stacking_context: StackingContext::root(),
items: HashMap::new(),
stacking_context_children: HashMap::new(),
scroll_roots: HashMap::new(),
stacking_context_info: HashMap::new(),
scroll_root_parents: HashMap::new(),
processing_scroll_root_element: false,
current_stacking_context_id: StackingContextId::root(),
current_scroll_root_id: ScrollRootId::root(),
@ -164,13 +183,18 @@ impl<'a> DisplayListBuildState<'a> {
fn add_stacking_context(&mut self,
parent_id: StackingContextId,
stacking_context: StackingContext) {
let contexts = self.stacking_context_children.entry(parent_id).or_insert(Vec::new());
contexts.push(stacking_context);
let info = self.stacking_context_info
.entry(parent_id)
.or_insert(StackingContextInfo::new());
info.children.push(stacking_context);
}
fn add_scroll_root(&mut self, scroll_root: ScrollRoot) {
debug_assert!(!self.scroll_roots.contains_key(&scroll_root.id));
self.scroll_roots.insert(scroll_root.id, scroll_root);
fn add_scroll_root(&mut self, scroll_root: ScrollRoot, stacking_context_id: StackingContextId) {
self.scroll_root_parents.insert(scroll_root.id, scroll_root.parent_id);
let info = self.stacking_context_info
.entry(stacking_context_id)
.or_insert(StackingContextInfo::new());
info.scroll_roots.push(scroll_root);
}
fn parent_scroll_root_id(&self, scroll_root_id: ScrollRootId) -> ScrollRootId {
@ -178,8 +202,8 @@ impl<'a> DisplayListBuildState<'a> {
return ScrollRootId::root()
}
debug_assert!(self.scroll_roots.contains_key(&scroll_root_id));
self.scroll_roots.get(&scroll_root_id).unwrap().parent_id
debug_assert!(self.scroll_root_parents.contains_key(&scroll_root_id));
*self.scroll_root_parents.get(&scroll_root_id).unwrap()
}
fn create_base_display_item(&self,
@ -209,13 +233,10 @@ impl<'a> DisplayListBuildState<'a> {
}
pub fn to_display_list(mut self) -> DisplayList {
let mut scroll_root_stack = Vec::new();
scroll_root_stack.push(ScrollRootId::root());
let mut list = Vec::new();
let root_context = mem::replace(&mut self.root_stacking_context, StackingContext::root());
self.to_display_list_for_stacking_context(&mut list, root_context, &mut scroll_root_stack);
self.to_display_list_for_stacking_context(&mut list, root_context);
DisplayList {
list: list,
@ -224,128 +245,75 @@ impl<'a> DisplayListBuildState<'a> {
fn to_display_list_for_stacking_context(&mut self,
list: &mut Vec<DisplayItem>,
stacking_context: StackingContext,
scroll_root_stack: &mut Vec<ScrollRootId>) {
stacking_context: StackingContext) {
let mut child_items = self.items.remove(&stacking_context.id).unwrap_or(Vec::new());
child_items.sort_by(|a, b| a.base().section.cmp(&b.base().section));
child_items.reverse();
let mut child_stacking_contexts =
self.stacking_context_children.remove(&stacking_context.id).unwrap_or_else(Vec::new);
child_stacking_contexts.sort();
let mut info = self.stacking_context_info.remove(&stacking_context.id)
.unwrap_or_else(StackingContextInfo::new);
let real_stacking_context = stacking_context.context_type == StackingContextType::Real;
if !real_stacking_context {
self.to_display_list_for_items(list,
child_items,
child_stacking_contexts,
scroll_root_stack);
return;
info.children.sort();
if stacking_context.context_type != StackingContextType::Real {
list.extend(info.scroll_roots.into_iter().map(|root| root.to_push()));
self.to_display_list_for_items(list, child_items, info.children);
} else {
let (push_item, pop_item) = stacking_context.to_display_list_items();
list.push(push_item);
list.extend(info.scroll_roots.into_iter().map(|root| root.to_push()));
self.to_display_list_for_items(list, child_items, info.children);
list.push(pop_item);
}
let mut scroll_root_stack = Vec::new();
scroll_root_stack.push(stacking_context.parent_scroll_id);
let (push_item, pop_item) = stacking_context.to_display_list_items();
list.push(push_item);
self.to_display_list_for_items(list,
child_items,
child_stacking_contexts,
&mut scroll_root_stack);
list.push(pop_item);
}
fn to_display_list_for_items(&mut self,
list: &mut Vec<DisplayItem>,
mut child_items: Vec<DisplayItem>,
child_stacking_contexts: Vec<StackingContext>,
scroll_root_stack: &mut Vec<ScrollRootId>) {
child_stacking_contexts: Vec<StackingContext>) {
// Properly order display items that make up a stacking context. "Steps" here
// refer to the steps in CSS 2.1 Appendix E.
// Steps 1 and 2: Borders and background for the root.
while child_items.last().map_or(false,
|child| child.section() == DisplayListSection::BackgroundAndBorders) {
let item = child_items.pop().unwrap();
self.switch_scroll_roots(list, item.scroll_root_id(), scroll_root_stack);
list.push(item);
list.push(child_items.pop().unwrap());
}
// Step 3: Positioned descendants with negative z-indices.
let mut child_stacking_contexts = child_stacking_contexts.into_iter().peekable();
while child_stacking_contexts.peek().map_or(false, |child| child.z_index < 0) {
let context = child_stacking_contexts.next().unwrap();
self.switch_scroll_roots(list, context.parent_scroll_id, scroll_root_stack);
self.to_display_list_for_stacking_context(list, context, scroll_root_stack);
self.to_display_list_for_stacking_context(list, context);
}
// Step 4: Block backgrounds and borders.
while child_items.last().map_or(false,
|child| child.section() == DisplayListSection::BlockBackgroundsAndBorders) {
let item = child_items.pop().unwrap();
self.switch_scroll_roots(list, item.scroll_root_id(), scroll_root_stack);
list.push(item);
list.push(child_items.pop().unwrap());
}
// Step 5: Floats.
while child_stacking_contexts.peek().map_or(false,
|child| child.context_type == StackingContextType::PseudoFloat) {
let context = child_stacking_contexts.next().unwrap();
self.switch_scroll_roots(list, context.parent_scroll_id, scroll_root_stack);
self.to_display_list_for_stacking_context(list, context, scroll_root_stack);
self.to_display_list_for_stacking_context(list, context);
}
// Step 6 & 7: Content and inlines that generate stacking contexts.
while child_items.last().map_or(false,
|child| child.section() == DisplayListSection::Content) {
let item = child_items.pop().unwrap();
self.switch_scroll_roots(list, item.scroll_root_id(), scroll_root_stack);
list.push(item);
list.push(child_items.pop().unwrap());
}
// Step 8 & 9: Positioned descendants with nonnegative, numeric z-indices.
for child in child_stacking_contexts {
self.switch_scroll_roots(list, child.parent_scroll_id, scroll_root_stack);
self.to_display_list_for_stacking_context(list, child, scroll_root_stack);
self.to_display_list_for_stacking_context(list, child);
}
// Step 10: Outlines.
for item in child_items.drain(..) {
self.switch_scroll_roots(list, item.scroll_root_id(), scroll_root_stack);
list.push(item);
}
for _ in scroll_root_stack.drain(1..) {
list.push(DisplayItem::PopScrollRoot(Box::new(BaseDisplayItem::empty())));
}
}
fn switch_scroll_roots(&self,
list: &mut Vec<DisplayItem>,
new_id: ScrollRootId,
scroll_root_stack: &mut Vec<ScrollRootId>) {
if new_id == *scroll_root_stack.last().unwrap() {
return;
}
if new_id == *scroll_root_stack.first().unwrap() {
for _ in scroll_root_stack.drain(1..) {
list.push(DisplayItem::PopScrollRoot(Box::new(BaseDisplayItem::empty())));
}
return;
}
// We never want to reach the root of the ScrollRoot tree without encountering the
// containing scroll root of this StackingContext. If this does happen we've tried to
// switch to a ScrollRoot that does not contain our current stacking context or isn't
// itself a direct child of our current stacking context. This should never happen
// due to CSS stacking rules.
debug_assert!(new_id != ScrollRootId::root());
let scroll_root = self.scroll_roots.get(&new_id).unwrap();
self.switch_scroll_roots(list, scroll_root.parent_id, scroll_root_stack);
scroll_root_stack.push(new_id);
list.push(scroll_root.to_push());
}
}
@ -507,6 +475,10 @@ pub trait FragmentDisplayListBuilding {
mode: StackingContextCreationMode,
parent_scroll_id: ScrollRootId)
-> StackingContext;
/// The id of stacking context this fragment would create.
fn stacking_context_id(&self) -> StackingContextId;
}
fn handle_overlapping_radii(size: &Size2D<Au>, radii: &BorderRadii<Au>) -> BorderRadii<Au> {
@ -1612,6 +1584,10 @@ impl FragmentDisplayListBuilding for Fragment {
}
}
fn stacking_context_id(&self) -> StackingContextId {
StackingContextId::new_of_type(self.node.id() as usize, self.fragment_type())
}
fn create_stacking_context(&self,
id: StackingContextId,
base_flow: &BaseFlow,
@ -1858,14 +1834,12 @@ impl FragmentDisplayListBuilding for Fragment {
pub trait BlockFlowDisplayListBuilding {
fn collect_stacking_contexts_for_block(&mut self, state: &mut DisplayListBuildState);
fn collect_scroll_root_for_block(&mut self, state: &mut DisplayListBuildState) -> ScrollRootId;
fn setup_scroll_root_for_block(&mut self, state: &mut DisplayListBuildState) -> ScrollRootId;
fn create_pseudo_stacking_context_for_block(&mut self,
stacking_context_id: StackingContextId,
parent_stacking_context_id: StackingContextId,
parent_scroll_root_id: ScrollRootId,
state: &mut DisplayListBuildState);
fn create_real_stacking_context_for_block(&mut self,
stacking_context_id: StackingContextId,
parent_stacking_context_id: StackingContextId,
parent_scroll_root_id: ScrollRootId,
state: &mut DisplayListBuildState);
@ -1876,43 +1850,49 @@ pub trait BlockFlowDisplayListBuilding {
impl BlockFlowDisplayListBuilding for BlockFlow {
fn collect_stacking_contexts_for_block(&mut self, state: &mut DisplayListBuildState) {
let parent_scroll_root_id = state.current_scroll_root_id;
self.base.scroll_root_id = self.collect_scroll_root_for_block(state);
state.current_scroll_root_id = self.base.scroll_root_id;
let parent_stacking_context_id = state.current_stacking_context_id;
let block_stacking_context_type = self.block_stacking_context_type();
if block_stacking_context_type == BlockStackingContextType::NonstackingContext {
self.base.stacking_context_id = state.current_stacking_context_id;
self.base.collect_stacking_contexts_for_children(state);
} else {
let parent_stacking_context_id = state.current_stacking_context_id;
let stacking_context_id =
StackingContextId::new_of_type(self.fragment.node.id() as usize,
self.fragment.fragment_type());
state.current_stacking_context_id = stacking_context_id;
self.base.stacking_context_id = stacking_context_id;
self.base.stacking_context_id = match block_stacking_context_type {
BlockStackingContextType::NonstackingContext => state.current_stacking_context_id,
BlockStackingContextType::PseudoStackingContext |
BlockStackingContextType::StackingContext => self.fragment.stacking_context_id(),
};
state.current_stacking_context_id = self.base.stacking_context_id;
if block_stacking_context_type == BlockStackingContextType::PseudoStackingContext {
self.create_pseudo_stacking_context_for_block(stacking_context_id,
parent_stacking_context_id,
parent_scroll_root_id,
let original_scroll_root_id = state.current_scroll_root_id;
// 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_scroll_root_for_block(state);
match block_stacking_context_type {
BlockStackingContextType::NonstackingContext => {
self.base.collect_stacking_contexts_for_children(state);
}
BlockStackingContextType::PseudoStackingContext => {
self.create_pseudo_stacking_context_for_block(parent_stacking_context_id,
containing_scroll_root_id,
state);
} else {
self.create_real_stacking_context_for_block(stacking_context_id,
parent_stacking_context_id,
parent_scroll_root_id,
}
BlockStackingContextType::StackingContext => {
self.create_real_stacking_context_for_block(parent_stacking_context_id,
containing_scroll_root_id,
state);
}
state.current_stacking_context_id = parent_stacking_context_id;
}
state.current_scroll_root_id = parent_scroll_root_id;
state.current_scroll_root_id = original_scroll_root_id;
state.current_stacking_context_id = parent_stacking_context_id;
}
fn collect_scroll_root_for_block(&mut self, state: &mut DisplayListBuildState) -> ScrollRootId {
fn setup_scroll_root_for_block(&mut self, state: &mut DisplayListBuildState) -> ScrollRootId {
let containing_scroll_root_id = state.current_scroll_root_id;
self.base.scroll_root_id = containing_scroll_root_id;
if !self.style_permits_scrolling_overflow() {
return state.current_scroll_root_id;
return containing_scroll_root_id;
}
let coordinate_system = if self.fragment.establishes_stacking_context() {
@ -1933,25 +1913,27 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
self.base.overflow.scroll.size.height > clip.size.height;
self.mark_scrolling_overflow(has_scrolling_overflow);
if !has_scrolling_overflow {
return state.current_scroll_root_id;
return containing_scroll_root_id;
}
let scroll_root_id = ScrollRootId::new_of_type(self.fragment.node.id() as usize,
self.fragment.fragment_type());
let parent_scroll_root_id = state.current_scroll_root_id;
let new_scroll_root_id = ScrollRootId::new_of_type(self.fragment.node.id() as usize,
self.fragment.fragment_type());
state.add_scroll_root(
ScrollRoot {
id: scroll_root_id,
parent_id: parent_scroll_root_id,
id: new_scroll_root_id,
parent_id: containing_scroll_root_id,
clip: clip,
size: self.base.overflow.scroll.size,
}
},
self.base.stacking_context_id
);
scroll_root_id
self.base.scroll_root_id = new_scroll_root_id;
state.current_scroll_root_id = new_scroll_root_id;
containing_scroll_root_id
}
fn create_pseudo_stacking_context_for_block(&mut self,
stacking_context_id: StackingContextId,
parent_stacking_context_id: StackingContextId,
parent_scroll_root_id: ScrollRootId,
state: &mut DisplayListBuildState) {
@ -1963,7 +1945,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
StackingContextCreationMode::PseudoFloat
};
let new_context = self.fragment.create_stacking_context(stacking_context_id,
let new_context = self.fragment.create_stacking_context(self.base.stacking_context_id,
&self.base,
ScrollPolicy::Scrollable,
creation_mode,
@ -1972,19 +1954,20 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
self.base.collect_stacking_contexts_for_children(state);
let new_children =
state.stacking_context_children.remove(&stacking_context_id).unwrap_or_else(Vec::new);
for child in new_children {
if child.context_type == StackingContextType::PseudoFloat {
state.add_stacking_context(stacking_context_id, child);
} else {
state.add_stacking_context(parent_stacking_context_id, child);
let children = state.stacking_context_info.get_mut(&self.base.stacking_context_id)
.map(|info| info.take_children());
if let Some(children) = children {
for child in children {
if child.context_type == StackingContextType::PseudoFloat {
state.add_stacking_context(self.base.stacking_context_id, child);
} else {
state.add_stacking_context(parent_stacking_context_id, child);
}
}
}
}
fn create_real_stacking_context_for_block(&mut self,
stacking_context_id: StackingContextId,
parent_stacking_context_id: StackingContextId,
parent_scroll_root_id: ScrollRootId,
state: &mut DisplayListBuildState) {
@ -1995,7 +1978,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
};
let stacking_context = self.fragment.create_stacking_context(
stacking_context_id,
self.base.stacking_context_id,
&self.base,
scroll_policy,
StackingContextCreationMode::Normal,

View file

@ -16,14 +16,16 @@ use msg::constellation_msg::PipelineId;
use style::computed_values::{image_rendering, mix_blend_mode};
use style::computed_values::filter::{self, Filter};
use style::values::computed::BorderStyle;
use webrender_traits::{self, DisplayListBuilder, ExtendMode, LayoutTransform};
use webrender_traits::{self, DisplayListBuilder, ExtendMode, LayoutTransform, ScrollLayerId};
pub trait WebRenderDisplayListConverter {
fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder;
}
trait WebRenderDisplayItemConverter {
fn convert_to_webrender(&self, builder: &mut DisplayListBuilder);
fn convert_to_webrender(&self,
builder: &mut DisplayListBuilder,
current_scroll_root_id: &mut ScrollRootId);
}
trait ToBorderStyle {
@ -212,16 +214,31 @@ impl ToFilterOps for filter::T {
impl WebRenderDisplayListConverter for DisplayList {
fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder {
let traversal = DisplayListTraversal::new(self);
let mut builder = DisplayListBuilder::new(pipeline_id.to_webrender());
let webrender_pipeline_id = pipeline_id.to_webrender();
let mut builder = DisplayListBuilder::new(webrender_pipeline_id);
let mut current_scroll_root_id = ScrollRootId::root();
builder.push_clip_id(current_scroll_root_id.convert_to_webrender(webrender_pipeline_id));
for item in traversal {
item.convert_to_webrender(&mut builder);
item.convert_to_webrender(&mut builder, &mut current_scroll_root_id);
}
builder
}
}
impl WebRenderDisplayItemConverter for DisplayItem {
fn convert_to_webrender(&self, builder: &mut DisplayListBuilder) {
fn convert_to_webrender(&self,
builder: &mut DisplayListBuilder,
current_scroll_root_id: &mut ScrollRootId) {
let scroll_root_id = self.base().scroll_root_id;
if scroll_root_id != *current_scroll_root_id {
let pipeline_id = builder.pipeline_id;
builder.pop_clip_id();
builder.push_clip_id(scroll_root_id.convert_to_webrender(pipeline_id));
*current_scroll_root_id = scroll_root_id;
}
match *self {
DisplayItem::SolidColor(ref item) => {
let color = item.color;
@ -403,21 +420,26 @@ impl WebRenderDisplayItemConverter for DisplayItem {
vec![],
None);
builder.push_scroll_layer(clip,
item.scroll_root.size.to_sizef(),
Some(item.scroll_root.id.convert_to_webrender()));
let provided_id = ScrollLayerId::new(item.scroll_root.id.0, builder.pipeline_id);
let id = builder.define_clip(clip,
item.scroll_root.size.to_sizef(),
Some(provided_id));
debug_assert!(provided_id == id);
}
DisplayItem::PopScrollRoot(_) => builder.pop_scroll_layer(),
DisplayItem::PopScrollRoot(_) => {} //builder.pop_scroll_layer(),
}
}
}
trait WebRenderScrollRootIdConverter {
fn convert_to_webrender(&self) -> webrender_traits::ServoScrollRootId;
fn convert_to_webrender(&self, pipeline_id: webrender_traits::PipelineId) -> ScrollLayerId;
}
impl WebRenderScrollRootIdConverter for ScrollRootId {
fn convert_to_webrender(&self) -> webrender_traits::ServoScrollRootId {
webrender_traits::ServoScrollRootId(self.0)
fn convert_to_webrender(&self, pipeline_id: webrender_traits::PipelineId) -> ScrollLayerId {
if *self == ScrollRootId::root() {
ScrollLayerId::root_scroll_layer(pipeline_id)
} else {
ScrollLayerId::new(self.0, pipeline_id)
}
}
}