Simplify stacking context creation

Have Fragment::create_stacking_context understand which stacking
contexts need layers and which do not. This simplifies the way it is
called and eliminates a bunch of code.
This commit is contained in:
Martin Robinson 2015-09-30 15:41:21 -07:00
parent fb6d0946cb
commit 1a494b1a73
3 changed files with 67 additions and 94 deletions

View file

@ -50,7 +50,7 @@ use layout_debug;
use layout_task::DISPLAY_PORT_SIZE_FACTOR;
use model::{CollapsibleMargins, MaybeAuto, specified, specified_or_none};
use model::{IntrinsicISizes, MarginCollapseInfo};
use msg::compositor_msg::{LayerId, LayerType};
use msg::compositor_msg::LayerId;
use rustc_serialize::{Encodable, Encoder};
use std::cmp::{max, min};
use std::fmt;
@ -63,7 +63,6 @@ use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use util::geometry::{Au, MAX_AU, MAX_RECT};
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
use util::opts;
use wrapper::PseudoElementType;
/// Information specific to floated blocks.
#[derive(Clone, RustcEncodable)]
@ -2076,16 +2075,11 @@ impl Flow for BlockFlow {
}
fn layer_id(&self) -> LayerId {
let layer_type = match self.fragment.pseudo {
PseudoElementType::Normal => LayerType::FragmentBody,
PseudoElementType::Before(_) => LayerType::BeforePseudoContent,
PseudoElementType::After(_) => LayerType::AfterPseudoContent
};
LayerId::new_of_type(layer_type, self.fragment.node.id() as usize)
self.fragment.layer_id()
}
fn layer_id_for_overflow_scroll(&self) -> LayerId {
LayerId::new_of_type(LayerType::OverflowScroll, self.fragment.node.id() as usize)
self.fragment.layer_id_for_overflow_scroll()
}
fn is_absolute_containing_block(&self) -> bool {

View file

@ -34,7 +34,7 @@ use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
use ipc_channel::ipc::{self, IpcSharedMemory};
use list_item::ListItemFlow;
use model::{self, MaybeAuto, ToGfxMatrix};
use msg::compositor_msg::{LayerId, ScrollPolicy, SubpageLayerInfo};
use msg::compositor_msg::{ScrollPolicy, SubpageLayerInfo};
use net_traits::image::base::{Image, PixelFormat};
use net_traits::image_cache_task::UsePlaceholder;
use std::default::Default;
@ -64,12 +64,6 @@ use util::range::Range;
/// The logical width of an insertion point: at the moment, a one-pixel-wide line.
const INSERTION_POINT_LOGICAL_WIDTH: Au = Au(1 * AU_PER_PX);
/// Whether a stacking context needs a layer or not.
pub enum StackingContextLayerNecessity {
Always(LayerId, ScrollPolicy),
IfCanvasOrIframe(LayerId),
}
/// The results of display list building for a single flow.
pub enum DisplayListBuildingResult {
None,
@ -257,7 +251,7 @@ pub trait FragmentDisplayListBuilding {
base_flow: &BaseFlow,
display_list: Box<DisplayList>,
layout_context: &LayoutContext,
needs_layer: StackingContextLayerNecessity,
scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode)
-> Arc<StackingContext>;
}
@ -1171,7 +1165,7 @@ impl FragmentDisplayListBuilding for Fragment {
base_flow: &BaseFlow,
display_list: Box<DisplayList>,
layout_context: &LayoutContext,
needs_layer: StackingContextLayerNecessity,
scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode)
-> Arc<StackingContext> {
let border_box = match mode {
@ -1284,24 +1278,23 @@ impl FragmentDisplayListBuilding for Fragment {
filters.push(Filter::Opacity(effects.opacity))
}
// Ensure every canvas or iframe has a layer.
let (scroll_policy, layer_id) = match needs_layer {
StackingContextLayerNecessity::Always(layer_id, scroll_policy) => {
(scroll_policy, Some(layer_id))
}
StackingContextLayerNecessity::IfCanvasOrIframe(layer_id) => {
// FIXME(pcwalton): So so bogus :(
match self.specific {
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => {
(ScrollPolicy::Scrollable, Some(layer_id))
}
_ => (ScrollPolicy::Scrollable, None),
}
}
let canvas_or_iframe = match self.specific {
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => true,
_ => false
};
// If it's a canvas we must propagate the layer and the renderer to the paint
// task
// There are three situations that need layers: when the fragment has the HAS_LAYER
// flag, when this is a canvas or iframe fragment, and when we are building a layer
// tree for overflow scrolling.
let layer_id = if mode == StackingContextCreationMode::InnerScrollWrapper {
Some(self.layer_id_for_overflow_scroll())
} else if self.flags.contains(HAS_LAYER) || canvas_or_iframe {
Some(self.layer_id())
} else {
None
};
// If it's a canvas we must propagate the layer and the renderer to the paint task.
if let SpecificFragmentInfo::Canvas(ref fragment_info) = self.specific {
let layer_id = layer_id.unwrap();
if let Some(ref ipc_renderer) = fragment_info.ipc_renderer {
@ -1585,27 +1578,19 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
border_painting_mode,
background_border_level);
self.base.display_list_building_result = if self.fragment.flags.contains(HAS_LAYER) {
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
let scroll_policy = if self.is_fixed() {
ScrollPolicy::FixedPosition
} else {
ScrollPolicy::Scrollable
};
let stacking_context = self.fragment.create_stacking_context(
&self.base,
display_list,
layout_context,
StackingContextLayerNecessity::Always(self.layer_id(), scroll_policy),
StackingContextCreationMode::Normal);
DisplayListBuildingResult::StackingContext(stacking_context)
} else if self.fragment.establishes_stacking_context() {
DisplayListBuildingResult::StackingContext(
self.fragment.create_stacking_context(
&self.base,
display_list,
layout_context,
StackingContextLayerNecessity::IfCanvasOrIframe(self.layer_id()),
scroll_policy,
StackingContextCreationMode::Normal))
} else {
match self.fragment.style.get_box().position {
@ -1670,22 +1655,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
}
};
if !self.fragment.flags.contains(HAS_LAYER) {
if !self.fragment.establishes_stacking_context() {
display_list.form_pseudo_stacking_context_for_positioned_content();
self.base.display_list_building_result =
DisplayListBuildingResult::Normal(display_list);
} else {
self.base.display_list_building_result =
DisplayListBuildingResult::StackingContext(
self.fragment.create_stacking_context(
&self.base,
display_list,
layout_context,
StackingContextLayerNecessity::IfCanvasOrIframe(self.layer_id()),
StackingContextCreationMode::Normal));
}
return
if !self.fragment.flags.contains(HAS_LAYER) && !self.fragment.establishes_stacking_context() {
display_list.form_pseudo_stacking_context_for_positioned_content();
self.base.display_list_building_result =
DisplayListBuildingResult::Normal(display_list);
return;
}
// If we got here, then we need a new layer.
@ -1695,40 +1669,33 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
ScrollPolicy::Scrollable
};
let stacking_context_creation_mode = if outer_display_list_for_overflow_scroll.is_some() {
StackingContextCreationMode::InnerScrollWrapper
} else {
StackingContextCreationMode::Normal
};
let layer_id = if outer_display_list_for_overflow_scroll.is_some() {
self.layer_id_for_overflow_scroll()
} else {
self.layer_id()
};
let stacking_context = self.fragment.create_stacking_context(
&self.base,
display_list,
layout_context,
StackingContextLayerNecessity::Always(layer_id, scroll_policy),
stacking_context_creation_mode);
let outermost_stacking_context = match outer_display_list_for_overflow_scroll {
Some(mut outer_display_list_for_overflow_scroll) => {
outer_display_list_for_overflow_scroll.children.push_back(stacking_context);
let stacking_context = match outer_display_list_for_overflow_scroll {
Some(mut outer_display_list) => {
outer_display_list.children.push_back(self.fragment.create_stacking_context(
&self.base,
display_list,
layout_context,
scroll_policy,
StackingContextCreationMode::InnerScrollWrapper));
self.fragment.create_stacking_context(
&self.base,
outer_display_list_for_overflow_scroll,
outer_display_list,
layout_context,
StackingContextLayerNecessity::Always(self.layer_id(), scroll_policy),
scroll_policy,
StackingContextCreationMode::OuterScrollWrapper)
}
None => stacking_context,
None => {
self.fragment.create_stacking_context(
&self.base,
display_list,
layout_context,
scroll_policy,
StackingContextCreationMode::Normal)
}
};
self.base.display_list_building_result =
DisplayListBuildingResult::StackingContext(outermost_stacking_context)
DisplayListBuildingResult::StackingContext(stacking_context)
}
fn build_display_list_for_floating_block(&mut self,
@ -1743,12 +1710,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
DisplayListBuildingResult::StackingContext(
self.fragment.create_stacking_context(
&self.base,
display_list,
layout_context,
StackingContextLayerNecessity::IfCanvasOrIframe(self.layer_id()),
StackingContextCreationMode::Normal))
self.fragment.create_stacking_context(&self.base,
display_list,
layout_context,
ScrollPolicy::Scrollable,
StackingContextCreationMode::Normal))
} else {
DisplayListBuildingResult::Normal(display_list)
}
@ -1851,8 +1817,7 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
&self.base,
display_list,
layout_context,
StackingContextLayerNecessity::Always(self.layer_id(),
ScrollPolicy::Scrollable),
ScrollPolicy::Scrollable,
StackingContextCreationMode::Normal))
} else {
DisplayListBuildingResult::Normal(display_list)

View file

@ -22,6 +22,7 @@ use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT};
use ipc_channel::ipc::IpcSender;
use layout_debug;
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
use msg::compositor_msg::{LayerId, LayerType};
use msg::constellation_msg::{PipelineId, SubpageId};
use net_traits::image::base::Image;
use net_traits::image_cache_task::UsePlaceholder;
@ -2423,6 +2424,19 @@ impl Fragment {
}
}
}
pub fn layer_id(&self) -> LayerId {
let layer_type = match self.pseudo {
PseudoElementType::Normal => LayerType::FragmentBody,
PseudoElementType::Before(_) => LayerType::BeforePseudoContent,
PseudoElementType::After(_) => LayerType::AfterPseudoContent
};
LayerId::new_of_type(layer_type, self.node.id() as usize)
}
pub fn layer_id_for_overflow_scroll(&self) -> LayerId {
LayerId::new_of_type(LayerType::OverflowScroll, self.node.id() as usize)
}
}
impl fmt::Debug for Fragment {