mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
layout: Rewrite clipping to be per-display-item instead of having
a separate `ClipDisplayItem`. We push down clipping areas during absolute position calculation. This makes display items into a flat list, improving cache locality. It dramatically simplifies the code all around. Because we need to push down clip rects even for absolutely-positioned children of non-absolutely-positioned flows, this patch alters the parallel traversal to compute absolute positions for absolutely-positioned children at the same time it computes absolute positions for other children. This doesn't seem to break anything either in theory (since the overall order remains correct) or in practice. It simplifies the parallel traversal code quite a bit. See the relevant Gecko bug: https://bugzilla.mozilla.org/show_bug.cgi?id=615734
This commit is contained in:
parent
f350879574
commit
bffaad118e
12 changed files with 312 additions and 487 deletions
|
@ -196,15 +196,6 @@ impl StackingContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
for item in list.into_iter() {
|
for item in list.into_iter() {
|
||||||
match item {
|
|
||||||
ClipDisplayItemClass(box ClipDisplayItem {
|
|
||||||
base: base,
|
|
||||||
children: sublist
|
|
||||||
}) => {
|
|
||||||
let sub_stacking_context = StackingContext::new(sublist);
|
|
||||||
stacking_context.merge_with_clip(sub_stacking_context, &base.bounds, base.node)
|
|
||||||
}
|
|
||||||
item => {
|
|
||||||
match item.base().level {
|
match item.base().level {
|
||||||
BackgroundAndBordersStackingLevel => {
|
BackgroundAndBordersStackingLevel => {
|
||||||
stacking_context.background_and_borders.push(item)
|
stacking_context.background_and_borders.push(item)
|
||||||
|
@ -231,58 +222,9 @@ impl StackingContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stacking_context
|
stacking_context
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merges another stacking context into this one, with the given clipping rectangle and DOM
|
|
||||||
/// node that supplies it.
|
|
||||||
fn merge_with_clip(&mut self,
|
|
||||||
other: StackingContext,
|
|
||||||
clip_rect: &Rect<Au>,
|
|
||||||
clipping_dom_node: OpaqueNode) {
|
|
||||||
let StackingContext {
|
|
||||||
background_and_borders,
|
|
||||||
block_backgrounds_and_borders,
|
|
||||||
floats,
|
|
||||||
content,
|
|
||||||
positioned_descendants: positioned_descendants
|
|
||||||
} = other;
|
|
||||||
|
|
||||||
let push = |destination: &mut DisplayList, source: DisplayList, level| {
|
|
||||||
if !source.is_empty() {
|
|
||||||
let base = BaseDisplayItem::new(*clip_rect, clipping_dom_node, level);
|
|
||||||
destination.push(ClipDisplayItemClass(box ClipDisplayItem::new(base, source)))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
push(&mut self.background_and_borders,
|
|
||||||
background_and_borders,
|
|
||||||
BackgroundAndBordersStackingLevel);
|
|
||||||
push(&mut self.block_backgrounds_and_borders,
|
|
||||||
block_backgrounds_and_borders,
|
|
||||||
BlockBackgroundsAndBordersStackingLevel);
|
|
||||||
push(&mut self.floats, floats, FloatStackingLevel);
|
|
||||||
push(&mut self.content, content, ContentStackingLevel);
|
|
||||||
|
|
||||||
for (z_index, list) in positioned_descendants.into_iter() {
|
|
||||||
match self.positioned_descendants
|
|
||||||
.iter_mut()
|
|
||||||
.find(|& &(existing_z_index, _)| z_index == existing_z_index) {
|
|
||||||
Some(&(_, ref mut existing_list)) => {
|
|
||||||
push(existing_list, list, PositionedDescendantStackingLevel(z_index));
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut new_list = DisplayList::new();
|
|
||||||
push(&mut new_list, list, PositionedDescendantStackingLevel(z_index));
|
|
||||||
self.positioned_descendants.push((z_index, new_list));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which level to place backgrounds and borders in.
|
/// Which level to place backgrounds and borders in.
|
||||||
|
@ -342,11 +284,13 @@ impl DisplayList {
|
||||||
|
|
||||||
/// Draws the display list into the given render context. The display list must be flattened
|
/// Draws the display list into the given render context. The display list must be flattened
|
||||||
/// first for correct painting.
|
/// first for correct painting.
|
||||||
pub fn draw_into_context(&self, render_context: &mut RenderContext,
|
pub fn draw_into_context(&self,
|
||||||
current_transform: &Matrix2D<AzFloat>) {
|
render_context: &mut RenderContext,
|
||||||
|
current_transform: &Matrix2D<AzFloat>,
|
||||||
|
current_clip_rect: &Rect<Au>) {
|
||||||
debug!("Beginning display list.");
|
debug!("Beginning display list.");
|
||||||
for item in self.list.iter() {
|
for item in self.list.iter() {
|
||||||
item.draw_into_context(render_context, current_transform)
|
item.draw_into_context(render_context, current_transform, current_clip_rect)
|
||||||
}
|
}
|
||||||
debug!("Ending display list.");
|
debug!("Ending display list.");
|
||||||
}
|
}
|
||||||
|
@ -356,12 +300,6 @@ impl DisplayList {
|
||||||
ParentDisplayItemIterator(self.list.iter())
|
ParentDisplayItemIterator(self.list.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this list is empty and false otherwise.
|
|
||||||
#[inline]
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.list.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Flattens a display list into a display list with a single stacking level according to the
|
/// Flattens a display list into a display list with a single stacking level according to the
|
||||||
/// steps in CSS 2.1 § E.2.
|
/// steps in CSS 2.1 § E.2.
|
||||||
///
|
///
|
||||||
|
@ -421,10 +359,6 @@ impl DisplayList {
|
||||||
fn set_stacking_level(&mut self, new_level: StackingLevel) {
|
fn set_stacking_level(&mut self, new_level: StackingLevel) {
|
||||||
for item in self.list.iter_mut() {
|
for item in self.list.iter_mut() {
|
||||||
item.mut_base().level = new_level;
|
item.mut_base().level = new_level;
|
||||||
match item.mut_sublist() {
|
|
||||||
None => {}
|
|
||||||
Some(sublist) => sublist.set_stacking_level(new_level),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,7 +371,6 @@ pub enum DisplayItem {
|
||||||
ImageDisplayItemClass(Box<ImageDisplayItem>),
|
ImageDisplayItemClass(Box<ImageDisplayItem>),
|
||||||
BorderDisplayItemClass(Box<BorderDisplayItem>),
|
BorderDisplayItemClass(Box<BorderDisplayItem>),
|
||||||
LineDisplayItemClass(Box<LineDisplayItem>),
|
LineDisplayItemClass(Box<LineDisplayItem>),
|
||||||
ClipDisplayItemClass(Box<ClipDisplayItem>),
|
|
||||||
|
|
||||||
/// A pseudo-display item that exists only so that queries like `ContentBoxQuery` and
|
/// A pseudo-display item that exists only so that queries like `ContentBoxQuery` and
|
||||||
/// `ContentBoxesQuery` can be answered.
|
/// `ContentBoxesQuery` can be answered.
|
||||||
|
@ -450,9 +383,7 @@ pub enum DisplayItem {
|
||||||
/// Information common to all display items.
|
/// Information common to all display items.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct BaseDisplayItem {
|
pub struct BaseDisplayItem {
|
||||||
/// The boundaries of the display item.
|
/// The boundaries of the display item, in layer coordinates.
|
||||||
///
|
|
||||||
/// TODO: Which coordinate system should this use?
|
|
||||||
pub bounds: Rect<Au>,
|
pub bounds: Rect<Au>,
|
||||||
|
|
||||||
/// The originating DOM node.
|
/// The originating DOM node.
|
||||||
|
@ -460,14 +391,22 @@ pub struct BaseDisplayItem {
|
||||||
|
|
||||||
/// The stacking level in which this display item lives.
|
/// The stacking level in which this display item lives.
|
||||||
pub level: StackingLevel,
|
pub level: StackingLevel,
|
||||||
|
|
||||||
|
/// The rectangle to clip to.
|
||||||
|
///
|
||||||
|
/// TODO(pcwalton): Eventually, to handle `border-radius`, this will (at least) need to grow
|
||||||
|
/// the ability to describe rounded rectangles.
|
||||||
|
pub clip_rect: Rect<Au>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BaseDisplayItem {
|
impl BaseDisplayItem {
|
||||||
pub fn new(bounds: Rect<Au>, node: OpaqueNode, level: StackingLevel) -> BaseDisplayItem {
|
pub fn new(bounds: Rect<Au>, node: OpaqueNode, level: StackingLevel, clip_rect: Rect<Au>)
|
||||||
|
-> BaseDisplayItem {
|
||||||
BaseDisplayItem {
|
BaseDisplayItem {
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
node: node,
|
node: node,
|
||||||
level: level,
|
level: level,
|
||||||
|
clip_rect: clip_rect,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -544,25 +483,6 @@ pub struct LineDisplayItem {
|
||||||
pub style: border_style::T
|
pub style: border_style::T
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clips a list of child display items to this display item's boundaries.
|
|
||||||
#[deriving(Clone)]
|
|
||||||
pub struct ClipDisplayItem {
|
|
||||||
/// The base information.
|
|
||||||
pub base: BaseDisplayItem,
|
|
||||||
|
|
||||||
/// The child nodes.
|
|
||||||
pub children: DisplayList,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClipDisplayItem {
|
|
||||||
pub fn new(base: BaseDisplayItem, children: DisplayList) -> ClipDisplayItem {
|
|
||||||
ClipDisplayItem {
|
|
||||||
base: base,
|
|
||||||
children: children,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum DisplayItemIterator<'a> {
|
pub enum DisplayItemIterator<'a> {
|
||||||
EmptyDisplayItemIterator,
|
EmptyDisplayItemIterator,
|
||||||
ParentDisplayItemIterator(dlist::Items<'a,DisplayItem>),
|
ParentDisplayItemIterator(dlist::Items<'a,DisplayItem>),
|
||||||
|
@ -580,24 +500,24 @@ impl<'a> Iterator<&'a DisplayItem> for DisplayItemIterator<'a> {
|
||||||
|
|
||||||
impl DisplayItem {
|
impl DisplayItem {
|
||||||
/// Renders this display item into the given render context.
|
/// Renders this display item into the given render context.
|
||||||
fn draw_into_context(&self, render_context: &mut RenderContext,
|
fn draw_into_context(&self,
|
||||||
current_transform: &Matrix2D<AzFloat>) {
|
render_context: &mut RenderContext,
|
||||||
|
current_transform: &Matrix2D<AzFloat>,
|
||||||
|
current_clip_rect: &Rect<Au>) {
|
||||||
// This should have been flattened to the content stacking level first.
|
// This should have been flattened to the content stacking level first.
|
||||||
assert!(self.base().level == ContentStackingLevel);
|
assert!(self.base().level == ContentStackingLevel);
|
||||||
|
|
||||||
|
let clip_rect = &self.base().clip_rect;
|
||||||
|
let need_to_clip = current_clip_rect != clip_rect;
|
||||||
|
if need_to_clip {
|
||||||
|
render_context.draw_push_clip(clip_rect);
|
||||||
|
}
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
SolidColorDisplayItemClass(ref solid_color) => {
|
SolidColorDisplayItemClass(ref solid_color) => {
|
||||||
render_context.draw_solid_color(&solid_color.base.bounds, solid_color.color)
|
render_context.draw_solid_color(&solid_color.base.bounds, solid_color.color)
|
||||||
}
|
}
|
||||||
|
|
||||||
ClipDisplayItemClass(ref clip) => {
|
|
||||||
render_context.draw_push_clip(&clip.base.bounds);
|
|
||||||
for item in clip.children.iter() {
|
|
||||||
(*item).draw_into_context(render_context, current_transform);
|
|
||||||
}
|
|
||||||
render_context.draw_pop_clip();
|
|
||||||
}
|
|
||||||
|
|
||||||
TextDisplayItemClass(ref text) => {
|
TextDisplayItemClass(ref text) => {
|
||||||
debug!("Drawing text at {}.", text.base.bounds);
|
debug!("Drawing text at {}.", text.base.bounds);
|
||||||
|
|
||||||
|
@ -688,6 +608,10 @@ impl DisplayItem {
|
||||||
|
|
||||||
PseudoDisplayItemClass(_) => {}
|
PseudoDisplayItemClass(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if need_to_clip {
|
||||||
|
render_context.draw_pop_clip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn base<'a>(&'a self) -> &'a BaseDisplayItem {
|
pub fn base<'a>(&'a self) -> &'a BaseDisplayItem {
|
||||||
|
@ -697,7 +621,6 @@ impl DisplayItem {
|
||||||
ImageDisplayItemClass(ref image_item) => &image_item.base,
|
ImageDisplayItemClass(ref image_item) => &image_item.base,
|
||||||
BorderDisplayItemClass(ref border) => &border.base,
|
BorderDisplayItemClass(ref border) => &border.base,
|
||||||
LineDisplayItemClass(ref line) => &line.base,
|
LineDisplayItemClass(ref line) => &line.base,
|
||||||
ClipDisplayItemClass(ref clip) => &clip.base,
|
|
||||||
PseudoDisplayItemClass(ref base) => &**base,
|
PseudoDisplayItemClass(ref base) => &**base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -709,7 +632,6 @@ impl DisplayItem {
|
||||||
ImageDisplayItemClass(ref mut image_item) => &mut image_item.base,
|
ImageDisplayItemClass(ref mut image_item) => &mut image_item.base,
|
||||||
BorderDisplayItemClass(ref mut border) => &mut border.base,
|
BorderDisplayItemClass(ref mut border) => &mut border.base,
|
||||||
LineDisplayItemClass(ref mut line) => &mut line.base,
|
LineDisplayItemClass(ref mut line) => &mut line.base,
|
||||||
ClipDisplayItemClass(ref mut clip) => &mut clip.base,
|
|
||||||
PseudoDisplayItemClass(ref mut base) => &mut **base,
|
PseudoDisplayItemClass(ref mut base) => &mut **base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -718,40 +640,12 @@ impl DisplayItem {
|
||||||
self.base().bounds
|
self.base().bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn children<'a>(&'a self) -> DisplayItemIterator<'a> {
|
|
||||||
match *self {
|
|
||||||
ClipDisplayItemClass(ref clip) => ParentDisplayItemIterator(clip.children.list.iter()),
|
|
||||||
SolidColorDisplayItemClass(..) |
|
|
||||||
TextDisplayItemClass(..) |
|
|
||||||
ImageDisplayItemClass(..) |
|
|
||||||
BorderDisplayItemClass(..) |
|
|
||||||
LineDisplayItemClass(..) |
|
|
||||||
PseudoDisplayItemClass(..) => EmptyDisplayItemIterator,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a mutable reference to the sublist contained within this display list item, if any.
|
|
||||||
fn mut_sublist<'a>(&'a mut self) -> Option<&'a mut DisplayList> {
|
|
||||||
match *self {
|
|
||||||
ClipDisplayItemClass(ref mut clip) => Some(&mut clip.children),
|
|
||||||
SolidColorDisplayItemClass(..) |
|
|
||||||
TextDisplayItemClass(..) |
|
|
||||||
ImageDisplayItemClass(..) |
|
|
||||||
BorderDisplayItemClass(..) |
|
|
||||||
LineDisplayItemClass(..) |
|
|
||||||
PseudoDisplayItemClass(..) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn debug_with_level(&self, level: uint) {
|
pub fn debug_with_level(&self, level: uint) {
|
||||||
let mut indent = String::new();
|
let mut indent = String::new();
|
||||||
for _ in range(0, level) {
|
for _ in range(0, level) {
|
||||||
indent.push_str("| ")
|
indent.push_str("| ")
|
||||||
}
|
}
|
||||||
debug!("{}+ {}", indent, self);
|
debug!("{}+ {}", indent, self);
|
||||||
for child in self.children() {
|
|
||||||
child.debug_with_level(level + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,7 +658,6 @@ impl fmt::Show for DisplayItem {
|
||||||
ImageDisplayItemClass(_) => "Image",
|
ImageDisplayItemClass(_) => "Image",
|
||||||
BorderDisplayItemClass(_) => "Border",
|
BorderDisplayItemClass(_) => "Border",
|
||||||
LineDisplayItemClass(_) => "Line",
|
LineDisplayItemClass(_) => "Line",
|
||||||
ClipDisplayItemClass(_) => "Clip",
|
|
||||||
PseudoDisplayItemClass(_) => "Pseudo",
|
PseudoDisplayItemClass(_) => "Pseudo",
|
||||||
},
|
},
|
||||||
self.base().bounds,
|
self.base().bounds,
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use display_list::{BorderDisplayItemClass, ClipDisplayItem, ClipDisplayItemClass, DisplayItem};
|
use display_list::{DisplayItem, DisplayList};
|
||||||
use display_list::{DisplayList, ImageDisplayItemClass, LineDisplayItemClass};
|
|
||||||
use display_list::{PseudoDisplayItemClass, SolidColorDisplayItemClass, TextDisplayItemClass};
|
|
||||||
|
|
||||||
use collections::dlist::DList;
|
use collections::dlist::DList;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
|
@ -45,29 +43,12 @@ impl DisplayListOptimizer {
|
||||||
|
|
||||||
fn process_display_item(&self, display_item: &DisplayItem) -> Option<DisplayItem> {
|
fn process_display_item(&self, display_item: &DisplayItem) -> Option<DisplayItem> {
|
||||||
// Eliminate display items outside the visible region.
|
// Eliminate display items outside the visible region.
|
||||||
if !self.visible_rect.intersects(&display_item.base().bounds) {
|
if !self.visible_rect.intersects(&display_item.base().bounds) ||
|
||||||
return None
|
!self.visible_rect.intersects(&display_item.base().clip_rect) {
|
||||||
}
|
None
|
||||||
|
} else {
|
||||||
// Recur.
|
|
||||||
match *display_item {
|
|
||||||
ClipDisplayItemClass(ref clip) => {
|
|
||||||
let new_children = self.process_display_list(&clip.children);
|
|
||||||
if new_children.is_empty() {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
Some(ClipDisplayItemClass(box ClipDisplayItem {
|
|
||||||
base: clip.base.clone(),
|
|
||||||
children: new_children,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
BorderDisplayItemClass(_) | ImageDisplayItemClass(_) | LineDisplayItemClass(_) |
|
|
||||||
PseudoDisplayItemClass(_) | SolidColorDisplayItemClass(_) |
|
|
||||||
TextDisplayItemClass(_) => {
|
|
||||||
Some((*display_item).clone())
|
Some((*display_item).clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,14 @@ use servo_msg::compositor_msg::{LayerMetadata, RenderListener, RenderingRenderSt
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, Failure, FailureMsg, PipelineId};
|
use servo_msg::constellation_msg::{ConstellationChan, Failure, FailureMsg, PipelineId};
|
||||||
use servo_msg::constellation_msg::{RendererReadyMsg};
|
use servo_msg::constellation_msg::{RendererReadyMsg};
|
||||||
use servo_msg::platform::surface::NativeSurfaceAzureMethods;
|
use servo_msg::platform::surface::NativeSurfaceAzureMethods;
|
||||||
use servo_util::geometry;
|
use servo_util::geometry::{Au, mod};
|
||||||
use servo_util::opts::Opts;
|
use servo_util::opts::Opts;
|
||||||
use servo_util::smallvec::{SmallVec, SmallVec1};
|
use servo_util::smallvec::{SmallVec, SmallVec1};
|
||||||
use servo_util::task::spawn_named_with_send_on_failure;
|
use servo_util::task::spawn_named_with_send_on_failure;
|
||||||
use servo_util::time::{TimeProfilerChan, profile};
|
use servo_util::time::{TimeProfilerChan, profile};
|
||||||
use servo_util::time;
|
use servo_util::time;
|
||||||
use std::comm::{Receiver, Sender, channel};
|
use std::comm::{Receiver, Sender, channel};
|
||||||
|
use std::i32;
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
use font_cache_task::FontCacheTask;
|
use font_cache_task::FontCacheTask;
|
||||||
|
|
||||||
|
@ -356,8 +357,13 @@ impl<C:RenderListener + Send> RenderTask<C> {
|
||||||
ctx.clear();
|
ctx.clear();
|
||||||
|
|
||||||
// Draw the display list.
|
// Draw the display list.
|
||||||
profile(time::RenderingDrawingCategory, None, self.time_profiler_chan.clone(), || {
|
profile(time::RenderingDrawingCategory,
|
||||||
display_list.draw_into_context(&mut ctx, &matrix);
|
None,
|
||||||
|
self.time_profiler_chan.clone(),
|
||||||
|
|| {
|
||||||
|
let clip_rect = Rect(Point2D(Au(i32::MIN), Au(i32::MIN)),
|
||||||
|
Size2D(Au(i32::MAX), Au(i32::MAX)));
|
||||||
|
display_list.draw_into_context(&mut ctx, &matrix, &clip_rect);
|
||||||
ctx.draw_target.flush();
|
ctx.draw_target.flush();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ use gfx::display_list::{RootOfStackingContextLevel};
|
||||||
use gfx::render_task::RenderLayer;
|
use gfx::render_task::RenderLayer;
|
||||||
use serialize::{Encoder, Encodable};
|
use serialize::{Encoder, Encodable};
|
||||||
use servo_msg::compositor_msg::{FixedPosition, LayerId, Scrollable};
|
use servo_msg::compositor_msg::{FixedPosition, LayerId, Scrollable};
|
||||||
use servo_util::geometry::{Au, MAX_AU};
|
use servo_util::geometry::{Au, MAX_AU, MAX_RECT};
|
||||||
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
|
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -1078,18 +1078,19 @@ impl BlockFlow {
|
||||||
fn build_display_list_block_common(&mut self,
|
fn build_display_list_block_common(&mut self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
background_border_level: BackgroundAndBorderLevel) {
|
background_border_level: BackgroundAndBorderLevel) {
|
||||||
let rel_offset =
|
let relative_offset =
|
||||||
self.fragment.relative_position(&self.base
|
self.fragment.relative_position(&self.base
|
||||||
.absolute_position_info
|
.absolute_position_info
|
||||||
.relative_containing_block_size);
|
.relative_containing_block_size);
|
||||||
|
|
||||||
// Add the box that starts the block context.
|
// Add the box that starts the block context.
|
||||||
let mut display_list = DisplayList::new();
|
let mut display_list = DisplayList::new();
|
||||||
let mut accumulator = self.fragment.build_display_list(
|
self.fragment.build_display_list(&mut display_list,
|
||||||
&mut display_list,
|
|
||||||
layout_context,
|
layout_context,
|
||||||
self.base.abs_position.add_size(&rel_offset.to_physical(self.base.writing_mode)),
|
self.base.abs_position.add_size(
|
||||||
background_border_level);
|
&relative_offset.to_physical(self.base.writing_mode)),
|
||||||
|
background_border_level,
|
||||||
|
&self.base.clip_rect);
|
||||||
|
|
||||||
let mut child_layers = DList::new();
|
let mut child_layers = DList::new();
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
|
@ -1098,19 +1099,21 @@ impl BlockFlow {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
accumulator.push_child(&mut display_list, kid);
|
display_list.push_all_move(mem::replace(&mut flow::mut_base(kid).display_list,
|
||||||
|
DisplayList::new()));
|
||||||
child_layers.append(mem::replace(&mut flow::mut_base(kid).layers, DList::new()))
|
child_layers.append(mem::replace(&mut flow::mut_base(kid).layers, DList::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process absolute descendant links.
|
// Process absolute descendant links.
|
||||||
for abs_descendant_link in self.base.abs_descendants.iter() {
|
for abs_descendant_link in self.base.abs_descendants.iter() {
|
||||||
// TODO(pradeep): Send in our absolute position directly.
|
// TODO(pradeep): Send in our absolute position directly.
|
||||||
accumulator.push_child(&mut display_list, abs_descendant_link);
|
display_list.push_all_move(mem::replace(
|
||||||
|
&mut flow::mut_base(abs_descendant_link).display_list,
|
||||||
|
DisplayList::new()));
|
||||||
child_layers.append(mem::replace(&mut flow::mut_base(abs_descendant_link).layers,
|
child_layers.append(mem::replace(&mut flow::mut_base(abs_descendant_link).layers,
|
||||||
DList::new()));
|
DList::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
accumulator.finish(&mut display_list);
|
|
||||||
self.base.display_list = display_list;
|
self.base.display_list = display_list;
|
||||||
self.base.layers = child_layers
|
self.base.layers = child_layers
|
||||||
}
|
}
|
||||||
|
@ -1696,6 +1699,10 @@ impl Flow for BlockFlow {
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
|
|
||||||
|
if self.is_root() {
|
||||||
|
self.base.clip_rect = MAX_RECT;
|
||||||
|
}
|
||||||
|
|
||||||
if self.is_absolutely_positioned() {
|
if self.is_absolutely_positioned() {
|
||||||
let position_start = self.base.position.start.to_physical(
|
let position_start = self.base.position.start.to_physical(
|
||||||
self.base.writing_mode, container_size);
|
self.base.writing_mode, container_size);
|
||||||
|
@ -1737,8 +1744,11 @@ impl Flow for BlockFlow {
|
||||||
absolute_position_info.layers_needed_for_positioned_flows =
|
absolute_position_info.layers_needed_for_positioned_flows =
|
||||||
self.base.flags.layers_needed_for_descendants();
|
self.base.flags.layers_needed_for_descendants();
|
||||||
|
|
||||||
// Process children.
|
// Compute the clipping rectangle for children.
|
||||||
let this_position = self.base.abs_position;
|
let this_position = self.base.abs_position;
|
||||||
|
let clip_rect = self.fragment.clip_rect_for_children(self.base.clip_rect, this_position);
|
||||||
|
|
||||||
|
// Process children.
|
||||||
let writing_mode = self.base.writing_mode;
|
let writing_mode = self.base.writing_mode;
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
if !kid.is_absolutely_positioned() {
|
if !kid.is_absolutely_positioned() {
|
||||||
|
@ -1749,6 +1759,8 @@ impl Flow for BlockFlow {
|
||||||
container_size);
|
container_size);
|
||||||
kid_base.absolute_position_info = absolute_position_info
|
kid_base.absolute_position_info = absolute_position_info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flow::mut_base(kid).clip_rect = clip_rect
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process absolute descendant links.
|
// Process absolute descendant links.
|
||||||
|
|
|
@ -1204,7 +1204,6 @@ impl FlowConstructionUtils for FlowRef {
|
||||||
|
|
||||||
base.children.push_back(new_child);
|
base.children.push_back(new_child);
|
||||||
let _ = base.parallel.children_count.fetch_add(1, Relaxed);
|
let _ = base.parallel.children_count.fetch_add(1, Relaxed);
|
||||||
let _ = base.parallel.children_and_absolute_descendant_count.fetch_add(1, Relaxed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finishes a flow. Once a flow is finished, no more child flows or fragments may be added to
|
/// Finishes a flow. Once a flow is finished, no more child flows or fragments may be added to
|
||||||
|
|
|
@ -46,7 +46,7 @@ use table_wrapper::TableWrapperFlow;
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
use collections::dlist::DList;
|
use collections::dlist::DList;
|
||||||
use geom::Point2D;
|
use geom::{Point2D, Rect, Size2D};
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
use gfx::render_task::RenderLayer;
|
use gfx::render_task::RenderLayer;
|
||||||
use serialize::{Encoder, Encodable};
|
use serialize::{Encoder, Encodable};
|
||||||
|
@ -59,7 +59,7 @@ use std::num::Zero;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::Zip;
|
use std::iter::Zip;
|
||||||
use std::raw;
|
use std::raw;
|
||||||
use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
|
use std::sync::atomics::{AtomicUint, SeqCst};
|
||||||
use std::slice::MutItems;
|
use std::slice::MutItems;
|
||||||
use style::computed_values::{clear, float, position, text_align};
|
use style::computed_values::{clear, float, position, text_align};
|
||||||
|
|
||||||
|
@ -168,14 +168,14 @@ pub trait Flow: fmt::Show + ToString + Sync {
|
||||||
fail!("called col_inline_sizes() on an other flow than table-row/table-rowgroup/table")
|
fail!("called col_inline_sizes() on an other flow than table-row/table-rowgroup/table")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this is a table row flow or table rowgroup flow or table flow, returns column min inline-sizes.
|
/// If this is a table row flow or table rowgroup flow or table flow, returns column min
|
||||||
/// Fails otherwise.
|
/// inline-sizes. Fails otherwise.
|
||||||
fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
|
fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
|
||||||
fail!("called col_min_inline_sizes() on an other flow than table-row/table-rowgroup/table")
|
fail!("called col_min_inline_sizes() on an other flow than table-row/table-rowgroup/table")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this is a table row flow or table rowgroup flow or table flow, returns column min inline-sizes.
|
/// If this is a table row flow or table rowgroup flow or table flow, returns column min
|
||||||
/// Fails otherwise.
|
/// inline-sizes. Fails otherwise.
|
||||||
fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
|
fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
|
||||||
fail!("called col_pref_inline_sizes() on an other flow than table-row/table-rowgroup/table")
|
fail!("called col_pref_inline_sizes() on an other flow than table-row/table-rowgroup/table")
|
||||||
}
|
}
|
||||||
|
@ -679,8 +679,10 @@ pub type DescendantOffsetIter<'a> = Zip<DescendantIter<'a>, MutItems<'a, Au>>;
|
||||||
pub struct AbsolutePositionInfo {
|
pub struct AbsolutePositionInfo {
|
||||||
/// The size of the containing block for relatively-positioned descendants.
|
/// The size of the containing block for relatively-positioned descendants.
|
||||||
pub relative_containing_block_size: LogicalSize<Au>,
|
pub relative_containing_block_size: LogicalSize<Au>,
|
||||||
|
|
||||||
/// The position of the absolute containing block.
|
/// The position of the absolute containing block.
|
||||||
pub absolute_containing_block_position: Point2D<Au>,
|
pub absolute_containing_block_position: Point2D<Au>,
|
||||||
|
|
||||||
/// Whether the absolute containing block forces positioned descendants to be layerized.
|
/// Whether the absolute containing block forces positioned descendants to be layerized.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Move into `FlowFlags`.
|
/// FIXME(pcwalton): Move into `FlowFlags`.
|
||||||
|
@ -770,6 +772,12 @@ pub struct BaseFlow {
|
||||||
/// FIXME(pcwalton): Merge with `absolute_static_i_offset` and `fixed_static_i_offset` above?
|
/// FIXME(pcwalton): Merge with `absolute_static_i_offset` and `fixed_static_i_offset` above?
|
||||||
pub absolute_position_info: AbsolutePositionInfo,
|
pub absolute_position_info: AbsolutePositionInfo,
|
||||||
|
|
||||||
|
/// The clipping rectangle for this flow and its descendants, in layer coordinates.
|
||||||
|
///
|
||||||
|
/// TODO(pcwalton): When we have `border-radius` this will need to at least support rounded
|
||||||
|
/// rectangles.
|
||||||
|
pub clip_rect: Rect<Au>,
|
||||||
|
|
||||||
/// The unflattened display items for this flow.
|
/// The unflattened display items for this flow.
|
||||||
pub display_list: DisplayList,
|
pub display_list: DisplayList,
|
||||||
|
|
||||||
|
@ -785,11 +793,10 @@ pub struct BaseFlow {
|
||||||
impl fmt::Show for BaseFlow {
|
impl fmt::Show for BaseFlow {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f,
|
write!(f,
|
||||||
"@ {}, CC {}, ADC {}, CADC {}",
|
"@ {}, CC {}, ADC {}",
|
||||||
self.position,
|
self.position,
|
||||||
self.parallel.children_count.load(SeqCst),
|
self.parallel.children_count.load(SeqCst),
|
||||||
self.abs_descendants.len(),
|
self.abs_descendants.len())
|
||||||
self.parallel.children_and_absolute_descendant_count.load(SeqCst))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -851,6 +858,7 @@ impl BaseFlow {
|
||||||
display_list: DisplayList::new(),
|
display_list: DisplayList::new(),
|
||||||
layers: DList::new(),
|
layers: DList::new(),
|
||||||
absolute_position_info: AbsolutePositionInfo::new(writing_mode),
|
absolute_position_info: AbsolutePositionInfo::new(writing_mode),
|
||||||
|
clip_rect: Rect(Zero::zero(), Size2D(Au(0), Au(0))),
|
||||||
|
|
||||||
flags: FlowFlags::new(),
|
flags: FlowFlags::new(),
|
||||||
writing_mode: writing_mode,
|
writing_mode: writing_mode,
|
||||||
|
@ -1210,10 +1218,6 @@ impl MutableOwnedFlowUtils for FlowRef {
|
||||||
|
|
||||||
let block = self.get_mut().as_block();
|
let block = self.get_mut().as_block();
|
||||||
block.base.abs_descendants = abs_descendants;
|
block.base.abs_descendants = abs_descendants;
|
||||||
block.base
|
|
||||||
.parallel
|
|
||||||
.children_and_absolute_descendant_count
|
|
||||||
.fetch_add(block.base.abs_descendants.len() as int, Relaxed);
|
|
||||||
|
|
||||||
for descendant_link in block.base.abs_descendants.iter() {
|
for descendant_link in block.base.abs_descendants.iter() {
|
||||||
let base = mut_base(descendant_link);
|
let base = mut_base(descendant_link);
|
||||||
|
|
|
@ -11,7 +11,6 @@ use construct::FlowConstructor;
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use floats::{ClearBoth, ClearLeft, ClearRight, ClearType};
|
use floats::{ClearBoth, ClearLeft, ClearRight, ClearType};
|
||||||
use flow::Flow;
|
use flow::Flow;
|
||||||
use flow;
|
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
use inline::{InlineFragmentContext, InlineMetrics};
|
use inline::{InlineFragmentContext, InlineMetrics};
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
|
@ -25,13 +24,12 @@ use geom::{Point2D, Rect, Size2D, SideOffsets2D};
|
||||||
use geom::approxeq::ApproxEq;
|
use geom::approxeq::ApproxEq;
|
||||||
use gfx::color::rgb;
|
use gfx::color::rgb;
|
||||||
use gfx::display_list::{BackgroundAndBorderLevel, BaseDisplayItem, BorderDisplayItem};
|
use gfx::display_list::{BackgroundAndBorderLevel, BaseDisplayItem, BorderDisplayItem};
|
||||||
use gfx::display_list::{BorderDisplayItemClass, ClipDisplayItem, ClipDisplayItemClass};
|
use gfx::display_list::{BorderDisplayItemClass, ContentStackingLevel, DisplayList};
|
||||||
use gfx::display_list::{ContentStackingLevel, DisplayItem, DisplayList, ImageDisplayItem};
|
use gfx::display_list::{ImageDisplayItem, ImageDisplayItemClass, LineDisplayItem};
|
||||||
use gfx::display_list::{ImageDisplayItemClass, LineDisplayItem};
|
|
||||||
use gfx::display_list::{LineDisplayItemClass, OpaqueNode, PseudoDisplayItemClass};
|
use gfx::display_list::{LineDisplayItemClass, OpaqueNode, PseudoDisplayItemClass};
|
||||||
use gfx::display_list::{SolidColorDisplayItem, SolidColorDisplayItemClass, StackingLevel};
|
use gfx::display_list::{SidewaysLeft, SidewaysRight, SolidColorDisplayItem};
|
||||||
use gfx::display_list::{TextDisplayItem, TextDisplayItemClass};
|
use gfx::display_list::{SolidColorDisplayItemClass, StackingLevel, TextDisplayItem};
|
||||||
use gfx::display_list::{Upright, SidewaysLeft, SidewaysRight};
|
use gfx::display_list::{TextDisplayItemClass, Upright};
|
||||||
use gfx::font::FontStyle;
|
use gfx::font::FontStyle;
|
||||||
use gfx::text::glyph::CharIndex;
|
use gfx::text::glyph::CharIndex;
|
||||||
use gfx::text::text_run::TextRun;
|
use gfx::text::text_run::TextRun;
|
||||||
|
@ -40,7 +38,7 @@ use serialize::{Encodable, Encoder};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
|
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
|
||||||
use servo_net::image::holder::ImageHolder;
|
use servo_net::image::holder::ImageHolder;
|
||||||
use servo_net::local_image_cache::LocalImageCache;
|
use servo_net::local_image_cache::LocalImageCache;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::{Au, ZERO_RECT};
|
||||||
use servo_util::geometry;
|
use servo_util::geometry;
|
||||||
use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin, WritingMode};
|
use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin, WritingMode};
|
||||||
use servo_util::range::*;
|
use servo_util::range::*;
|
||||||
|
@ -49,7 +47,6 @@ use servo_util::str::is_whitespace;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::from_str::FromStr;
|
use std::from_str::FromStr;
|
||||||
use std::mem;
|
|
||||||
use std::num::Zero;
|
use std::num::Zero;
|
||||||
use style::{ComputedValues, TElement, TNode, cascade_anonymous, RGBA};
|
use style::{ComputedValues, TElement, TNode, cascade_anonymous, RGBA};
|
||||||
use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
|
@ -60,24 +57,26 @@ use style::computed_values::{text_decoration, vertical_align, visibility, white_
|
||||||
use sync::{Arc, Mutex};
|
use sync::{Arc, Mutex};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position themselves. In
|
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
|
||||||
/// general, fragments do not have a simple correspondence with CSS fragments in the specification:
|
/// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
|
||||||
|
/// specification:
|
||||||
///
|
///
|
||||||
/// * Several fragments may correspond to the same CSS box or DOM node. For example, a CSS text box
|
/// * Several fragments may correspond to the same CSS box or DOM node. For example, a CSS text box
|
||||||
/// broken across two lines is represented by two fragments.
|
/// broken across two lines is represented by two fragments.
|
||||||
///
|
///
|
||||||
/// * Some CSS fragments are not created at all, such as some anonymous block fragments induced by inline
|
/// * Some CSS fragments are not created at all, such as some anonymous block fragments induced by
|
||||||
/// fragments with block-level sibling fragments. In that case, Servo uses an `InlineFlow` with
|
/// inline fragments with block-level sibling fragments. In that case, Servo uses an `InlineFlow`
|
||||||
/// `BlockFlow` siblings; the `InlineFlow` is block-level, but not a block container. It is
|
/// with `BlockFlow` siblings; the `InlineFlow` is block-level, but not a block container. It is
|
||||||
/// positioned as if it were a block fragment, but its children are positioned according to inline
|
/// positioned as if it were a block fragment, but its children are positioned according to
|
||||||
/// flow.
|
/// inline flow.
|
||||||
///
|
///
|
||||||
/// A `GenericFragment` is an empty fragment that contributes only borders, margins, padding, and
|
/// A `GenericFragment` is an empty fragment that contributes only borders, margins, padding, and
|
||||||
/// backgrounds. It is analogous to a CSS nonreplaced content box.
|
/// backgrounds. It is analogous to a CSS nonreplaced content box.
|
||||||
///
|
///
|
||||||
/// A fragment's type influences how its styles are interpreted during layout. For example, replaced
|
/// A fragment's type influences how its styles are interpreted during layout. For example,
|
||||||
/// content such as images are resized differently from tables, text, or other content. Different
|
/// replaced content such as images are resized differently from tables, text, or other content.
|
||||||
/// types of fragments may also contain custom data; for example, text fragments contain text.
|
/// Different types of fragments may also contain custom data; for example, text fragments contain
|
||||||
|
/// text.
|
||||||
///
|
///
|
||||||
/// FIXME(#2260, pcwalton): This can be slimmed down some.
|
/// FIXME(#2260, pcwalton): This can be slimmed down some.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -787,7 +786,8 @@ impl Fragment {
|
||||||
list: &mut DisplayList,
|
list: &mut DisplayList,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
level: StackingLevel,
|
level: StackingLevel,
|
||||||
absolute_bounds: &Rect<Au>) {
|
absolute_bounds: &Rect<Au>,
|
||||||
|
clip_rect: &Rect<Au>) {
|
||||||
// FIXME: This causes a lot of background colors to be displayed when they are clearly not
|
// FIXME: This causes a lot of background colors to be displayed when they are clearly not
|
||||||
// needed. We could use display list optimization to clean this up, but it still seems
|
// needed. We could use display list optimization to clean this up, but it still seems
|
||||||
// inefficient. What we really want is something like "nearest ancestor element that
|
// inefficient. What we really want is something like "nearest ancestor element that
|
||||||
|
@ -795,7 +795,7 @@ impl Fragment {
|
||||||
let background_color = style.resolve_color(style.get_background().background_color);
|
let background_color = style.resolve_color(style.get_background().background_color);
|
||||||
if !background_color.alpha.approx_eq(&0.0) {
|
if !background_color.alpha.approx_eq(&0.0) {
|
||||||
let display_item = box SolidColorDisplayItem {
|
let display_item = box SolidColorDisplayItem {
|
||||||
base: BaseDisplayItem::new(*absolute_bounds, self.node, level),
|
base: BaseDisplayItem::new(*absolute_bounds, self.node, level, *clip_rect),
|
||||||
color: background_color.to_gfx_color(),
|
color: background_color.to_gfx_color(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -828,12 +828,10 @@ impl Fragment {
|
||||||
let image_height = Au::from_px(image.height as int);
|
let image_height = Au::from_px(image.height as int);
|
||||||
let mut bounds = *absolute_bounds;
|
let mut bounds = *absolute_bounds;
|
||||||
|
|
||||||
// Add clip item.
|
// Clip.
|
||||||
|
//
|
||||||
// TODO: Check the bounds to see if a clip item is actually required.
|
// TODO: Check the bounds to see if a clip item is actually required.
|
||||||
let mut clip_display_item = box ClipDisplayItem {
|
let clip_rect = clip_rect.intersection(&bounds).unwrap_or(ZERO_RECT);
|
||||||
base: BaseDisplayItem::new(bounds, self.node, level),
|
|
||||||
children: DisplayList::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Use background-attachment to get the initial virtual origin
|
// Use background-attachment to get the initial virtual origin
|
||||||
let (virtual_origin_x, virtual_origin_y) = match background.background_attachment {
|
let (virtual_origin_x, virtual_origin_y) = match background.background_attachment {
|
||||||
|
@ -884,14 +882,12 @@ impl Fragment {
|
||||||
|
|
||||||
// Create the image display item.
|
// Create the image display item.
|
||||||
let image_display_item = ImageDisplayItemClass(box ImageDisplayItem {
|
let image_display_item = ImageDisplayItemClass(box ImageDisplayItem {
|
||||||
base: BaseDisplayItem::new(bounds, self.node, level),
|
base: BaseDisplayItem::new(bounds, self.node, level, clip_rect),
|
||||||
image: image.clone(),
|
image: image.clone(),
|
||||||
stretch_size: Size2D(Au::from_px(image.width as int),
|
stretch_size: Size2D(Au::from_px(image.width as int),
|
||||||
Au::from_px(image.height as int)),
|
Au::from_px(image.height as int)),
|
||||||
});
|
});
|
||||||
|
list.push(image_display_item)
|
||||||
clip_display_item.children.push(image_display_item);
|
|
||||||
list.push(ClipDisplayItemClass(clip_display_item))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the display items necessary to paint the borders of this fragment to a display list if
|
/// Adds the display items necessary to paint the borders of this fragment to a display list if
|
||||||
|
@ -900,7 +896,8 @@ impl Fragment {
|
||||||
style: &ComputedValues,
|
style: &ComputedValues,
|
||||||
list: &mut DisplayList,
|
list: &mut DisplayList,
|
||||||
abs_bounds: &Rect<Au>,
|
abs_bounds: &Rect<Au>,
|
||||||
level: StackingLevel) {
|
level: StackingLevel,
|
||||||
|
clip_rect: &Rect<Au>) {
|
||||||
let border = style.logical_border_width();
|
let border = style.logical_border_width();
|
||||||
if border.is_zero() {
|
if border.is_zero() {
|
||||||
return
|
return
|
||||||
|
@ -913,7 +910,7 @@ impl Fragment {
|
||||||
|
|
||||||
// Append the border to the display list.
|
// Append the border to the display list.
|
||||||
let border_display_item = box BorderDisplayItem {
|
let border_display_item = box BorderDisplayItem {
|
||||||
base: BaseDisplayItem::new(*abs_bounds, self.node, level),
|
base: BaseDisplayItem::new(*abs_bounds, self.node, level, *clip_rect),
|
||||||
border: border.to_physical(style.writing_mode),
|
border: border.to_physical(style.writing_mode),
|
||||||
color: SideOffsets2D::new(top_color.to_gfx_color(),
|
color: SideOffsets2D::new(top_color.to_gfx_color(),
|
||||||
right_color.to_gfx_color(),
|
right_color.to_gfx_color(),
|
||||||
|
@ -931,7 +928,8 @@ impl Fragment {
|
||||||
fn build_debug_borders_around_text_fragments(&self,
|
fn build_debug_borders_around_text_fragments(&self,
|
||||||
display_list: &mut DisplayList,
|
display_list: &mut DisplayList,
|
||||||
flow_origin: Point2D<Au>,
|
flow_origin: Point2D<Au>,
|
||||||
text_fragment: &ScannedTextFragmentInfo) {
|
text_fragment: &ScannedTextFragmentInfo,
|
||||||
|
clip_rect: &Rect<Au>) {
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
// Fragment position wrt to the owning flow.
|
// Fragment position wrt to the owning flow.
|
||||||
|
@ -942,7 +940,10 @@ impl Fragment {
|
||||||
|
|
||||||
// Compute the text fragment bounds and draw a border surrounding them.
|
// Compute the text fragment bounds and draw a border surrounding them.
|
||||||
let border_display_item = box BorderDisplayItem {
|
let border_display_item = box BorderDisplayItem {
|
||||||
base: BaseDisplayItem::new(absolute_fragment_bounds, self.node, ContentStackingLevel),
|
base: BaseDisplayItem::new(absolute_fragment_bounds,
|
||||||
|
self.node,
|
||||||
|
ContentStackingLevel,
|
||||||
|
*clip_rect),
|
||||||
border: SideOffsets2D::new_all_same(Au::from_px(1)),
|
border: SideOffsets2D::new_all_same(Au::from_px(1)),
|
||||||
color: SideOffsets2D::new_all_same(rgb(0, 0, 200)),
|
color: SideOffsets2D::new_all_same(rgb(0, 0, 200)),
|
||||||
style: SideOffsets2D::new_all_same(border_style::solid)
|
style: SideOffsets2D::new_all_same(border_style::solid)
|
||||||
|
@ -958,7 +959,7 @@ impl Fragment {
|
||||||
baseline.origin = baseline.origin + flow_origin;
|
baseline.origin = baseline.origin + flow_origin;
|
||||||
|
|
||||||
let line_display_item = box LineDisplayItem {
|
let line_display_item = box LineDisplayItem {
|
||||||
base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel),
|
base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel, *clip_rect),
|
||||||
color: rgb(0, 200, 0),
|
color: rgb(0, 200, 0),
|
||||||
style: border_style::dashed,
|
style: border_style::dashed,
|
||||||
};
|
};
|
||||||
|
@ -967,7 +968,8 @@ impl Fragment {
|
||||||
|
|
||||||
fn build_debug_borders_around_fragment(&self,
|
fn build_debug_borders_around_fragment(&self,
|
||||||
display_list: &mut DisplayList,
|
display_list: &mut DisplayList,
|
||||||
flow_origin: Point2D<Au>) {
|
flow_origin: Point2D<Au>,
|
||||||
|
clip_rect: &Rect<Au>) {
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
// Fragment position wrt to the owning flow.
|
// Fragment position wrt to the owning flow.
|
||||||
|
@ -978,7 +980,10 @@ impl Fragment {
|
||||||
|
|
||||||
// This prints a debug border around the border of this fragment.
|
// This prints a debug border around the border of this fragment.
|
||||||
let border_display_item = box BorderDisplayItem {
|
let border_display_item = box BorderDisplayItem {
|
||||||
base: BaseDisplayItem::new(absolute_fragment_bounds, self.node, ContentStackingLevel),
|
base: BaseDisplayItem::new(absolute_fragment_bounds,
|
||||||
|
self.node,
|
||||||
|
ContentStackingLevel,
|
||||||
|
*clip_rect),
|
||||||
border: SideOffsets2D::new_all_same(Au::from_px(1)),
|
border: SideOffsets2D::new_all_same(Au::from_px(1)),
|
||||||
color: SideOffsets2D::new_all_same(rgb(0, 0, 200)),
|
color: SideOffsets2D::new_all_same(rgb(0, 0, 200)),
|
||||||
style: SideOffsets2D::new_all_same(border_style::solid)
|
style: SideOffsets2D::new_all_same(border_style::solid)
|
||||||
|
@ -994,12 +999,13 @@ impl Fragment {
|
||||||
/// * `layout_context`: The layout context.
|
/// * `layout_context`: The layout context.
|
||||||
/// * `dirty`: The dirty rectangle in the coordinate system of the owning flow.
|
/// * `dirty`: The dirty rectangle in the coordinate system of the owning flow.
|
||||||
/// * `flow_origin`: Position of the origin of the owning flow wrt the display list root flow.
|
/// * `flow_origin`: Position of the origin of the owning flow wrt the display list root flow.
|
||||||
|
/// * `clip_rect`: The rectangle to clip the display items to.
|
||||||
pub fn build_display_list(&mut self,
|
pub fn build_display_list(&mut self,
|
||||||
display_list: &mut DisplayList,
|
display_list: &mut DisplayList,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
flow_origin: Point2D<Au>,
|
flow_origin: Point2D<Au>,
|
||||||
background_and_border_level: BackgroundAndBorderLevel)
|
background_and_border_level: BackgroundAndBorderLevel,
|
||||||
-> ChildDisplayListAccumulator {
|
clip_rect: &Rect<Au>) {
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
let rect_to_absolute = |writing_mode: WritingMode, logical_rect: LogicalRect<Au>| {
|
let rect_to_absolute = |writing_mode: WritingMode, logical_rect: LogicalRect<Au>| {
|
||||||
|
@ -1016,22 +1022,13 @@ impl Fragment {
|
||||||
layout_context.shared.dirty,
|
layout_context.shared.dirty,
|
||||||
flow_origin);
|
flow_origin);
|
||||||
|
|
||||||
let may_need_clip = match self.specific {
|
|
||||||
ScannedTextFragment(_) => false,
|
|
||||||
_ => true,
|
|
||||||
};
|
|
||||||
let mut accumulator = ChildDisplayListAccumulator::new(self.style(),
|
|
||||||
absolute_fragment_bounds,
|
|
||||||
self.node,
|
|
||||||
ContentStackingLevel,
|
|
||||||
may_need_clip);
|
|
||||||
if self.style().get_inheritedbox().visibility != visibility::visible {
|
if self.style().get_inheritedbox().visibility != visibility::visible {
|
||||||
return accumulator
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !absolute_fragment_bounds.intersects(&layout_context.shared.dirty) {
|
if !absolute_fragment_bounds.intersects(&layout_context.shared.dirty) {
|
||||||
debug!("Fragment::build_display_list: Did not intersect...");
|
debug!("Fragment::build_display_list: Did not intersect...");
|
||||||
return accumulator
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Fragment::build_display_list: intersected. Adding display item...");
|
debug!("Fragment::build_display_list: intersected. Adding display item...");
|
||||||
|
@ -1043,7 +1040,8 @@ impl Fragment {
|
||||||
// Add a pseudo-display item for content box queries. This is a very bogus thing to do.
|
// Add a pseudo-display item for content box queries. This is a very bogus thing to do.
|
||||||
let base_display_item = box BaseDisplayItem::new(absolute_fragment_bounds,
|
let base_display_item = box BaseDisplayItem::new(absolute_fragment_bounds,
|
||||||
self.node,
|
self.node,
|
||||||
level);
|
level,
|
||||||
|
*clip_rect);
|
||||||
display_list.push(PseudoDisplayItemClass(base_display_item));
|
display_list.push(PseudoDisplayItemClass(base_display_item));
|
||||||
|
|
||||||
// Add the background to the list, if applicable.
|
// Add the background to the list, if applicable.
|
||||||
|
@ -1055,7 +1053,8 @@ impl Fragment {
|
||||||
display_list,
|
display_list,
|
||||||
layout_context,
|
layout_context,
|
||||||
level,
|
level,
|
||||||
&absolute_fragment_bounds);
|
&absolute_fragment_bounds,
|
||||||
|
clip_rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -1068,7 +1067,8 @@ impl Fragment {
|
||||||
display_list,
|
display_list,
|
||||||
layout_context,
|
layout_context,
|
||||||
level,
|
level,
|
||||||
&absolute_fragment_bounds);
|
&absolute_fragment_bounds,
|
||||||
|
clip_rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,7 +1082,8 @@ impl Fragment {
|
||||||
&**style,
|
&**style,
|
||||||
display_list,
|
display_list,
|
||||||
&absolute_fragment_bounds,
|
&absolute_fragment_bounds,
|
||||||
level);
|
level,
|
||||||
|
clip_rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -1090,10 +1091,12 @@ impl Fragment {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
ScannedTextFragment(_) => {},
|
ScannedTextFragment(_) => {},
|
||||||
_ => {
|
_ => {
|
||||||
self.build_display_list_for_borders_if_applicable(&*self.style,
|
self.build_display_list_for_borders_if_applicable(
|
||||||
|
&*self.style,
|
||||||
display_list,
|
display_list,
|
||||||
&absolute_fragment_bounds,
|
&absolute_fragment_bounds,
|
||||||
level);
|
level,
|
||||||
|
clip_rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1125,15 +1128,17 @@ impl Fragment {
|
||||||
};
|
};
|
||||||
|
|
||||||
let text_display_item = box TextDisplayItem {
|
let text_display_item = box TextDisplayItem {
|
||||||
base: BaseDisplayItem::new(
|
base: BaseDisplayItem::new(absolute_content_box,
|
||||||
absolute_content_box, self.node, ContentStackingLevel),
|
self.node,
|
||||||
|
ContentStackingLevel,
|
||||||
|
*clip_rect),
|
||||||
text_run: text_fragment.run.clone(),
|
text_run: text_fragment.run.clone(),
|
||||||
range: text_fragment.range,
|
range: text_fragment.range,
|
||||||
text_color: self.style().get_color().color.to_gfx_color(),
|
text_color: self.style().get_color().color.to_gfx_color(),
|
||||||
orientation: orientation,
|
orientation: orientation,
|
||||||
baseline_origin: baseline_origin,
|
baseline_origin: baseline_origin,
|
||||||
};
|
};
|
||||||
accumulator.push(display_list, TextDisplayItemClass(text_display_item));
|
display_list.push(TextDisplayItemClass(text_display_item));
|
||||||
|
|
||||||
// Create display items for text decoration
|
// Create display items for text decoration
|
||||||
{
|
{
|
||||||
|
@ -1141,14 +1146,17 @@ impl Fragment {
|
||||||
match maybe_color {
|
match maybe_color {
|
||||||
None => {},
|
None => {},
|
||||||
Some(color) => {
|
Some(color) => {
|
||||||
accumulator.push(display_list, SolidColorDisplayItemClass(
|
display_list.push(SolidColorDisplayItemClass(
|
||||||
box SolidColorDisplayItem {
|
box SolidColorDisplayItem {
|
||||||
base: BaseDisplayItem::new(
|
base: BaseDisplayItem::new(
|
||||||
rect_to_absolute(self.style.writing_mode, rect()),
|
rect_to_absolute(
|
||||||
self.node, ContentStackingLevel),
|
self.style.writing_mode,
|
||||||
|
rect()),
|
||||||
|
self.node,
|
||||||
|
ContentStackingLevel,
|
||||||
|
*clip_rect),
|
||||||
color: color.to_gfx_color(),
|
color: color.to_gfx_color(),
|
||||||
}
|
}));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1182,14 +1190,18 @@ impl Fragment {
|
||||||
// We should have a real `SERVO_DEBUG` system.
|
// We should have a real `SERVO_DEBUG` system.
|
||||||
debug!("{:?}", self.build_debug_borders_around_text_fragments(display_list,
|
debug!("{:?}", self.build_debug_borders_around_text_fragments(display_list,
|
||||||
flow_origin,
|
flow_origin,
|
||||||
text_fragment))
|
text_fragment,
|
||||||
|
clip_rect))
|
||||||
}
|
}
|
||||||
GenericFragment | IframeFragment(..) | TableFragment | TableCellFragment |
|
GenericFragment | IframeFragment(..) | TableFragment | TableCellFragment |
|
||||||
TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) | InputFragment(_) |
|
TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) | InputFragment(_) |
|
||||||
InlineAbsoluteHypotheticalFragment(_) => {
|
InlineAbsoluteHypotheticalFragment(_) => {
|
||||||
// FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We
|
// FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We
|
||||||
// should have a real `SERVO_DEBUG` system.
|
// should have a real `SERVO_DEBUG` system.
|
||||||
debug!("{:?}", self.build_debug_borders_around_fragment(display_list, flow_origin))
|
debug!("{:?}",
|
||||||
|
self.build_debug_borders_around_fragment(display_list,
|
||||||
|
flow_origin,
|
||||||
|
clip_rect))
|
||||||
}
|
}
|
||||||
ImageFragment(ref mut image_fragment) => {
|
ImageFragment(ref mut image_fragment) => {
|
||||||
let image_ref = &mut image_fragment.image;
|
let image_ref = &mut image_fragment.image;
|
||||||
|
@ -1201,12 +1213,13 @@ impl Fragment {
|
||||||
let image_display_item = box ImageDisplayItem {
|
let image_display_item = box ImageDisplayItem {
|
||||||
base: BaseDisplayItem::new(absolute_content_box,
|
base: BaseDisplayItem::new(absolute_content_box,
|
||||||
self.node,
|
self.node,
|
||||||
ContentStackingLevel),
|
ContentStackingLevel,
|
||||||
|
*clip_rect),
|
||||||
image: image.clone(),
|
image: image.clone(),
|
||||||
stretch_size: absolute_content_box.size,
|
stretch_size: absolute_content_box.size,
|
||||||
};
|
};
|
||||||
|
|
||||||
accumulator.push(display_list, ImageDisplayItemClass(image_display_item))
|
display_list.push(ImageDisplayItemClass(image_display_item))
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// No image data at all? Do nothing.
|
// No image data at all? Do nothing.
|
||||||
|
@ -1220,7 +1233,8 @@ impl Fragment {
|
||||||
|
|
||||||
// FIXME(pcwalton): This is a bit of an abuse of the logging
|
// FIXME(pcwalton): This is a bit of an abuse of the logging
|
||||||
// infrastructure. We should have a real `SERVO_DEBUG` system.
|
// infrastructure. We should have a real `SERVO_DEBUG` system.
|
||||||
debug!("{:?}", self.build_debug_borders_around_fragment(display_list, flow_origin))
|
debug!("{:?}",
|
||||||
|
self.build_debug_borders_around_fragment(display_list, flow_origin, clip_rect))
|
||||||
|
|
||||||
// If this is an iframe, then send its position and size up to the constellation.
|
// If this is an iframe, then send its position and size up to the constellation.
|
||||||
//
|
//
|
||||||
|
@ -1240,8 +1254,6 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
accumulator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the intrinsic inline-sizes of this fragment.
|
/// Returns the intrinsic inline-sizes of this fragment.
|
||||||
|
@ -1800,6 +1812,28 @@ impl Fragment {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clip_rect_for_children(&self, current_clip_rect: Rect<Au>, flow_origin: Point2D<Au>)
|
||||||
|
-> Rect<Au> {
|
||||||
|
// Don't clip if we're text.
|
||||||
|
match self.specific {
|
||||||
|
ScannedTextFragment(_) => return current_clip_rect,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only clip if `overflow` tells us to.
|
||||||
|
match self.style.get_box().overflow {
|
||||||
|
overflow::hidden | overflow::auto | overflow::scroll => {}
|
||||||
|
_ => return current_clip_rect,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new clip rect.
|
||||||
|
//
|
||||||
|
// FIXME(#2795): Get the real container size.
|
||||||
|
let physical_rect = self.border_box.to_physical(self.style.writing_mode, Size2D::zero());
|
||||||
|
current_clip_rect.intersection(&Rect(physical_rect.origin + flow_origin,
|
||||||
|
physical_rect.size)).unwrap_or(ZERO_RECT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Show for Fragment {
|
impl fmt::Show for Fragment {
|
||||||
|
@ -1828,61 +1862,3 @@ impl fmt::Show for Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An object that accumulates display lists of child flows, applying a clipping rect if necessary.
|
|
||||||
pub struct ChildDisplayListAccumulator {
|
|
||||||
clip_display_item: Option<Box<ClipDisplayItem>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ChildDisplayListAccumulator {
|
|
||||||
/// Creates a `ChildDisplayListAccumulator` from the `overflow` property in the given style.
|
|
||||||
fn new(style: &ComputedValues,
|
|
||||||
bounds: Rect<Au>,
|
|
||||||
node: OpaqueNode,
|
|
||||||
level: StackingLevel,
|
|
||||||
may_need_clip: bool)
|
|
||||||
-> ChildDisplayListAccumulator {
|
|
||||||
ChildDisplayListAccumulator {
|
|
||||||
clip_display_item: match (may_need_clip, style.get_box().overflow) {
|
|
||||||
(true, overflow::hidden) | (true, overflow::auto) | (true, overflow::scroll) => {
|
|
||||||
Some(box ClipDisplayItem {
|
|
||||||
base: BaseDisplayItem::new(bounds, node, level),
|
|
||||||
children: DisplayList::new(),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
(false, _) | (_, overflow::visible) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pushes the given display item onto this display list.
|
|
||||||
pub fn push(&mut self, parent_display_list: &mut DisplayList, item: DisplayItem) {
|
|
||||||
match self.clip_display_item {
|
|
||||||
None => parent_display_list.push(item),
|
|
||||||
Some(ref mut clip_display_item) => clip_display_item.children.push(item),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pushes the display items from the given child onto this display list.
|
|
||||||
pub fn push_child(&mut self, parent_display_list: &mut DisplayList, child: &mut Flow) {
|
|
||||||
let kid_display_list = mem::replace(&mut flow::mut_base(child).display_list,
|
|
||||||
DisplayList::new());
|
|
||||||
match self.clip_display_item {
|
|
||||||
None => parent_display_list.push_all_move(kid_display_list),
|
|
||||||
Some(ref mut clip_display_item) => {
|
|
||||||
clip_display_item.children.push_all_move(kid_display_list)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes this accumulator and pushes the clipping item, if any, onto the given display
|
|
||||||
/// list.
|
|
||||||
pub fn finish(self, display_list: &mut DisplayList) {
|
|
||||||
let ChildDisplayListAccumulator {
|
|
||||||
clip_display_item
|
|
||||||
} = self;
|
|
||||||
match clip_display_item {
|
|
||||||
None => {}
|
|
||||||
Some(clip_display_item) => display_list.push(ClipDisplayItemClass(clip_display_item)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ use context::LayoutContext;
|
||||||
use floats::{FloatLeft, Floats, PlacementInfo};
|
use floats::{FloatLeft, Floats, PlacementInfo};
|
||||||
use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass, MutableFlowUtils};
|
use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass, MutableFlowUtils};
|
||||||
use flow;
|
use flow;
|
||||||
use fragment::{Fragment, InlineBlockFragment, ScannedTextFragment, ScannedTextFragmentInfo};
|
use fragment::{Fragment, InlineAbsoluteHypotheticalFragment, InlineBlockFragment};
|
||||||
use fragment::{SplitInfo};
|
use fragment::{ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
|
||||||
use layout_debug;
|
use layout_debug;
|
||||||
use model::IntrinsicISizes;
|
use model::IntrinsicISizes;
|
||||||
use text;
|
use text;
|
||||||
|
@ -18,7 +18,7 @@ use wrapper::ThreadSafeLayoutNode;
|
||||||
|
|
||||||
use collections::{Deque, RingBuf};
|
use collections::{Deque, RingBuf};
|
||||||
use geom::Rect;
|
use geom::Rect;
|
||||||
use gfx::display_list::ContentLevel;
|
use gfx::display_list::{ContentLevel, DisplayList};
|
||||||
use gfx::font::FontMetrics;
|
use gfx::font::FontMetrics;
|
||||||
use gfx::font_context::FontContext;
|
use gfx::font_context::FontContext;
|
||||||
use geom::Size2D;
|
use geom::Size2D;
|
||||||
|
@ -704,19 +704,20 @@ impl InlineFlow {
|
||||||
let fragment_position = self.base
|
let fragment_position = self.base
|
||||||
.abs_position
|
.abs_position
|
||||||
.add_size(&rel_offset.to_physical(self.base.writing_mode));
|
.add_size(&rel_offset.to_physical(self.base.writing_mode));
|
||||||
let mut accumulator = fragment.build_display_list(&mut self.base.display_list,
|
fragment.build_display_list(&mut self.base.display_list,
|
||||||
layout_context,
|
layout_context,
|
||||||
fragment_position,
|
fragment_position,
|
||||||
ContentLevel);
|
ContentLevel,
|
||||||
|
&self.base.clip_rect);
|
||||||
match fragment.specific {
|
match fragment.specific {
|
||||||
InlineBlockFragment(ref mut block_flow) => {
|
InlineBlockFragment(ref mut block_flow) => {
|
||||||
let block_flow = block_flow.flow_ref.get_mut();
|
let block_flow = block_flow.flow_ref.get_mut();
|
||||||
accumulator.push_child(&mut self.base.display_list, block_flow);
|
self.base.display_list.push_all_move(
|
||||||
|
mem::replace(&mut flow::mut_base(block_flow).display_list,
|
||||||
|
DisplayList::new()));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
accumulator.finish(&mut self.base.display_list);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1124,16 +1125,40 @@ impl Flow for InlineFlow {
|
||||||
|
|
||||||
fn compute_absolute_position(&mut self) {
|
fn compute_absolute_position(&mut self) {
|
||||||
for fragment in self.fragments.fragments.iter_mut() {
|
for fragment in self.fragments.fragments.iter_mut() {
|
||||||
match fragment.specific {
|
let absolute_position = match fragment.specific {
|
||||||
InlineBlockFragment(ref mut info) => {
|
InlineBlockFragment(ref mut info) => {
|
||||||
let block_flow = info.flow_ref.get_mut().as_block();
|
let block_flow = info.flow_ref.get_mut().as_block();
|
||||||
|
|
||||||
// FIXME(#2795): Get the real container size
|
// FIXME(#2795): Get the real container size
|
||||||
let container_size = Size2D::zero();
|
let container_size = Size2D::zero();
|
||||||
block_flow.base.abs_position =
|
block_flow.base.abs_position =
|
||||||
self.base.abs_position +
|
self.base.abs_position +
|
||||||
fragment.border_box.start.to_physical(self.base.writing_mode,
|
fragment.border_box.start.to_physical(self.base.writing_mode,
|
||||||
container_size);
|
container_size);
|
||||||
|
block_flow.base.abs_position
|
||||||
|
}
|
||||||
|
InlineAbsoluteHypotheticalFragment(ref mut info) => {
|
||||||
|
let block_flow = info.flow_ref.get_mut().as_block();
|
||||||
|
// FIXME(#2795): Get the real container size
|
||||||
|
let container_size = Size2D::zero();
|
||||||
|
block_flow.base.abs_position =
|
||||||
|
self.base.abs_position +
|
||||||
|
fragment.border_box.start.to_physical(self.base.writing_mode,
|
||||||
|
container_size);
|
||||||
|
block_flow.base.abs_position
|
||||||
|
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let clip_rect = fragment.clip_rect_for_children(self.base.clip_rect,
|
||||||
|
absolute_position);
|
||||||
|
|
||||||
|
match fragment.specific {
|
||||||
|
InlineBlockFragment(ref mut info) => {
|
||||||
|
flow::mut_base(info.flow_ref.get_mut()).clip_rect = clip_rect
|
||||||
|
}
|
||||||
|
InlineAbsoluteHypotheticalFragment(ref mut info) => {
|
||||||
|
flow::mut_base(info.flow_ref.get_mut()).clip_rect = clip_rect
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ use encoding::all::UTF_8;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
use gfx::display_list::{ClipDisplayItemClass, ContentStackingLevel, DisplayItem};
|
use gfx::display_list::{ContentStackingLevel, DisplayItem, DisplayItemIterator, DisplayList};
|
||||||
use gfx::display_list::{DisplayItemIterator, DisplayList, OpaqueNode};
|
use gfx::display_list::{OpaqueNode};
|
||||||
use gfx::render_task::{RenderInitMsg, RenderChan, RenderLayer};
|
use gfx::render_task::{RenderInitMsg, RenderChan, RenderLayer};
|
||||||
use gfx::{render_task, color};
|
use gfx::{render_task, color};
|
||||||
use layout_traits;
|
use layout_traits;
|
||||||
|
@ -852,7 +852,6 @@ impl LayoutRPC for LayoutRPCImpl {
|
||||||
mut iter: DisplayItemIterator,
|
mut iter: DisplayItemIterator,
|
||||||
node: OpaqueNode) {
|
node: OpaqueNode) {
|
||||||
for item in iter {
|
for item in iter {
|
||||||
union_boxes_for_node(accumulator, item.children(), node);
|
|
||||||
if item.base().node == node {
|
if item.base().node == node {
|
||||||
match *accumulator {
|
match *accumulator {
|
||||||
None => *accumulator = Some(item.base().bounds),
|
None => *accumulator = Some(item.base().bounds),
|
||||||
|
@ -884,7 +883,6 @@ impl LayoutRPC for LayoutRPCImpl {
|
||||||
mut iter: DisplayItemIterator,
|
mut iter: DisplayItemIterator,
|
||||||
node: OpaqueNode) {
|
node: OpaqueNode) {
|
||||||
for item in iter {
|
for item in iter {
|
||||||
add_boxes_for_node(accumulator, item.children(), node);
|
|
||||||
if item.base().node == node {
|
if item.base().node == node {
|
||||||
accumulator.push(item.base().bounds)
|
accumulator.push(item.base().bounds)
|
||||||
}
|
}
|
||||||
|
@ -907,47 +905,25 @@ impl LayoutRPC for LayoutRPCImpl {
|
||||||
|
|
||||||
/// Requests the node containing the point of interest
|
/// Requests the node containing the point of interest
|
||||||
fn hit_test(&self, _: TrustedNodeAddress, point: Point2D<f32>) -> Result<HitTestResponse, ()> {
|
fn hit_test(&self, _: TrustedNodeAddress, point: Point2D<f32>) -> Result<HitTestResponse, ()> {
|
||||||
fn hit_test<'a,I:Iterator<&'a DisplayItem>>(x: Au, y: Au, mut iterator: I)
|
fn hit_test<'a,I>(point: Point2D<Au>, mut iterator: I)
|
||||||
-> Option<HitTestResponse> {
|
-> Option<HitTestResponse>
|
||||||
|
where I: Iterator<&'a DisplayItem> {
|
||||||
for item in iterator {
|
for item in iterator {
|
||||||
match *item {
|
// TODO(tikue): This check should really be performed by a method of `DisplayItem`.
|
||||||
ClipDisplayItemClass(ref cc) => {
|
if geometry::rect_contains_point(item.base().clip_rect, point) &&
|
||||||
if geometry::rect_contains_point(cc.base.bounds, Point2D(x, y)) {
|
geometry::rect_contains_point(item.bounds(), point) {
|
||||||
let ret = hit_test(x, y, cc.children.list.iter().rev());
|
return Some(HitTestResponse(item.base().node.to_untrusted_node_address()))
|
||||||
if !ret.is_none() {
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
None
|
||||||
}
|
}
|
||||||
_ => {}
|
let point = Point2D(Au::from_frac_px(point.x as f64), Au::from_frac_px(point.y as f64));
|
||||||
}
|
|
||||||
|
|
||||||
let bounds = item.bounds();
|
|
||||||
|
|
||||||
// TODO(tikue): This check should really be performed by a method of
|
|
||||||
// DisplayItem.
|
|
||||||
if x < bounds.origin.x + bounds.size.width &&
|
|
||||||
bounds.origin.x <= x &&
|
|
||||||
y < bounds.origin.y + bounds.size.height &&
|
|
||||||
bounds.origin.y <= y {
|
|
||||||
return Some(HitTestResponse(item.base()
|
|
||||||
.node
|
|
||||||
.to_untrusted_node_address()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let ret: Option<HitTestResponse> = None;
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
let (x, y) = (Au::from_frac_px(point.x as f64),
|
|
||||||
Au::from_frac_px(point.y as f64));
|
|
||||||
|
|
||||||
let resp = {
|
let resp = {
|
||||||
let &LayoutRPCImpl(ref rw_data) = self;
|
let &LayoutRPCImpl(ref rw_data) = self;
|
||||||
let rw_data = rw_data.lock();
|
let rw_data = rw_data.lock();
|
||||||
match rw_data.display_list {
|
match rw_data.display_list {
|
||||||
None => fail!("no display list!"),
|
None => fail!("no display list!"),
|
||||||
Some(ref display_list) => hit_test(x, y, display_list.list.iter().rev()),
|
Some(ref display_list) => hit_test(point, display_list.list.iter().rev()),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -957,49 +933,29 @@ impl LayoutRPC for LayoutRPCImpl {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_over(&self, _: TrustedNodeAddress, point: Point2D<f32>) -> Result<MouseOverResponse, ()> {
|
fn mouse_over(&self, _: TrustedNodeAddress, point: Point2D<f32>)
|
||||||
fn mouse_over_test<'a,
|
-> Result<MouseOverResponse, ()> {
|
||||||
I:Iterator<&'a DisplayItem>>(
|
fn mouse_over_test<'a,I>(point: Point2D<Au>,
|
||||||
x: Au,
|
|
||||||
y: Au,
|
|
||||||
mut iterator: I,
|
mut iterator: I,
|
||||||
result: &mut Vec<UntrustedNodeAddress>) {
|
result: &mut Vec<UntrustedNodeAddress>)
|
||||||
|
where I: Iterator<&'a DisplayItem> {
|
||||||
for item in iterator {
|
for item in iterator {
|
||||||
match *item {
|
// TODO(tikue): This check should really be performed by a method of `DisplayItem`.
|
||||||
ClipDisplayItemClass(ref cc) => {
|
if geometry::rect_contains_point(item.bounds(), point) {
|
||||||
mouse_over_test(x, y, cc.children.list.iter().rev(), result);
|
result.push(item.base().node.to_untrusted_node_address())
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let bounds = item.bounds();
|
|
||||||
|
|
||||||
// TODO(tikue): This check should really be performed by a method
|
|
||||||
// of DisplayItem.
|
|
||||||
if x < bounds.origin.x + bounds.size.width &&
|
|
||||||
bounds.origin.x <= x &&
|
|
||||||
y < bounds.origin.y + bounds.size.height &&
|
|
||||||
bounds.origin.y <= y {
|
|
||||||
result.push(item.base()
|
|
||||||
.node
|
|
||||||
.to_untrusted_node_address());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut mouse_over_list: Vec<UntrustedNodeAddress> = vec!();
|
let mut mouse_over_list: Vec<UntrustedNodeAddress> = vec!();
|
||||||
let (x, y) = (Au::from_frac_px(point.x as f64), Au::from_frac_px(point.y as f64));
|
let point = Point2D(Au::from_frac_px(point.x as f64), Au::from_frac_px(point.y as f64));
|
||||||
|
|
||||||
{
|
{
|
||||||
let &LayoutRPCImpl(ref rw_data) = self;
|
let &LayoutRPCImpl(ref rw_data) = self;
|
||||||
let rw_data = rw_data.lock();
|
let rw_data = rw_data.lock();
|
||||||
match rw_data.display_list {
|
match rw_data.display_list {
|
||||||
None => fail!("no display list!"),
|
None => fail!("no display list!"),
|
||||||
Some(ref display_list) => {
|
Some(ref display_list) => {
|
||||||
mouse_over_test(x,
|
mouse_over_test(point, display_list.list.iter().rev(), &mut mouse_over_list);
|
||||||
y,
|
|
||||||
display_list.list.iter().rev(),
|
|
||||||
&mut mouse_over_list);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,8 +188,6 @@ trait ParallelPostorderDomTraversal : PostorderDomTraversal {
|
||||||
pub struct FlowParallelInfo {
|
pub struct FlowParallelInfo {
|
||||||
/// The number of children that still need work done.
|
/// The number of children that still need work done.
|
||||||
pub children_count: AtomicInt,
|
pub children_count: AtomicInt,
|
||||||
/// The number of children and absolute descendants that still need work done.
|
|
||||||
pub children_and_absolute_descendant_count: AtomicInt,
|
|
||||||
/// The address of the parent flow.
|
/// The address of the parent flow.
|
||||||
pub parent: UnsafeFlow,
|
pub parent: UnsafeFlow,
|
||||||
}
|
}
|
||||||
|
@ -198,7 +196,6 @@ impl FlowParallelInfo {
|
||||||
pub fn new() -> FlowParallelInfo {
|
pub fn new() -> FlowParallelInfo {
|
||||||
FlowParallelInfo {
|
FlowParallelInfo {
|
||||||
children_count: AtomicInt::new(0),
|
children_count: AtomicInt::new(0),
|
||||||
children_and_absolute_descendant_count: AtomicInt::new(0),
|
|
||||||
parent: null_unsafe_flow(),
|
parent: null_unsafe_flow(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,41 +379,14 @@ fn compute_absolute_position(unsafe_flow: UnsafeFlow,
|
||||||
// Compute the absolute position for the flow.
|
// Compute the absolute position for the flow.
|
||||||
flow.get_mut().compute_absolute_position();
|
flow.get_mut().compute_absolute_position();
|
||||||
|
|
||||||
// If we are the containing block, count the number of absolutely-positioned children, so
|
// Enqueue all children.
|
||||||
// that we don't double-count them in the `children_and_absolute_descendant_count`
|
|
||||||
// reference count.
|
|
||||||
let mut absolutely_positioned_child_count = 0u;
|
|
||||||
for kid in flow::child_iter(flow.get_mut()) {
|
for kid in flow::child_iter(flow.get_mut()) {
|
||||||
if kid.is_absolutely_positioned() {
|
|
||||||
absolutely_positioned_child_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(flow::mut_base(flow.get_mut()).parallel
|
|
||||||
.children_and_absolute_descendant_count
|
|
||||||
.fetch_sub(absolutely_positioned_child_count as int,
|
|
||||||
SeqCst));
|
|
||||||
|
|
||||||
// Enqueue all non-absolutely-positioned children.
|
|
||||||
for kid in flow::child_iter(flow.get_mut()) {
|
|
||||||
if !kid.is_absolutely_positioned() {
|
|
||||||
had_descendants = true;
|
had_descendants = true;
|
||||||
proxy.push(WorkUnit {
|
proxy.push(WorkUnit {
|
||||||
fun: compute_absolute_position,
|
fun: compute_absolute_position,
|
||||||
data: borrowed_flow_to_unsafe_flow(kid),
|
data: borrowed_flow_to_unsafe_flow(kid),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Possibly enqueue absolute descendants.
|
|
||||||
for absolute_descendant_link in flow::mut_base(flow.get_mut()).abs_descendants.iter() {
|
|
||||||
had_descendants = true;
|
|
||||||
let descendant = absolute_descendant_link;
|
|
||||||
proxy.push(WorkUnit {
|
|
||||||
fun: compute_absolute_position,
|
|
||||||
data: borrowed_flow_to_unsafe_flow(descendant),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there were no more descendants, start building the display list.
|
// If there were no more descendants, start building the display list.
|
||||||
if !had_descendants {
|
if !had_descendants {
|
||||||
|
@ -441,26 +411,12 @@ fn build_display_list(mut unsafe_flow: UnsafeFlow,
|
||||||
{
|
{
|
||||||
let base = flow::mut_base(flow.get_mut());
|
let base = flow::mut_base(flow.get_mut());
|
||||||
|
|
||||||
// Reset the count of children and absolute descendants for the next layout
|
// Reset the count of children for the next layout traversal.
|
||||||
// traversal.
|
base.parallel.children_count.store(base.children.len() as int, Relaxed);
|
||||||
let children_and_absolute_descendant_count = base.children.len() +
|
|
||||||
base.abs_descendants.len();
|
|
||||||
base.parallel
|
|
||||||
.children_and_absolute_descendant_count
|
|
||||||
.store(children_and_absolute_descendant_count as int, Relaxed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Possibly enqueue the parent.
|
// Possibly enqueue the parent.
|
||||||
let unsafe_parent = if flow.get().is_absolutely_positioned() {
|
let unsafe_parent = flow::mut_base(flow.get_mut()).parallel.parent;
|
||||||
match *flow::mut_base(flow.get_mut()).absolute_cb.get() {
|
|
||||||
None => fail!("no absolute containing block for absolutely positioned?!"),
|
|
||||||
Some(ref mut absolute_cb) => {
|
|
||||||
mut_borrowed_flow_to_unsafe_flow(absolute_cb.get_mut())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flow::mut_base(flow.get_mut()).parallel.parent
|
|
||||||
};
|
|
||||||
if unsafe_parent == null_unsafe_flow() {
|
if unsafe_parent == null_unsafe_flow() {
|
||||||
// We're done!
|
// We're done!
|
||||||
break
|
break
|
||||||
|
@ -472,7 +428,7 @@ fn build_display_list(mut unsafe_flow: UnsafeFlow,
|
||||||
let parent: &mut FlowRef = mem::transmute(&unsafe_parent);
|
let parent: &mut FlowRef = mem::transmute(&unsafe_parent);
|
||||||
let parent_base = flow::mut_base(parent.get_mut());
|
let parent_base = flow::mut_base(parent.get_mut());
|
||||||
if parent_base.parallel
|
if parent_base.parallel
|
||||||
.children_and_absolute_descendant_count
|
.children_count
|
||||||
.fetch_sub(1, SeqCst) == 1 {
|
.fetch_sub(1, SeqCst) == 1 {
|
||||||
// We were the last child of our parent. Build display lists for our parent.
|
// We were the last child of our parent. Build display lists for our parent.
|
||||||
unsafe_flow = unsafe_parent
|
unsafe_flow = unsafe_parent
|
||||||
|
|
|
@ -323,14 +323,8 @@ impl<'a> BuildDisplayList<'a> {
|
||||||
flow.compute_absolute_position();
|
flow.compute_absolute_position();
|
||||||
|
|
||||||
for kid in flow::mut_base(flow).child_iter() {
|
for kid in flow::mut_base(flow).child_iter() {
|
||||||
if !kid.is_absolutely_positioned() {
|
|
||||||
self.process(kid)
|
self.process(kid)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for absolute_descendant_link in flow::mut_base(flow).abs_descendants.iter() {
|
|
||||||
self.process(absolute_descendant_link)
|
|
||||||
}
|
|
||||||
|
|
||||||
flow.build_display_list(self.layout_context)
|
flow.build_display_list(self.layout_context)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,29 @@ impl Default for Au {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub static ZERO_RECT: Rect<Au> = Rect {
|
||||||
|
origin: Point2D {
|
||||||
|
x: Au(0),
|
||||||
|
y: Au(0),
|
||||||
|
},
|
||||||
|
size: Size2D {
|
||||||
|
width: Au(0),
|
||||||
|
height: Au(0),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub static MAX_RECT: Rect<Au> = Rect {
|
||||||
|
origin: Point2D {
|
||||||
|
x: Au(i32::MIN / 2),
|
||||||
|
y: Au(i32::MIN / 2),
|
||||||
|
},
|
||||||
|
size: Size2D {
|
||||||
|
width: MAX_AU,
|
||||||
|
height: MAX_AU,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub static MIN_AU: Au = Au(i32::MIN);
|
||||||
pub static MAX_AU: Au = Au(i32::MAX);
|
pub static MAX_AU: Au = Au(i32::MAX);
|
||||||
|
|
||||||
impl<E, S: Encoder<E>> Encodable<S, E> for Au {
|
impl<E, S: Encoder<E>> Encodable<S, E> for Au {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue