mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
auto merge of #4460 : pcwalton/servo/stacking-context-overflow, r=glennw
This was making `box-shadow` not show up in many cases, in particular, but the effects were not limited to that. r? @glennw
This commit is contained in:
commit
499d17f564
34 changed files with 881 additions and 568 deletions
|
@ -283,8 +283,7 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
self.clamp_scroll_offset_and_scroll_layer(scroll_offset + delta)
|
||||
}
|
||||
|
||||
fn clamp_scroll_offset_and_scroll_layer(&self,
|
||||
new_offset: TypedPoint2D<LayerPixel, f32>)
|
||||
fn clamp_scroll_offset_and_scroll_layer(&self, new_offset: TypedPoint2D<LayerPixel, f32>)
|
||||
-> ScrollEventResult {
|
||||
let layer_size = self.bounds.borrow().size;
|
||||
let content_size = calculate_content_size_for_layer(self);
|
||||
|
@ -339,17 +338,14 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
let _ = chan.send_opt(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message));
|
||||
}
|
||||
|
||||
fn scroll_layer_and_all_child_layers(&self,
|
||||
new_offset: TypedPoint2D<LayerPixel, f32>)
|
||||
fn scroll_layer_and_all_child_layers(&self, new_offset: TypedPoint2D<LayerPixel, f32>)
|
||||
-> bool {
|
||||
let mut result = false;
|
||||
|
||||
// Only scroll this layer if it's not fixed-positioned.
|
||||
if self.extra_data.borrow().scroll_policy != FixedPosition {
|
||||
let new_offset = new_offset.to_untyped();
|
||||
*self.transform.borrow_mut() = identity().translate(new_offset.x,
|
||||
new_offset.y,
|
||||
0.0);
|
||||
*self.transform.borrow_mut() = identity().translate(new_offset.x, new_offset.y, 0.0);
|
||||
*self.content_offset.borrow_mut() = Point2D::from_untyped(&new_offset);
|
||||
result = true
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ use servo_msg::compositor_msg::LayerId;
|
|||
use servo_net::image::base::Image;
|
||||
use servo_util::cursor::Cursor;
|
||||
use servo_util::dlist as servo_dlist;
|
||||
use servo_util::geometry::{mod, Au, MAX_RECT, ZERO_POINT, ZERO_RECT};
|
||||
use servo_util::geometry::{mod, Au, MAX_RECT, ZERO_RECT};
|
||||
use servo_util::range::Range;
|
||||
use servo_util::smallvec::{SmallVec, SmallVec8};
|
||||
use std::fmt;
|
||||
|
@ -160,9 +160,8 @@ pub struct StackingContext {
|
|||
pub layer: Option<Arc<PaintLayer>>,
|
||||
/// The position and size of this stacking context.
|
||||
pub bounds: Rect<Au>,
|
||||
/// The clipping rect for this stacking context, in the coordinate system of the *parent*
|
||||
/// stacking context.
|
||||
pub clip_rect: Rect<Au>,
|
||||
/// The overflow rect for this stacking context in its coordinate system.
|
||||
pub overflow: Rect<Au>,
|
||||
/// The `z-index` for this stacking context.
|
||||
pub z_index: i32,
|
||||
/// The opacity of this stacking context.
|
||||
|
@ -171,12 +170,10 @@ pub struct StackingContext {
|
|||
|
||||
impl StackingContext {
|
||||
/// Creates a new stacking context.
|
||||
///
|
||||
/// TODO(pcwalton): Stacking contexts should not always be clipped to their bounds, to handle
|
||||
/// overflow properly.
|
||||
#[inline]
|
||||
pub fn new(display_list: Box<DisplayList>,
|
||||
bounds: Rect<Au>,
|
||||
bounds: &Rect<Au>,
|
||||
overflow: &Rect<Au>,
|
||||
z_index: i32,
|
||||
opacity: AzFloat,
|
||||
layer: Option<Arc<PaintLayer>>)
|
||||
|
@ -184,8 +181,8 @@ impl StackingContext {
|
|||
StackingContext {
|
||||
display_list: display_list,
|
||||
layer: layer,
|
||||
bounds: bounds,
|
||||
clip_rect: Rect(ZERO_POINT, bounds.size),
|
||||
bounds: *bounds,
|
||||
overflow: *overflow,
|
||||
z_index: z_index,
|
||||
opacity: opacity,
|
||||
}
|
||||
|
@ -196,7 +193,7 @@ impl StackingContext {
|
|||
paint_context: &mut PaintContext,
|
||||
tile_bounds: &Rect<AzFloat>,
|
||||
transform: &Matrix2D<AzFloat>,
|
||||
clip_rect: Option<Rect<Au>>) {
|
||||
clip_rect: Option<&Rect<Au>>) {
|
||||
let temporary_draw_target =
|
||||
paint_context.get_or_create_temporary_draw_target(self.opacity);
|
||||
{
|
||||
|
@ -205,7 +202,7 @@ impl StackingContext {
|
|||
font_ctx: &mut *paint_context.font_ctx,
|
||||
page_rect: paint_context.page_rect,
|
||||
screen_rect: paint_context.screen_rect,
|
||||
clip_rect: clip_rect,
|
||||
clip_rect: clip_rect.map(|clip_rect| *clip_rect),
|
||||
transient_clip: None,
|
||||
};
|
||||
|
||||
|
@ -252,7 +249,7 @@ impl StackingContext {
|
|||
positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext,
|
||||
&new_tile_rect,
|
||||
&new_transform,
|
||||
Some(positioned_kid.clip_rect))
|
||||
Some(&positioned_kid.overflow))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,7 +292,7 @@ impl StackingContext {
|
|||
positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext,
|
||||
&new_tile_rect,
|
||||
&new_transform,
|
||||
Some(positioned_kid.clip_rect))
|
||||
Some(&positioned_kid.overflow))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,11 +326,18 @@ impl StackingContext {
|
|||
}
|
||||
};
|
||||
|
||||
let child_stacking_context_bounds = child_stacking_context.bounds.to_azure_rect();
|
||||
let tile_subrect = tile_bounds.intersection(&child_stacking_context_bounds)
|
||||
// Translate the child's overflow region into our coordinate system.
|
||||
let child_stacking_context_overflow =
|
||||
child_stacking_context.overflow.translate(&child_stacking_context.bounds.origin)
|
||||
.to_azure_rect();
|
||||
|
||||
// Intersect that with the current tile boundaries to find the tile boundaries that the
|
||||
// child covers.
|
||||
let tile_subrect = tile_bounds.intersection(&child_stacking_context_overflow)
|
||||
.unwrap_or(ZERO_AZURE_RECT);
|
||||
let offset = tile_subrect.origin - child_stacking_context_bounds.origin;
|
||||
Rect(offset, tile_subrect.size)
|
||||
|
||||
// Translate the resulting rect into the child's coordinate system.
|
||||
tile_subrect.translate(&-child_stacking_context.bounds.to_azure_rect().origin)
|
||||
}
|
||||
|
||||
/// Places all nodes containing the point of interest into `result`, topmost first. If
|
||||
|
@ -605,6 +609,20 @@ impl ClippingRegion {
|
|||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Translates this clipping region by the given vector.
|
||||
#[inline]
|
||||
pub fn translate(&self, delta: &Point2D<Au>) -> ClippingRegion {
|
||||
ClippingRegion {
|
||||
main: self.main.translate(delta),
|
||||
complex: self.complex.iter().map(|complex| {
|
||||
ComplexClippingRegion {
|
||||
rect: complex.rect.translate(delta),
|
||||
radii: complex.radii,
|
||||
}
|
||||
}).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata attached to each display item. This is useful for performing auxiliary tasks with
|
||||
|
|
|
@ -59,7 +59,8 @@ impl DisplayListOptimizer {
|
|||
mut stacking_contexts: I)
|
||||
where I: Iterator<&'a Arc<StackingContext>> {
|
||||
for stacking_context in stacking_contexts {
|
||||
if self.visible_rect.intersects(&stacking_context.bounds) {
|
||||
let overflow = stacking_context.overflow.translate(&stacking_context.bounds.origin);
|
||||
if self.visible_rect.intersects(&overflow) {
|
||||
result_list.push_back((*stacking_context).clone())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,20 +148,21 @@ fn initialize_layers<C>(compositor: &mut C,
|
|||
stacking_context: &StackingContext,
|
||||
page_position: &Point2D<Au>) {
|
||||
let page_position = stacking_context.bounds.origin + *page_position;
|
||||
match stacking_context.layer {
|
||||
None => {}
|
||||
Some(ref paint_layer) => {
|
||||
metadata.push(LayerMetadata {
|
||||
id: paint_layer.id,
|
||||
position:
|
||||
Rect(Point2D(page_position.x.to_nearest_px() as uint,
|
||||
page_position.y.to_nearest_px() as uint),
|
||||
Size2D(stacking_context.bounds.size.width.to_nearest_px() as uint,
|
||||
stacking_context.bounds.size.height.to_nearest_px() as uint)),
|
||||
background_color: paint_layer.background_color,
|
||||
scroll_policy: paint_layer.scroll_policy,
|
||||
})
|
||||
}
|
||||
if let Some(ref paint_layer) = stacking_context.layer {
|
||||
// Layers start at the top left of their overflow rect, as far as the info we give to
|
||||
// the compositor is concerned.
|
||||
let overflow_relative_page_position = page_position + stacking_context.overflow.origin;
|
||||
let layer_position =
|
||||
Rect(Point2D(overflow_relative_page_position.x.to_nearest_px() as i32,
|
||||
overflow_relative_page_position.y.to_nearest_px() as i32),
|
||||
Size2D(stacking_context.overflow.size.width.to_nearest_px() as i32,
|
||||
stacking_context.overflow.size.height.to_nearest_px() as i32));
|
||||
metadata.push(LayerMetadata {
|
||||
id: paint_layer.id,
|
||||
position: layer_position,
|
||||
background_color: paint_layer.background_color,
|
||||
scroll_policy: paint_layer.scroll_policy,
|
||||
})
|
||||
}
|
||||
|
||||
for kid in stacking_context.display_list.children.iter() {
|
||||
|
@ -384,15 +385,14 @@ impl<C> PaintTask<C> where C: PaintListener + Send {
|
|||
layer_id: LayerId) {
|
||||
profile(TimeProfilerCategory::Painting, None, self.time_profiler_chan.clone(), || {
|
||||
// Bail out if there is no appropriate stacking context.
|
||||
let stacking_context = match self.root_stacking_context {
|
||||
Some(ref stacking_context) => {
|
||||
match display_list::find_stacking_context_with_layer_id(stacking_context,
|
||||
layer_id) {
|
||||
Some(stacking_context) => stacking_context,
|
||||
None => return,
|
||||
}
|
||||
let stacking_context = if let Some(ref stacking_context) = self.root_stacking_context {
|
||||
match display_list::find_stacking_context_with_layer_id(stacking_context,
|
||||
layer_id) {
|
||||
Some(stacking_context) => stacking_context,
|
||||
None => return,
|
||||
}
|
||||
None => return,
|
||||
} else {
|
||||
return
|
||||
};
|
||||
|
||||
// Divide up the layer into tiles and distribute them to workers via a simple round-
|
||||
|
@ -547,8 +547,13 @@ impl WorkerThread {
|
|||
transient_clip: None,
|
||||
};
|
||||
|
||||
// Apply a translation to start at the boundaries of the stacking context, since the
|
||||
// layer's origin starts at its overflow rect's origin.
|
||||
let tile_bounds = tile.page_rect.translate(
|
||||
&Point2D(stacking_context.overflow.origin.x.to_subpx() as AzFloat,
|
||||
stacking_context.overflow.origin.y.to_subpx() as AzFloat));
|
||||
|
||||
// Apply the translation to paint the tile we want.
|
||||
let tile_bounds = tile.page_rect;
|
||||
let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
|
||||
let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
|
||||
let matrix = matrix.translate(-tile_bounds.origin.x as AzFloat,
|
||||
|
@ -561,7 +566,7 @@ impl WorkerThread {
|
|||
profile(TimeProfilerCategory::PaintingPerTile, None,
|
||||
self.time_profiler_sender.clone(), || {
|
||||
stacking_context.optimize_and_draw_into_context(&mut paint_context,
|
||||
&tile.page_rect,
|
||||
&tile_bounds,
|
||||
&matrix,
|
||||
None);
|
||||
paint_context.draw_target.flush();
|
||||
|
|
|
@ -32,7 +32,7 @@ use context::LayoutContext;
|
|||
use css::node_style::StyledNode;
|
||||
use display_list_builder::{BlockFlowDisplayListBuilding, FragmentDisplayListBuilding};
|
||||
use floats::{ClearType, FloatKind, Floats, PlacementInfo};
|
||||
use flow::{AbsolutePositionInfo, BaseFlow, ForceNonfloatedFlag, FlowClass, Flow};
|
||||
use flow::{mod, AbsolutePositionInfo, BaseFlow, ForceNonfloatedFlag, FlowClass, Flow};
|
||||
use flow::{ImmutableFlowUtils, MutableFlowUtils, PreorderFlowTraversal};
|
||||
use flow::{PostorderFlowTraversal, mut_base};
|
||||
use flow::{HAS_LEFT_FLOATED_DESCENDANTS, HAS_RIGHT_FLOATED_DESCENDANTS};
|
||||
|
@ -40,8 +40,7 @@ use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
|
|||
use flow::{LAYERS_NEEDED_FOR_DESCENDANTS, NEEDS_LAYER};
|
||||
use flow::{IS_ABSOLUTELY_POSITIONED};
|
||||
use flow::{CLEARS_LEFT, CLEARS_RIGHT};
|
||||
use flow;
|
||||
use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo};
|
||||
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||
use layout_debug;
|
||||
use model::{IntrinsicISizes, MarginCollapseInfo};
|
||||
|
@ -49,11 +48,11 @@ use model::{MaybeAuto, CollapsibleMargins, specified, specified_or_none};
|
|||
use table::ColumnComputedInlineSize;
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::Size2D;
|
||||
use geom::{Point2D, Rect, Size2D};
|
||||
use gfx::display_list::{ClippingRegion, DisplayList};
|
||||
use serialize::{Encoder, Encodable};
|
||||
use servo_msg::compositor_msg::LayerId;
|
||||
use servo_util::geometry::{Au, MAX_AU, ZERO_POINT};
|
||||
use servo_util::geometry::{Au, MAX_AU};
|
||||
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
|
||||
use servo_util::opts;
|
||||
use std::cmp::{max, min};
|
||||
|
@ -1769,23 +1768,40 @@ impl Flow for BlockFlow {
|
|||
};
|
||||
|
||||
// Compute the origin and clipping rectangle for children.
|
||||
let origin_for_children = if self.fragment.establishes_stacking_context() {
|
||||
ZERO_POINT
|
||||
let relative_offset = relative_offset.to_physical(self.base.writing_mode);
|
||||
let origin_for_children;
|
||||
let clip_in_child_coordinate_system;
|
||||
if self.fragment.establishes_stacking_context() {
|
||||
// We establish a stacking context, so the position of our children is vertically
|
||||
// correct, but has to be adjusted to accommodate horizontal margins. (Note the
|
||||
// calculation involving `position` below and recall that inline-direction flow
|
||||
// positions are relative to the edges of the margin box.)
|
||||
//
|
||||
// FIXME(pcwalton): Is this vertical-writing-direction-safe?
|
||||
let margin = self.fragment.margin.to_physical(self.base.writing_mode);
|
||||
origin_for_children = Point2D(-margin.left, Au(0)) + relative_offset;
|
||||
clip_in_child_coordinate_system =
|
||||
self.base.clip.translate(&-self.base.stacking_relative_position)
|
||||
} else {
|
||||
self.base.stacking_relative_position
|
||||
};
|
||||
let clip = self.fragment.clipping_region_for_children(&self.base.clip,
|
||||
&origin_for_children);
|
||||
origin_for_children = self.base.stacking_relative_position + relative_offset;
|
||||
clip_in_child_coordinate_system = self.base.clip.clone()
|
||||
}
|
||||
let stacking_relative_border_box =
|
||||
self.fragment
|
||||
.stacking_relative_border_box(&self.base.stacking_relative_position,
|
||||
&self.base
|
||||
.absolute_position_info
|
||||
.relative_containing_block_size,
|
||||
CoordinateSystem::Self);
|
||||
let clip = self.fragment.clipping_region_for_children(&clip_in_child_coordinate_system,
|
||||
&stacking_relative_border_box);
|
||||
|
||||
// Process children.
|
||||
let writing_mode = self.base.writing_mode;
|
||||
for kid in self.base.child_iter() {
|
||||
if !flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) {
|
||||
let kid_base = flow::mut_base(kid);
|
||||
kid_base.stacking_relative_position =
|
||||
origin_for_children
|
||||
+ kid_base.position.start.to_physical(kid_base.writing_mode, container_size)
|
||||
+ relative_offset.to_physical(writing_mode);
|
||||
kid_base.stacking_relative_position = origin_for_children +
|
||||
kid_base.position.start.to_physical(kid_base.writing_mode, container_size);
|
||||
}
|
||||
|
||||
flow::mut_base(kid).absolute_position_info = absolute_position_info_for_children;
|
||||
|
@ -1797,13 +1813,6 @@ impl Flow for BlockFlow {
|
|||
self.flags.insert(IS_ROOT)
|
||||
}
|
||||
|
||||
/// Return true if store overflow is delayed for this flow.
|
||||
///
|
||||
/// Currently happens only for absolutely positioned flows.
|
||||
fn is_store_overflow_delayed(&mut self) -> bool {
|
||||
self.base.flags.contains(IS_ABSOLUTELY_POSITIONED)
|
||||
}
|
||||
|
||||
fn is_root(&self) -> bool {
|
||||
self.flags.contains(IS_ROOT)
|
||||
}
|
||||
|
@ -1839,16 +1848,20 @@ impl Flow for BlockFlow {
|
|||
|
||||
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
|
||||
if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) &&
|
||||
self.fragment.style().logical_position().inline_start == LengthOrPercentageOrAuto::Auto &&
|
||||
self.fragment.style().logical_position().inline_end == LengthOrPercentageOrAuto::Auto {
|
||||
self.fragment.style().logical_position().inline_start ==
|
||||
LengthOrPercentageOrAuto::Auto &&
|
||||
self.fragment.style().logical_position().inline_end ==
|
||||
LengthOrPercentageOrAuto::Auto {
|
||||
self.base.position.start.i = inline_position
|
||||
}
|
||||
}
|
||||
|
||||
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
|
||||
if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) &&
|
||||
self.fragment.style().logical_position().block_start == LengthOrPercentageOrAuto::Auto &&
|
||||
self.fragment.style().logical_position().block_end == LengthOrPercentageOrAuto::Auto {
|
||||
self.fragment.style().logical_position().block_start ==
|
||||
LengthOrPercentageOrAuto::Auto &&
|
||||
self.fragment.style().logical_position().block_end ==
|
||||
LengthOrPercentageOrAuto::Auto {
|
||||
self.base.position.start.b = block_position
|
||||
}
|
||||
}
|
||||
|
@ -1864,19 +1877,36 @@ impl Flow for BlockFlow {
|
|||
self.fragment.repair_style(new_style)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
if iterator.should_process(&self.fragment) {
|
||||
let fragment_origin =
|
||||
self.base.stacking_relative_position_of_child_fragment(&self.fragment);
|
||||
iterator.process(&self.fragment,
|
||||
self.fragment.stacking_relative_bounds(&fragment_origin));
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
self.fragment.compute_overflow()
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
if !iterator.should_process(&self.fragment) {
|
||||
return
|
||||
}
|
||||
|
||||
iterator.process(&self.fragment,
|
||||
&self.fragment
|
||||
.stacking_relative_border_box(&self.base.stacking_relative_position,
|
||||
&self.base
|
||||
.absolute_position_info
|
||||
.relative_containing_block_size,
|
||||
CoordinateSystem::Parent)
|
||||
.translate(stacking_context_position));
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Show for BlockFlow {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} - {:x}: frag={} ({})", self.class(), self.base.debug_id(), self.fragment, self.base)
|
||||
write!(f,
|
||||
"{} - {:x}: frag={} ({})",
|
||||
self.class(),
|
||||
self.base.debug_id(),
|
||||
self.fragment,
|
||||
self.base)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2455,11 +2485,14 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
|
|||
MaybeAuto::Specified(fragment.content_inline_size())
|
||||
}
|
||||
|
||||
fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &LayoutContext) -> Au {
|
||||
fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &LayoutContext)
|
||||
-> Au {
|
||||
block.containing_block_size(ctx.shared.screen_size).inline
|
||||
}
|
||||
|
||||
fn set_flow_x_coord_if_necessary(&self, block: &mut BlockFlow, solution: ISizeConstraintSolution) {
|
||||
fn set_flow_x_coord_if_necessary(&self,
|
||||
block: &mut BlockFlow,
|
||||
solution: ISizeConstraintSolution) {
|
||||
// Set the x-coordinate of the absolute flow wrt to its containing block.
|
||||
block.base.position.start.i = solution.inline_start;
|
||||
}
|
||||
|
|
|
@ -52,9 +52,9 @@ use servo_util::opts;
|
|||
use std::collections::DList;
|
||||
use std::mem;
|
||||
use std::sync::atomic::Relaxed;
|
||||
use style::ComputedValues;
|
||||
use style::computed_values::{caption_side, display, empty_cells, float, list_style_position};
|
||||
use style::computed_values::{position};
|
||||
use style::{mod, ComputedValues};
|
||||
use sync::Arc;
|
||||
use url::Url;
|
||||
|
||||
|
@ -681,7 +681,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
/// doesn't render its children, so this just nukes a child's fragments and creates a
|
||||
/// `Fragment`.
|
||||
fn build_fragments_for_replaced_inline_content(&mut self, node: &ThreadSafeLayoutNode)
|
||||
-> ConstructionResult {
|
||||
-> ConstructionResult {
|
||||
for kid in node.children() {
|
||||
kid.set_flow_construction_result(ConstructionResult::None)
|
||||
}
|
||||
|
@ -697,24 +697,42 @@ impl<'a> FlowConstructor<'a> {
|
|||
node.restyle_damage()))
|
||||
}
|
||||
|
||||
// If the value of `display` property is not `inline`, then we have a situation like
|
||||
// `<div style="position:absolute">foo bar baz</div>`. The fragments for `foo`, `bar`, and
|
||||
// `baz` had better not be absolutely positioned!
|
||||
let mut style = (*node.style()).clone();
|
||||
if style.get_box().display != display::inline {
|
||||
style = Arc::new(style::make_inline(&*style))
|
||||
}
|
||||
|
||||
// If this is generated content, then we need to initialize the accumulator with the
|
||||
// fragment corresponding to that content. Otherwise, just initialize with the ordinary
|
||||
// fragment that needs to be generated for this inline node.
|
||||
let fragment = if node.get_pseudo_element_type() != PseudoElementType::Normal {
|
||||
let fragment_info = SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node));
|
||||
Fragment::new_from_specific_info(node, fragment_info)
|
||||
let fragment_info =
|
||||
SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node));
|
||||
Fragment::from_opaque_node_and_style(
|
||||
OpaqueNodeMethods::from_thread_safe_layout_node(node),
|
||||
style,
|
||||
node.restyle_damage(),
|
||||
fragment_info)
|
||||
} else {
|
||||
Fragment::new(self, node)
|
||||
Fragment::from_opaque_node_and_style(
|
||||
OpaqueNodeMethods::from_thread_safe_layout_node(node),
|
||||
style,
|
||||
node.restyle_damage(),
|
||||
self.build_specific_fragment_info_for_node(node))
|
||||
};
|
||||
|
||||
let mut fragments = DList::new();
|
||||
fragments.push_back(fragment);
|
||||
|
||||
let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||
splits: DList::new(),
|
||||
fragments: fragments,
|
||||
abs_descendants: Descendants::new(),
|
||||
});
|
||||
let construction_item =
|
||||
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||
splits: DList::new(),
|
||||
fragments: fragments,
|
||||
abs_descendants: Descendants::new(),
|
||||
});
|
||||
ConstructionResult::ConstructionItem(construction_item)
|
||||
}
|
||||
|
||||
|
@ -726,17 +744,19 @@ impl<'a> FlowConstructor<'a> {
|
|||
_ => unreachable!()
|
||||
};
|
||||
|
||||
let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new(block_flow));
|
||||
let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new(
|
||||
block_flow));
|
||||
let fragment = Fragment::new_from_specific_info(node, fragment_info);
|
||||
|
||||
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
||||
fragment_accumulator.fragments.push_back(fragment);
|
||||
|
||||
let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||
splits: DList::new(),
|
||||
fragments: fragment_accumulator.to_dlist(),
|
||||
abs_descendants: abs_descendants,
|
||||
});
|
||||
let construction_item =
|
||||
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||
splits: DList::new(),
|
||||
fragments: fragment_accumulator.to_dlist(),
|
||||
abs_descendants: abs_descendants,
|
||||
});
|
||||
ConstructionResult::ConstructionItem(construction_item)
|
||||
}
|
||||
|
||||
|
@ -757,11 +777,12 @@ impl<'a> FlowConstructor<'a> {
|
|||
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
||||
fragment_accumulator.fragments.push_back(fragment);
|
||||
|
||||
let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||
splits: DList::new(),
|
||||
fragments: fragment_accumulator.to_dlist(),
|
||||
abs_descendants: abs_descendants,
|
||||
});
|
||||
let construction_item =
|
||||
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||
splits: DList::new(),
|
||||
fragments: fragment_accumulator.to_dlist(),
|
||||
abs_descendants: abs_descendants,
|
||||
});
|
||||
ConstructionResult::ConstructionItem(construction_item)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,9 @@
|
|||
use block::BlockFlow;
|
||||
use context::LayoutContext;
|
||||
use flow::{mod, Flow, IS_ABSOLUTELY_POSITIONED, NEEDS_LAYER};
|
||||
use fragment::{Fragment, SpecificFragmentInfo, IframeFragmentInfo, ImageFragmentInfo};
|
||||
use fragment::ScannedTextFragmentInfo;
|
||||
use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo};
|
||||
use fragment::{ScannedTextFragmentInfo, SpecificFragmentInfo};
|
||||
use inline::InlineFlow;
|
||||
use list_item::ListItemFlow;
|
||||
use model;
|
||||
use util::{OpaqueNodeMethods, ToGfxColor};
|
||||
|
@ -36,8 +37,8 @@ use servo_msg::constellation_msg::Msg as ConstellationMsg;
|
|||
use servo_msg::constellation_msg::ConstellationChan;
|
||||
use servo_net::image::holder::ImageHolder;
|
||||
use servo_util::cursor::{DefaultCursor, TextCursor, VerticalTextCursor};
|
||||
use servo_util::geometry::{mod, Au, ZERO_POINT};
|
||||
use servo_util::logical_geometry::{LogicalRect, WritingMode};
|
||||
use servo_util::geometry::{mod, Au};
|
||||
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
|
||||
use servo_util::opts;
|
||||
use std::default::Default;
|
||||
use std::num::FloatMath;
|
||||
|
@ -133,16 +134,19 @@ pub trait FragmentDisplayListBuilding {
|
|||
absolute_bounds: &Rect<Au>,
|
||||
clip: &ClippingRegion);
|
||||
|
||||
/// Adds display items necessary to draw debug boxes around a scanned text fragment.
|
||||
fn build_debug_borders_around_text_fragments(&self,
|
||||
style: &ComputedValues,
|
||||
display_list: &mut DisplayList,
|
||||
flow_origin: Point2D<Au>,
|
||||
stacking_relative_border_box: &Rect<Au>,
|
||||
stacking_relative_content_box: &Rect<Au>,
|
||||
text_fragment: &ScannedTextFragmentInfo,
|
||||
clip: &ClippingRegion);
|
||||
|
||||
/// Adds display items necessary to draw debug boxes around this fragment.
|
||||
fn build_debug_borders_around_fragment(&self,
|
||||
display_list: &mut DisplayList,
|
||||
flow_origin: Point2D<Au>,
|
||||
stacking_relative_border_box: &Rect<Au>,
|
||||
clip: &ClippingRegion);
|
||||
|
||||
/// Adds the display items for this fragment to the given display list.
|
||||
|
@ -152,12 +156,16 @@ pub trait FragmentDisplayListBuilding {
|
|||
/// * `display_list`: The display list to add display items to.
|
||||
/// * `layout_context`: The layout context.
|
||||
/// * `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.
|
||||
/// * `stacking_relative_flow_origin`: Position of the origin of the owning flow with respect
|
||||
/// to its nearest ancestor stacking context.
|
||||
/// * `relative_containing_block_size`: The size of the containing block that
|
||||
/// `position: relative` makes use of.
|
||||
/// * `clip`: The region to clip the display items to.
|
||||
fn build_display_list(&mut self,
|
||||
display_list: &mut DisplayList,
|
||||
layout_context: &LayoutContext,
|
||||
flow_origin: Point2D<Au>,
|
||||
stacking_relative_flow_origin: &Point2D<Au>,
|
||||
relative_containing_block_size: &LogicalSize<Au>,
|
||||
background_and_border_level: BackgroundAndBorderLevel,
|
||||
clip: &ClippingRegion);
|
||||
|
||||
|
@ -168,12 +176,17 @@ pub trait FragmentDisplayListBuilding {
|
|||
offset: Point2D<Au>,
|
||||
layout_context: &LayoutContext);
|
||||
|
||||
fn clipping_region_for_children(&self, current_clip: &ClippingRegion, flow_origin: &Point2D<Au>)
|
||||
/// Returns the appropriate clipping region for descendants of this flow.
|
||||
fn clipping_region_for_children(&self,
|
||||
current_clip: &ClippingRegion,
|
||||
stacking_relative_border_box: &Rect<Au>)
|
||||
-> ClippingRegion;
|
||||
|
||||
/// Calculates the clipping rectangle for a fragment, taking the `clip` property into account
|
||||
/// per CSS 2.1 § 11.1.2.
|
||||
fn calculate_style_specified_clip(&self, parent_clip: &ClippingRegion, origin: &Point2D<Au>)
|
||||
fn calculate_style_specified_clip(&self,
|
||||
parent_clip: &ClippingRegion,
|
||||
stacking_relative_border_box: &Rect<Au>)
|
||||
-> ClippingRegion;
|
||||
|
||||
/// Creates the text display item for one text fragment.
|
||||
|
@ -181,23 +194,20 @@ pub trait FragmentDisplayListBuilding {
|
|||
display_list: &mut DisplayList,
|
||||
text_fragment: &ScannedTextFragmentInfo,
|
||||
text_color: RGBA,
|
||||
offset: &Point2D<Au>,
|
||||
flow_origin: &Point2D<Au>,
|
||||
stacking_relative_content_box: &Rect<Au>,
|
||||
clip: &ClippingRegion);
|
||||
|
||||
/// Creates the display item for a text decoration: underline, overline, or line-through.
|
||||
fn build_display_list_for_text_decoration(&self,
|
||||
display_list: &mut DisplayList,
|
||||
color: RGBA,
|
||||
flow_origin: &Point2D<Au>,
|
||||
clip: &ClippingRegion,
|
||||
logical_bounds: &LogicalRect<Au>,
|
||||
offset: &Point2D<Au>);
|
||||
color: &RGBA,
|
||||
stacking_relative_box: &LogicalRect<Au>,
|
||||
clip: &ClippingRegion);
|
||||
|
||||
/// A helper method that `build_display_list` calls to create per-fragment-type display items.
|
||||
fn build_fragment_type_specific_display_items(&mut self,
|
||||
display_list: &mut DisplayList,
|
||||
flow_origin: Point2D<Au>,
|
||||
stacking_relative_border_box: &Rect<Au>,
|
||||
clip: &ClippingRegion);
|
||||
}
|
||||
|
||||
|
@ -580,20 +590,16 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
fn build_debug_borders_around_text_fragments(&self,
|
||||
style: &ComputedValues,
|
||||
display_list: &mut DisplayList,
|
||||
flow_origin: Point2D<Au>,
|
||||
stacking_relative_border_box: &Rect<Au>,
|
||||
stacking_relative_content_box: &Rect<Au>,
|
||||
text_fragment: &ScannedTextFragmentInfo,
|
||||
clip: &ClippingRegion) {
|
||||
// FIXME(#2795): Get the real container size
|
||||
// FIXME(pcwalton, #2795): Get the real container size.
|
||||
let container_size = Size2D::zero();
|
||||
// Fragment position wrt to the owning flow.
|
||||
let fragment_bounds = self.border_box.to_physical(self.style.writing_mode, container_size);
|
||||
let absolute_fragment_bounds = Rect(
|
||||
fragment_bounds.origin + flow_origin,
|
||||
fragment_bounds.size);
|
||||
|
||||
// Compute the text fragment bounds and draw a border surrounding them.
|
||||
display_list.content.push_back(DisplayItem::BorderClass(box BorderDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_fragment_bounds,
|
||||
base: BaseDisplayItem::new(*stacking_relative_border_box,
|
||||
DisplayItemMetadata::new(self.node, style, DefaultCursor),
|
||||
(*clip).clone()),
|
||||
border_widths: SideOffsets2D::new_all_same(Au::from_px(1)),
|
||||
|
@ -603,12 +609,12 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}));
|
||||
|
||||
// Draw a rectangle representing the baselines.
|
||||
let ascent = text_fragment.run.ascent();
|
||||
let mut baseline = self.border_box.clone();
|
||||
baseline.start.b = baseline.start.b + ascent;
|
||||
let mut baseline = LogicalRect::from_physical(self.style.writing_mode,
|
||||
*stacking_relative_content_box,
|
||||
container_size);
|
||||
baseline.start.b = baseline.start.b + text_fragment.run.ascent();
|
||||
baseline.size.block = Au(0);
|
||||
let mut baseline = baseline.to_physical(self.style.writing_mode, container_size);
|
||||
baseline.origin = baseline.origin + flow_origin;
|
||||
let baseline = baseline.to_physical(self.style.writing_mode, container_size);
|
||||
|
||||
let line_display_item = box LineDisplayItem {
|
||||
base: BaseDisplayItem::new(baseline,
|
||||
|
@ -622,19 +628,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
|
||||
fn build_debug_borders_around_fragment(&self,
|
||||
display_list: &mut DisplayList,
|
||||
flow_origin: Point2D<Au>,
|
||||
stacking_relative_border_box: &Rect<Au>,
|
||||
clip: &ClippingRegion) {
|
||||
// FIXME(#2795): Get the real container size
|
||||
let container_size = Size2D::zero();
|
||||
// Fragment position wrt to the owning flow.
|
||||
let fragment_bounds = self.border_box.to_physical(self.style.writing_mode, container_size);
|
||||
let absolute_fragment_bounds = Rect(
|
||||
fragment_bounds.origin + flow_origin,
|
||||
fragment_bounds.size);
|
||||
|
||||
// This prints a debug border around the border of this fragment.
|
||||
display_list.content.push_back(DisplayItem::BorderClass(box BorderDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_fragment_bounds,
|
||||
base: BaseDisplayItem::new(*stacking_relative_border_box,
|
||||
DisplayItemMetadata::new(self.node,
|
||||
&*self.style,
|
||||
DefaultCursor),
|
||||
|
@ -646,7 +644,9 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}));
|
||||
}
|
||||
|
||||
fn calculate_style_specified_clip(&self, parent_clip: &ClippingRegion, origin: &Point2D<Au>)
|
||||
fn calculate_style_specified_clip(&self,
|
||||
parent_clip: &ClippingRegion,
|
||||
stacking_relative_border_box: &Rect<Au>)
|
||||
-> ClippingRegion {
|
||||
// Account for `clip` per CSS 2.1 § 11.1.2.
|
||||
let style_clip_rect = match (self.style().get_box().position,
|
||||
|
@ -656,54 +656,49 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
};
|
||||
|
||||
// FIXME(pcwalton, #2795): Get the real container size.
|
||||
let border_box = self.border_box.to_physical(self.style.writing_mode, Size2D::zero());
|
||||
let clip_origin = Point2D(border_box.origin.x + style_clip_rect.left,
|
||||
border_box.origin.y + style_clip_rect.top);
|
||||
let new_clip_rect =
|
||||
Rect(clip_origin + *origin,
|
||||
Size2D(style_clip_rect.right.unwrap_or(border_box.size.width) - clip_origin.x,
|
||||
style_clip_rect.bottom.unwrap_or(border_box.size.height) - clip_origin.y));
|
||||
(*parent_clip).clone().intersect_rect(&new_clip_rect)
|
||||
let clip_origin = Point2D(stacking_relative_border_box.origin.x + style_clip_rect.left,
|
||||
stacking_relative_border_box.origin.y + style_clip_rect.top);
|
||||
let right = style_clip_rect.right.unwrap_or(stacking_relative_border_box.size.width);
|
||||
let bottom = style_clip_rect.bottom.unwrap_or(stacking_relative_border_box.size.height);
|
||||
let clip_size = Size2D(right - clip_origin.x, bottom - clip_origin.y);
|
||||
(*parent_clip).clone().intersect_rect(&Rect(clip_origin, clip_size))
|
||||
}
|
||||
|
||||
fn build_display_list(&mut self,
|
||||
display_list: &mut DisplayList,
|
||||
layout_context: &LayoutContext,
|
||||
flow_origin: Point2D<Au>,
|
||||
stacking_relative_flow_origin: &Point2D<Au>,
|
||||
relative_containing_block_size: &LogicalSize<Au>,
|
||||
background_and_border_level: BackgroundAndBorderLevel,
|
||||
clip: &ClippingRegion) {
|
||||
// Compute the fragment position relative to the parent stacking context. If the fragment
|
||||
// itself establishes a stacking context, then the origin of its position will be (0, 0)
|
||||
// for the purposes of this computation.
|
||||
let stacking_relative_flow_origin = if self.establishes_stacking_context() {
|
||||
ZERO_POINT
|
||||
} else {
|
||||
flow_origin
|
||||
};
|
||||
let absolute_fragment_bounds =
|
||||
self.stacking_relative_bounds(&stacking_relative_flow_origin);
|
||||
let stacking_relative_border_box =
|
||||
self.stacking_relative_border_box(stacking_relative_flow_origin,
|
||||
relative_containing_block_size,
|
||||
CoordinateSystem::Self);
|
||||
|
||||
debug!("Fragment::build_display_list at rel={}, abs={}: {}",
|
||||
debug!("Fragment::build_display_list at rel={}, abs={}, dirty={}, flow origin={}: {}",
|
||||
self.border_box,
|
||||
absolute_fragment_bounds,
|
||||
self);
|
||||
debug!("Fragment::build_display_list: dirty={}, flow_origin={}",
|
||||
stacking_relative_border_box,
|
||||
layout_context.shared.dirty,
|
||||
flow_origin);
|
||||
stacking_relative_flow_origin,
|
||||
self);
|
||||
|
||||
if self.style().get_inheritedbox().visibility != visibility::visible {
|
||||
return
|
||||
}
|
||||
|
||||
if !absolute_fragment_bounds.intersects(&layout_context.shared.dirty) {
|
||||
if !stacking_relative_border_box.intersects(&layout_context.shared.dirty) {
|
||||
debug!("Fragment::build_display_list: Did not intersect...");
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate the clip rect. If there's nothing to render at all, don't even construct
|
||||
// display list items.
|
||||
let clip = self.calculate_style_specified_clip(clip, &absolute_fragment_bounds.origin);
|
||||
if !clip.might_intersect_rect(&absolute_fragment_bounds) {
|
||||
let clip = self.calculate_style_specified_clip(clip, &stacking_relative_border_box);
|
||||
if !clip.might_intersect_rect(&stacking_relative_border_box) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -713,15 +708,34 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
let level =
|
||||
StackingLevel::from_background_and_border_level(background_and_border_level);
|
||||
|
||||
// Add a shadow to the list, if applicable.
|
||||
// Add shadows, background, borders, and outlines, if applicable.
|
||||
if let Some(ref inline_context) = self.inline_context {
|
||||
for style in inline_context.styles.iter().rev() {
|
||||
self.build_display_list_for_box_shadow_if_applicable(&**style,
|
||||
display_list,
|
||||
layout_context,
|
||||
level,
|
||||
&absolute_fragment_bounds,
|
||||
&clip);
|
||||
self.build_display_list_for_box_shadow_if_applicable(
|
||||
&**style,
|
||||
display_list,
|
||||
layout_context,
|
||||
level,
|
||||
&stacking_relative_border_box,
|
||||
&clip);
|
||||
self.build_display_list_for_background_if_applicable(
|
||||
&**style,
|
||||
display_list,
|
||||
layout_context,
|
||||
level,
|
||||
&stacking_relative_border_box,
|
||||
&clip);
|
||||
self.build_display_list_for_borders_if_applicable(
|
||||
&**style,
|
||||
display_list,
|
||||
&stacking_relative_border_box,
|
||||
level,
|
||||
&clip);
|
||||
self.build_display_list_for_outline_if_applicable(
|
||||
&**style,
|
||||
display_list,
|
||||
&stacking_relative_border_box,
|
||||
&clip);
|
||||
}
|
||||
}
|
||||
if !self.is_scanned_text_fragment() {
|
||||
|
@ -729,62 +743,35 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
display_list,
|
||||
layout_context,
|
||||
level,
|
||||
&absolute_fragment_bounds,
|
||||
&stacking_relative_border_box,
|
||||
&clip);
|
||||
}
|
||||
|
||||
// Add the background to the list, if applicable.
|
||||
if let Some(ref inline_context) = self.inline_context {
|
||||
for style in inline_context.styles.iter().rev() {
|
||||
self.build_display_list_for_background_if_applicable(&**style,
|
||||
display_list,
|
||||
layout_context,
|
||||
level,
|
||||
&absolute_fragment_bounds,
|
||||
&clip);
|
||||
}
|
||||
}
|
||||
if !self.is_scanned_text_fragment() {
|
||||
self.build_display_list_for_background_if_applicable(&*self.style,
|
||||
display_list,
|
||||
layout_context,
|
||||
level,
|
||||
&absolute_fragment_bounds,
|
||||
&stacking_relative_border_box,
|
||||
&clip);
|
||||
}
|
||||
|
||||
// Add a border and outlines, if applicable.
|
||||
if let Some(ref inline_context) = self.inline_context {
|
||||
for style in inline_context.styles.iter().rev() {
|
||||
self.build_display_list_for_borders_if_applicable(&**style,
|
||||
display_list,
|
||||
&absolute_fragment_bounds,
|
||||
level,
|
||||
&clip);
|
||||
self.build_display_list_for_outline_if_applicable(&**style,
|
||||
display_list,
|
||||
&absolute_fragment_bounds,
|
||||
&clip);
|
||||
}
|
||||
}
|
||||
if !self.is_scanned_text_fragment() {
|
||||
self.build_display_list_for_borders_if_applicable(&*self.style,
|
||||
display_list,
|
||||
&absolute_fragment_bounds,
|
||||
&stacking_relative_border_box,
|
||||
level,
|
||||
&clip);
|
||||
self.build_display_list_for_outline_if_applicable(&*self.style,
|
||||
display_list,
|
||||
&absolute_fragment_bounds,
|
||||
&stacking_relative_border_box,
|
||||
&clip);
|
||||
}
|
||||
}
|
||||
|
||||
// Create special per-fragment-type display items.
|
||||
self.build_fragment_type_specific_display_items(display_list, flow_origin, &clip);
|
||||
self.build_fragment_type_specific_display_items(display_list,
|
||||
&stacking_relative_border_box,
|
||||
&clip);
|
||||
|
||||
if opts::get().show_debug_fragment_borders {
|
||||
self.build_debug_borders_around_fragment(display_list, flow_origin, &clip)
|
||||
self.build_debug_borders_around_fragment(display_list,
|
||||
&stacking_relative_border_box,
|
||||
&clip)
|
||||
}
|
||||
|
||||
// If this is an iframe, then send its position and size up to the constellation.
|
||||
|
@ -799,31 +786,18 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
// the iframe is actually going to be displayed.
|
||||
if let SpecificFragmentInfo::Iframe(ref iframe_fragment) = self.specific {
|
||||
self.finalize_position_and_size_of_iframe(&**iframe_fragment,
|
||||
absolute_fragment_bounds.origin,
|
||||
stacking_relative_border_box.origin,
|
||||
layout_context)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_fragment_type_specific_display_items(&mut self,
|
||||
display_list: &mut DisplayList,
|
||||
flow_origin: Point2D<Au>,
|
||||
stacking_relative_border_box: &Rect<Au>,
|
||||
clip: &ClippingRegion) {
|
||||
// Compute the fragment position relative to the parent stacking context. If the fragment
|
||||
// itself establishes a stacking context, then the origin of its position will be (0, 0)
|
||||
// for the purposes of this computation.
|
||||
let stacking_relative_flow_origin = if self.establishes_stacking_context() {
|
||||
ZERO_POINT
|
||||
} else {
|
||||
flow_origin
|
||||
};
|
||||
|
||||
// FIXME(#2795): Get the real container size.
|
||||
let content_box = self.content_box();
|
||||
let container_size = Size2D::zero();
|
||||
let rect_to_absolute = |writing_mode: WritingMode, logical_rect: LogicalRect<Au>| {
|
||||
let physical_rect = logical_rect.to_physical(writing_mode, container_size);
|
||||
Rect(physical_rect.origin + stacking_relative_flow_origin, physical_rect.size)
|
||||
};
|
||||
// Compute the context box position relative to the parent stacking context.
|
||||
let stacking_relative_content_box =
|
||||
self.stacking_relative_content_box(stacking_relative_border_box);
|
||||
|
||||
match self.specific {
|
||||
SpecificFragmentInfo::UnscannedText(_) => {
|
||||
|
@ -838,16 +812,16 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
self.build_display_list_for_text_fragment(display_list,
|
||||
&**text_fragment,
|
||||
text_color,
|
||||
&flow_origin,
|
||||
&Point2D(Au(0), Au(0)),
|
||||
&stacking_relative_content_box,
|
||||
clip);
|
||||
|
||||
if opts::get().show_debug_fragment_borders {
|
||||
self.build_debug_borders_around_text_fragments(self.style(),
|
||||
display_list,
|
||||
flow_origin,
|
||||
stacking_relative_border_box,
|
||||
&stacking_relative_content_box,
|
||||
&**text_fragment,
|
||||
clip);
|
||||
clip)
|
||||
}
|
||||
}
|
||||
SpecificFragmentInfo::Generic |
|
||||
|
@ -859,25 +833,25 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
SpecificFragmentInfo::InlineBlock(_) |
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {
|
||||
if opts::get().show_debug_fragment_borders {
|
||||
self.build_debug_borders_around_fragment(display_list, flow_origin, clip);
|
||||
self.build_debug_borders_around_fragment(display_list,
|
||||
stacking_relative_border_box,
|
||||
clip);
|
||||
}
|
||||
}
|
||||
SpecificFragmentInfo::Image(ref mut image_fragment) => {
|
||||
let image_ref = &mut image_fragment.image;
|
||||
if let Some(image) = image_ref.get_image(self.node.to_untrusted_node_address()) {
|
||||
debug!("(building display list) building image fragment");
|
||||
let absolute_content_box = rect_to_absolute(self.style.writing_mode,
|
||||
content_box);
|
||||
|
||||
// Place the image into the display list.
|
||||
display_list.content.push_back(DisplayItem::ImageClass(box ImageDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_content_box,
|
||||
base: BaseDisplayItem::new(stacking_relative_content_box,
|
||||
DisplayItemMetadata::new(self.node,
|
||||
&*self.style,
|
||||
DefaultCursor),
|
||||
(*clip).clone()),
|
||||
image: image.clone(),
|
||||
stretch_size: absolute_content_box.size,
|
||||
stretch_size: stacking_relative_content_box.size,
|
||||
}));
|
||||
} else {
|
||||
// No image data at all? Do nothing.
|
||||
|
@ -910,7 +884,9 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
iframe_rect));
|
||||
}
|
||||
|
||||
fn clipping_region_for_children(&self, current_clip: &ClippingRegion, flow_origin: &Point2D<Au>)
|
||||
fn clipping_region_for_children(&self,
|
||||
current_clip: &ClippingRegion,
|
||||
stacking_relative_border_box: &Rect<Au>)
|
||||
-> ClippingRegion {
|
||||
// Don't clip if we're text.
|
||||
if self.is_scanned_text_fragment() {
|
||||
|
@ -918,27 +894,24 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
|
||||
// Account for style-specified `clip`.
|
||||
let current_clip = self.calculate_style_specified_clip(current_clip, flow_origin);
|
||||
let current_clip = self.calculate_style_specified_clip(current_clip,
|
||||
stacking_relative_border_box);
|
||||
|
||||
// Only clip if `overflow` tells us to.
|
||||
match self.style.get_box().overflow {
|
||||
overflow::hidden | overflow::auto | overflow::scroll => {}
|
||||
_ => return current_clip,
|
||||
overflow::hidden | overflow::auto | overflow::scroll => {
|
||||
// Create a new clip rect.
|
||||
current_clip.intersect_rect(stacking_relative_border_box)
|
||||
}
|
||||
_ => current_clip,
|
||||
}
|
||||
|
||||
// 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.intersect_rect(&Rect(physical_rect.origin + *flow_origin, physical_rect.size))
|
||||
}
|
||||
|
||||
fn build_display_list_for_text_fragment(&self,
|
||||
display_list: &mut DisplayList,
|
||||
text_fragment: &ScannedTextFragmentInfo,
|
||||
text_color: RGBA,
|
||||
flow_origin: &Point2D<Au>,
|
||||
offset: &Point2D<Au>,
|
||||
stacking_relative_content_box: &Rect<Au>,
|
||||
clip: &ClippingRegion) {
|
||||
// Determine the orientation and cursor to use.
|
||||
let (orientation, cursor) = if self.style.writing_mode.is_vertical() {
|
||||
|
@ -955,29 +928,16 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
//
|
||||
// FIXME(pcwalton): Get the real container size.
|
||||
let container_size = Size2D::zero();
|
||||
let content_box = self.content_box();
|
||||
let metrics = &text_fragment.run.font_metrics;
|
||||
let baseline_origin = {
|
||||
let mut content_box_start = content_box.start;
|
||||
content_box_start.b = content_box_start.b + metrics.ascent;
|
||||
content_box_start.to_physical(self.style.writing_mode, container_size) + *flow_origin +
|
||||
*offset
|
||||
};
|
||||
let stacking_relative_flow_origin = if self.establishes_stacking_context() {
|
||||
ZERO_POINT
|
||||
} else {
|
||||
*flow_origin
|
||||
};
|
||||
let rect_to_absolute = |writing_mode: WritingMode, logical_rect: LogicalRect<Au>| {
|
||||
let physical_rect = logical_rect.to_physical(writing_mode, container_size);
|
||||
Rect(physical_rect.origin + stacking_relative_flow_origin, physical_rect.size)
|
||||
};
|
||||
let content_rect = rect_to_absolute(self.style.writing_mode,
|
||||
content_box).translate(offset);
|
||||
let baseline_origin = stacking_relative_content_box.origin +
|
||||
LogicalPoint::new(self.style.writing_mode,
|
||||
Au(0),
|
||||
metrics.ascent).to_physical(self.style.writing_mode,
|
||||
container_size);
|
||||
|
||||
// Create the text display item.
|
||||
display_list.content.push_back(DisplayItem::TextClass(box TextDisplayItem {
|
||||
base: BaseDisplayItem::new(content_rect,
|
||||
base: BaseDisplayItem::new(*stacking_relative_content_box,
|
||||
DisplayItemMetadata::new(self.node, self.style(), cursor),
|
||||
(*clip).clone()),
|
||||
text_run: text_fragment.run.clone(),
|
||||
|
@ -989,63 +949,55 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
|
||||
// Create display items for text decorations.
|
||||
let text_decorations = self.style().get_inheritedtext()._servo_text_decorations_in_effect;
|
||||
if let Some(underline_color) = text_decorations.underline {
|
||||
let mut rect = content_box.clone();
|
||||
rect.start.b = rect.start.b + metrics.ascent - metrics.underline_offset;
|
||||
rect.size.block = metrics.underline_size;
|
||||
let stacking_relative_content_box =
|
||||
LogicalRect::from_physical(self.style.writing_mode,
|
||||
*stacking_relative_content_box,
|
||||
container_size);
|
||||
if let Some(ref underline_color) = text_decorations.underline {
|
||||
let mut stacking_relative_box = stacking_relative_content_box;
|
||||
stacking_relative_box.start.b = stacking_relative_content_box.start.b +
|
||||
metrics.ascent - metrics.underline_offset;
|
||||
stacking_relative_box.size.block = metrics.underline_size;
|
||||
self.build_display_list_for_text_decoration(display_list,
|
||||
underline_color,
|
||||
flow_origin,
|
||||
clip,
|
||||
&rect,
|
||||
offset)
|
||||
&stacking_relative_box,
|
||||
clip)
|
||||
}
|
||||
|
||||
if let Some(overline_color) = text_decorations.overline {
|
||||
let mut rect = content_box.clone();
|
||||
rect.size.block = metrics.underline_size;
|
||||
if let Some(ref overline_color) = text_decorations.overline {
|
||||
let mut stacking_relative_box = stacking_relative_content_box;
|
||||
stacking_relative_box.size.block = metrics.underline_size;
|
||||
self.build_display_list_for_text_decoration(display_list,
|
||||
overline_color,
|
||||
flow_origin,
|
||||
clip,
|
||||
&rect,
|
||||
offset)
|
||||
&stacking_relative_box,
|
||||
clip)
|
||||
}
|
||||
|
||||
if let Some(line_through_color) = text_decorations.line_through {
|
||||
let mut rect = content_box.clone();
|
||||
rect.start.b = rect.start.b + metrics.ascent - metrics.strikeout_offset;
|
||||
rect.size.block = metrics.strikeout_size;
|
||||
if let Some(ref line_through_color) = text_decorations.line_through {
|
||||
let mut stacking_relative_box = stacking_relative_content_box;
|
||||
stacking_relative_box.start.b = stacking_relative_box.start.b + metrics.ascent -
|
||||
metrics.strikeout_offset;
|
||||
stacking_relative_box.size.block = metrics.strikeout_size;
|
||||
self.build_display_list_for_text_decoration(display_list,
|
||||
line_through_color,
|
||||
flow_origin,
|
||||
clip,
|
||||
&rect,
|
||||
offset)
|
||||
&stacking_relative_box,
|
||||
clip)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_display_list_for_text_decoration(&self,
|
||||
display_list: &mut DisplayList,
|
||||
color: RGBA,
|
||||
flow_origin: &Point2D<Au>,
|
||||
clip: &ClippingRegion,
|
||||
logical_bounds: &LogicalRect<Au>,
|
||||
offset: &Point2D<Au>) {
|
||||
// FIXME(pcwalton): Get the real container size.
|
||||
color: &RGBA,
|
||||
stacking_relative_box: &LogicalRect<Au>,
|
||||
clip: &ClippingRegion) {
|
||||
// FIXME(pcwalton, #2795): Get the real container size.
|
||||
let container_size = Size2D::zero();
|
||||
let stacking_relative_flow_origin = if self.establishes_stacking_context() {
|
||||
ZERO_POINT
|
||||
} else {
|
||||
*flow_origin
|
||||
};
|
||||
let physical_rect = logical_bounds.to_physical(self.style.writing_mode, container_size);
|
||||
let stacking_relative_box = stacking_relative_box.to_physical(self.style.writing_mode,
|
||||
container_size);
|
||||
|
||||
let bounds = Rect(physical_rect.origin + stacking_relative_flow_origin,
|
||||
physical_rect.size).translate(offset);
|
||||
let metadata = DisplayItemMetadata::new(self.node, &*self.style, DefaultCursor);
|
||||
display_list.content.push_back(DisplayItem::SolidColorClass(box SolidColorDisplayItem {
|
||||
base: BaseDisplayItem::new(bounds, metadata, (*clip).clone()),
|
||||
base: BaseDisplayItem::new(stacking_relative_box, metadata, (*clip).clone()),
|
||||
color: color.to_gfx_color(),
|
||||
}))
|
||||
}
|
||||
|
@ -1081,14 +1033,16 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
layout_context: &LayoutContext,
|
||||
background_border_level: BackgroundAndBorderLevel) {
|
||||
// Add the box that starts the block context.
|
||||
let stacking_relative_fragment_origin =
|
||||
self.base.stacking_relative_position_of_child_fragment(&self.fragment);
|
||||
self.fragment.build_display_list(display_list,
|
||||
layout_context,
|
||||
stacking_relative_fragment_origin,
|
||||
&self.base.stacking_relative_position,
|
||||
&self.base
|
||||
.absolute_position_info
|
||||
.relative_containing_block_size,
|
||||
background_border_level,
|
||||
&self.base.clip);
|
||||
|
||||
// Add children.
|
||||
for kid in self.base.children.iter_mut() {
|
||||
flow::mut_base(kid).display_list_building_result.add_to(display_list);
|
||||
}
|
||||
|
@ -1103,7 +1057,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
background_border_level);
|
||||
|
||||
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
|
||||
DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, None))
|
||||
DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list,
|
||||
None))
|
||||
} else {
|
||||
DisplayListBuildingResult::Normal(display_list)
|
||||
}
|
||||
|
@ -1120,7 +1075,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
!self.base.flags.contains(NEEDS_LAYER) {
|
||||
// We didn't need a layer.
|
||||
self.base.display_list_building_result =
|
||||
DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, None));
|
||||
DisplayListBuildingResult::StackingContext(self.create_stacking_context(
|
||||
display_list,
|
||||
None));
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1137,7 +1094,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
Some(Arc::new(PaintLayer::new(self.layer_id(0),
|
||||
transparent,
|
||||
scroll_policy))));
|
||||
self.base.display_list_building_result = DisplayListBuildingResult::StackingContext(stacking_context)
|
||||
self.base.display_list_building_result =
|
||||
DisplayListBuildingResult::StackingContext(stacking_context)
|
||||
}
|
||||
|
||||
fn build_display_list_for_floating_block(&mut self,
|
||||
|
@ -1149,7 +1107,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
display_list.form_float_pseudo_stacking_context();
|
||||
|
||||
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
|
||||
DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, None))
|
||||
DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list,
|
||||
None))
|
||||
} else {
|
||||
DisplayListBuildingResult::Normal(display_list)
|
||||
}
|
||||
|
@ -1165,7 +1124,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
} else if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
|
||||
self.build_display_list_for_absolutely_positioned_block(display_list, layout_context)
|
||||
} else {
|
||||
self.build_display_list_for_static_block(display_list, layout_context, BackgroundAndBorderLevel::Block)
|
||||
self.build_display_list_for_static_block(display_list,
|
||||
layout_context,
|
||||
BackgroundAndBorderLevel::Block)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1173,11 +1134,67 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
display_list: Box<DisplayList>,
|
||||
layer: Option<Arc<PaintLayer>>)
|
||||
-> Arc<StackingContext> {
|
||||
let bounds = Rect(self.base.stacking_relative_position,
|
||||
self.base.overflow.size.to_physical(self.base.writing_mode));
|
||||
let z_index = self.fragment.style().get_box().z_index.number_or_zero();
|
||||
let opacity = self.fragment.style().get_effects().opacity as f32;
|
||||
Arc::new(StackingContext::new(display_list, bounds, z_index, opacity, layer))
|
||||
debug_assert!(self.fragment.establishes_stacking_context());
|
||||
let border_box = self.fragment
|
||||
.stacking_relative_border_box(&self.base.stacking_relative_position,
|
||||
&self.base
|
||||
.absolute_position_info
|
||||
.relative_containing_block_size,
|
||||
CoordinateSystem::Parent);
|
||||
|
||||
// FIXME(pcwalton): Is this vertical-writing-direction-safe?
|
||||
let margin = self.fragment.margin.to_physical(self.base.writing_mode);
|
||||
let overflow = self.base.overflow.translate(&-Point2D(margin.left, Au(0)));
|
||||
|
||||
Arc::new(StackingContext::new(display_list,
|
||||
&border_box,
|
||||
&overflow,
|
||||
self.fragment.style().get_box().z_index.number_or_zero(),
|
||||
self.fragment.style().get_effects().opacity as f32,
|
||||
layer))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InlineFlowDisplayListBuilding {
|
||||
fn build_display_list_for_inline(&mut self, layout_context: &LayoutContext);
|
||||
}
|
||||
|
||||
impl InlineFlowDisplayListBuilding for InlineFlow {
|
||||
fn build_display_list_for_inline(&mut self, layout_context: &LayoutContext) {
|
||||
// TODO(#228): Once we form lines and have their cached bounds, we can be smarter and
|
||||
// not recurse on a line if nothing in it can intersect the dirty region.
|
||||
debug!("Flow: building display list for {:u} inline fragments", self.fragments.len());
|
||||
|
||||
let mut display_list = box DisplayList::new();
|
||||
for fragment in self.fragments.fragments.iter_mut() {
|
||||
fragment.build_display_list(&mut *display_list,
|
||||
layout_context,
|
||||
&self.base.stacking_relative_position,
|
||||
&self.base
|
||||
.absolute_position_info
|
||||
.relative_containing_block_size,
|
||||
BackgroundAndBorderLevel::Content,
|
||||
&self.base.clip);
|
||||
match fragment.specific {
|
||||
SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
|
||||
let block_flow = block_flow.flow_ref.deref_mut();
|
||||
flow::mut_base(block_flow).display_list_building_result
|
||||
.add_to(&mut *display_list)
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => {
|
||||
let block_flow = block_flow.flow_ref.deref_mut();
|
||||
flow::mut_base(block_flow).display_list_building_result
|
||||
.add_to(&mut *display_list)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
self.base.display_list_building_result = DisplayListBuildingResult::Normal(display_list);
|
||||
|
||||
if opts::get().validate_display_list_geometry {
|
||||
self.base.validate_display_list_geometry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1192,17 +1209,16 @@ impl ListItemFlowDisplayListBuilding for ListItemFlow {
|
|||
mut display_list: Box<DisplayList>,
|
||||
layout_context: &LayoutContext) {
|
||||
// Draw the marker, if applicable.
|
||||
match self.marker {
|
||||
None => {}
|
||||
Some(ref mut marker) => {
|
||||
let stacking_relative_fragment_origin =
|
||||
self.block_flow.base.stacking_relative_position_of_child_fragment(marker);
|
||||
marker.build_display_list(&mut *display_list,
|
||||
layout_context,
|
||||
stacking_relative_fragment_origin,
|
||||
BackgroundAndBorderLevel::Content,
|
||||
&self.block_flow.base.clip);
|
||||
}
|
||||
if let Some(ref mut marker) = self.marker {
|
||||
marker.build_display_list(&mut *display_list,
|
||||
layout_context,
|
||||
&self.block_flow.base.stacking_relative_position,
|
||||
&self.block_flow
|
||||
.base
|
||||
.absolute_position_info
|
||||
.relative_containing_block_size,
|
||||
BackgroundAndBorderLevel::Content,
|
||||
&self.block_flow.base.clip);
|
||||
}
|
||||
|
||||
// Draw the rest of the block.
|
||||
|
@ -1280,3 +1296,4 @@ impl StackingContextConstruction for DisplayList {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ use display_list_builder::DisplayListBuildingResult;
|
|||
use floats::Floats;
|
||||
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
||||
use flow_ref::FlowRef;
|
||||
use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||
use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, RestyleDamage};
|
||||
use inline::InlineFlow;
|
||||
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
|
||||
|
@ -50,7 +50,7 @@ use geom::{Point2D, Rect, Size2D};
|
|||
use gfx::display_list::ClippingRegion;
|
||||
use serialize::{Encoder, Encodable};
|
||||
use servo_msg::compositor_msg::LayerId;
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::geometry::{Au, ZERO_RECT};
|
||||
use servo_util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
|
||||
use std::mem;
|
||||
use std::fmt;
|
||||
|
@ -220,8 +220,13 @@ pub trait Flow: fmt::Show + ToString + Sync {
|
|||
/// Phase 5 of reflow: builds display lists.
|
||||
fn build_display_list(&mut self, layout_context: &LayoutContext);
|
||||
|
||||
/// Perform an iteration of fragment bounds on this flow.
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator);
|
||||
/// Returns the union of all overflow rects of all of this flow's fragments.
|
||||
fn compute_overflow(&self) -> Rect<Au>;
|
||||
|
||||
/// Iterates through border boxes of all of this flow's fragments.
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>);
|
||||
|
||||
fn compute_collapsible_block_start_margin(&mut self,
|
||||
_layout_context: &mut LayoutContext,
|
||||
|
@ -718,7 +723,7 @@ pub struct BaseFlow {
|
|||
|
||||
/// The amount of overflow of this flow, relative to the containing block. Must include all the
|
||||
/// pixels of all the display list items for correct invalidation.
|
||||
pub overflow: LogicalRect<Au>,
|
||||
pub overflow: Rect<Au>,
|
||||
|
||||
/// Data used during parallel traversals.
|
||||
///
|
||||
|
@ -894,7 +899,7 @@ impl BaseFlow {
|
|||
children: FlowList::new(),
|
||||
intrinsic_inline_sizes: IntrinsicISizes::new(),
|
||||
position: LogicalRect::zero(writing_mode),
|
||||
overflow: LogicalRect::zero(writing_mode),
|
||||
overflow: ZERO_RECT,
|
||||
parallel: FlowParallelInfo::new(),
|
||||
floats: Floats::new(writing_mode),
|
||||
collapsible_margins: CollapsibleMargins::new(),
|
||||
|
@ -929,10 +934,12 @@ impl BaseFlow {
|
|||
/// Ensures that all display list items generated by this flow are within the flow's overflow
|
||||
/// rect. This should only be used for debugging.
|
||||
pub fn validate_display_list_geometry(&self) {
|
||||
let position_with_overflow = self.position.union(&self.overflow);
|
||||
let bounds = Rect(self.stacking_relative_position,
|
||||
Size2D(position_with_overflow.size.inline,
|
||||
position_with_overflow.size.block));
|
||||
// FIXME(pcwalton, #2795): Get the real container size.
|
||||
let container_size = Size2D::zero();
|
||||
let position_with_overflow = self.position
|
||||
.to_physical(self.writing_mode, container_size)
|
||||
.union(&self.overflow);
|
||||
let bounds = Rect(self.stacking_relative_position, position_with_overflow.size);
|
||||
|
||||
let all_items = match self.display_list_building_result {
|
||||
DisplayListBuildingResult::None => Vec::new(),
|
||||
|
@ -953,17 +960,6 @@ impl BaseFlow {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the position of the given fragment relative to the start of the nearest ancestor
|
||||
/// stacking context. The fragment must be a child fragment of this flow.
|
||||
pub fn stacking_relative_position_of_child_fragment(&self, fragment: &Fragment)
|
||||
-> Point2D<Au> {
|
||||
let relative_offset =
|
||||
fragment.relative_position(&self
|
||||
.absolute_position_info
|
||||
.relative_containing_block_size);
|
||||
self.stacking_relative_position.add_size(&relative_offset.to_physical(self.writing_mode))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ImmutableFlowUtils for &'a Flow + 'a {
|
||||
|
@ -1060,14 +1056,14 @@ impl<'a> ImmutableFlowUtils for &'a Flow + 'a {
|
|||
let flow = match self.class() {
|
||||
FlowClass::Table | FlowClass::TableRowGroup => {
|
||||
let fragment =
|
||||
Fragment::new_anonymous_table_fragment(node,
|
||||
SpecificFragmentInfo::TableRow);
|
||||
Fragment::new_anonymous_from_specific_info(node,
|
||||
SpecificFragmentInfo::TableRow);
|
||||
box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow>
|
||||
},
|
||||
FlowClass::TableRow => {
|
||||
let fragment =
|
||||
Fragment::new_anonymous_table_fragment(node,
|
||||
SpecificFragmentInfo::TableCell);
|
||||
Fragment::new_anonymous_from_specific_info(node,
|
||||
SpecificFragmentInfo::TableCell);
|
||||
let hide = node.style().get_inheritedtable().empty_cells == empty_cells::hide;
|
||||
box TableCellFlow::from_node_fragment_and_visibility_flag(node, fragment, !hide) as
|
||||
Box<Flow>
|
||||
|
@ -1175,40 +1171,29 @@ impl<'a> MutableFlowUtils for &'a mut Flow + 'a {
|
|||
/// already been set.
|
||||
/// Assumption: Absolute descendants have had their overflow calculated.
|
||||
fn store_overflow(self, _: &LayoutContext) {
|
||||
let my_position = mut_base(self).position;
|
||||
|
||||
// FIXME(pcwalton): We should calculate overflow on a per-fragment basis, because their
|
||||
// styles can affect overflow regions. Consider `box-shadow`, `outline`, etc.--anything
|
||||
// that can draw outside the border box. For now we assume overflow is the border box, but
|
||||
// that is wrong.
|
||||
let mut overflow = my_position;
|
||||
|
||||
// Calculate overflow on a per-fragment basis.
|
||||
let mut overflow = self.compute_overflow();
|
||||
if self.is_block_container() {
|
||||
let writing_mode = base(self).writing_mode;
|
||||
// FIXME(#2795): Get the real container size
|
||||
// FIXME(#2795): Get the real container size.
|
||||
let container_size = Size2D::zero();
|
||||
for kid in child_iter(self) {
|
||||
if kid.is_store_overflow_delayed() {
|
||||
// Absolute flows will be handled by their CB. If we are
|
||||
// their CB, they will show up in `abs_descendants`.
|
||||
continue;
|
||||
if base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) {
|
||||
continue
|
||||
}
|
||||
let kid_base = base(kid);
|
||||
let mut kid_overflow = kid_base.overflow.convert(
|
||||
kid_base.writing_mode, writing_mode, container_size);
|
||||
kid_overflow = kid_overflow.translate(&my_position.start);
|
||||
overflow = overflow.union(&kid_overflow)
|
||||
let kid_overflow = base(kid).overflow;
|
||||
let kid_position = base(kid).position.to_physical(base(kid).writing_mode,
|
||||
container_size);
|
||||
overflow = overflow.union(&kid_overflow.translate(&kid_position.origin))
|
||||
}
|
||||
|
||||
// FIXME(#2004, pcwalton): This is wrong for `position: fixed`.
|
||||
for descendant_link in mut_base(self).abs_descendants.iter() {
|
||||
let kid_base = base(descendant_link);
|
||||
let mut kid_overflow = kid_base.overflow.convert(
|
||||
kid_base.writing_mode, writing_mode, container_size);
|
||||
kid_overflow = kid_overflow.translate(&my_position.start);
|
||||
overflow = overflow.union(&kid_overflow)
|
||||
for kid in mut_base(self).abs_descendants.iter() {
|
||||
let kid_overflow = base(kid).overflow;
|
||||
let kid_position = base(kid).position.to_physical(base(kid).writing_mode,
|
||||
container_size);
|
||||
overflow = overflow.union(&kid_overflow.translate(&kid_position.origin))
|
||||
}
|
||||
}
|
||||
|
||||
mut_base(self).overflow = overflow;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ use util::OpaqueNodeMethods;
|
|||
use wrapper::{TLayoutNode, ThreadSafeLayoutNode};
|
||||
|
||||
use geom::{Point2D, Rect, Size2D};
|
||||
use gfx::display_list::OpaqueNode;
|
||||
use gfx::display_list::{BOX_SHADOW_INFLATION_FACTOR, OpaqueNode};
|
||||
use gfx::text::glyph::CharIndex;
|
||||
use gfx::text::text_run::{TextRun, TextRunSlice};
|
||||
use script_traits::UntrustedNodeAddress;
|
||||
|
@ -31,8 +31,7 @@ use serialize::{Encodable, Encoder};
|
|||
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
||||
use servo_net::image::holder::ImageHolder;
|
||||
use servo_net::local_image_cache::LocalImageCache;
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::geometry;
|
||||
use servo_util::geometry::{mod, Au, ZERO_POINT};
|
||||
use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin};
|
||||
use servo_util::range::*;
|
||||
use servo_util::smallvec::SmallVec;
|
||||
|
@ -62,8 +61,8 @@ use url::Url;
|
|||
/// positioned as if it were a block fragment, but its children are positioned according to
|
||||
/// inline flow.
|
||||
///
|
||||
/// A `SpecificFragmentInfo::Generic` is an empty fragment that contributes only borders, margins, padding, and
|
||||
/// backgrounds. It is analogous to a CSS nonreplaced content box.
|
||||
/// A `SpecificFragmentInfo::Generic` is an empty fragment that contributes only borders, margins,
|
||||
/// padding, and 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 content such as images are resized differently from tables, text, or other content.
|
||||
|
@ -83,8 +82,10 @@ pub struct Fragment {
|
|||
/// The CSS style of this fragment.
|
||||
pub style: Arc<ComputedValues>,
|
||||
|
||||
/// The position of this fragment relative to its owning flow.
|
||||
/// The size includes padding and border, but not margin.
|
||||
/// The position of this fragment relative to its owning flow. The size includes padding and
|
||||
/// border, but not margin.
|
||||
///
|
||||
/// NB: This does not account for relative positioning.
|
||||
pub border_box: LogicalRect<Au>,
|
||||
|
||||
/// The sum of border and padding; i.e. the distance from the edge of the border box to the
|
||||
|
@ -520,10 +521,28 @@ impl Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Fragment` instance for an anonymous object.
|
||||
pub fn new_anonymous(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode)
|
||||
-> Fragment {
|
||||
let node_style = cascade_anonymous(&**node.style());
|
||||
let writing_mode = node_style.writing_mode;
|
||||
Fragment {
|
||||
node: OpaqueNodeMethods::from_thread_safe_layout_node(node),
|
||||
style: Arc::new(node_style),
|
||||
restyle_damage: node.restyle_damage(),
|
||||
border_box: LogicalRect::zero(writing_mode),
|
||||
border_padding: LogicalMargin::zero(writing_mode),
|
||||
margin: LogicalMargin::zero(writing_mode),
|
||||
specific: constructor.build_specific_fragment_info_for_node(node),
|
||||
inline_context: None,
|
||||
debug_id: layout_debug::generate_unique_debug_id(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Fragment` instance for an anonymous table object.
|
||||
pub fn new_anonymous_table_fragment(node: &ThreadSafeLayoutNode,
|
||||
specific: SpecificFragmentInfo)
|
||||
-> Fragment {
|
||||
pub fn new_anonymous_from_specific_info(node: &ThreadSafeLayoutNode,
|
||||
specific: SpecificFragmentInfo)
|
||||
-> Fragment {
|
||||
// CSS 2.1 § 17.2.1 This is for non-inherited properties on anonymous table fragments
|
||||
// example:
|
||||
//
|
||||
|
@ -531,8 +550,9 @@ impl Fragment {
|
|||
// Foo
|
||||
// </div>
|
||||
//
|
||||
// Anonymous table fragments, SpecificFragmentInfo::TableRow and SpecificFragmentInfo::TableCell, are generated around
|
||||
// `Foo`, but they shouldn't inherit the border.
|
||||
// Anonymous table fragments, SpecificFragmentInfo::TableRow and
|
||||
// SpecificFragmentInfo::TableCell, are generated around `Foo`, but they shouldn't inherit
|
||||
// the border.
|
||||
|
||||
let node_style = cascade_anonymous(&**node.style());
|
||||
let writing_mode = node_style.writing_mode;
|
||||
|
@ -647,7 +667,10 @@ impl Fragment {
|
|||
fn quantities_included_in_intrinsic_inline_size(&self)
|
||||
-> QuantitiesIncludedInIntrinsicInlineSizes {
|
||||
match self.specific {
|
||||
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::InlineBlock(_) => {
|
||||
SpecificFragmentInfo::Generic |
|
||||
SpecificFragmentInfo::Iframe(_) |
|
||||
SpecificFragmentInfo::Image(_) |
|
||||
SpecificFragmentInfo::InlineBlock(_) => {
|
||||
QuantitiesIncludedInIntrinsicInlineSizes::all()
|
||||
}
|
||||
SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => {
|
||||
|
@ -836,9 +859,7 @@ impl Fragment {
|
|||
}
|
||||
|
||||
// Return offset from original position because of `position: relative`.
|
||||
pub fn relative_position(&self,
|
||||
containing_block_size: &LogicalSize<Au>)
|
||||
-> LogicalSize<Au> {
|
||||
pub fn relative_position(&self, containing_block_size: &LogicalSize<Au>) -> LogicalSize<Au> {
|
||||
fn from_style(style: &ComputedValues, container_size: &LogicalSize<Au>)
|
||||
-> LogicalSize<Au> {
|
||||
let offsets = style.logical_position();
|
||||
|
@ -1506,10 +1527,17 @@ impl Fragment {
|
|||
/// because the corresponding table flow is the primary fragment.
|
||||
pub fn is_primary_fragment(&self) -> bool {
|
||||
match self.specific {
|
||||
SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||
SpecificFragmentInfo::InlineBlock(_) |
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||
SpecificFragmentInfo::TableWrapper => false,
|
||||
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) |
|
||||
SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::TableColumn(_) | SpecificFragmentInfo::TableRow |
|
||||
SpecificFragmentInfo::Generic |
|
||||
SpecificFragmentInfo::Iframe(_) |
|
||||
SpecificFragmentInfo::Image(_) |
|
||||
SpecificFragmentInfo::ScannedText(_) |
|
||||
SpecificFragmentInfo::Table |
|
||||
SpecificFragmentInfo::TableCell |
|
||||
SpecificFragmentInfo::TableColumn(_) |
|
||||
SpecificFragmentInfo::TableRow |
|
||||
SpecificFragmentInfo::UnscannedText(_) => true,
|
||||
}
|
||||
}
|
||||
|
@ -1538,15 +1566,48 @@ impl Fragment {
|
|||
self.style = (*new_style).clone()
|
||||
}
|
||||
|
||||
/// Given the stacking-context-relative position of the containing flow, returns the boundaries
|
||||
/// of this fragment relative to the parent stacking context.
|
||||
pub fn stacking_relative_bounds(&self, stacking_relative_flow_origin: &Point2D<Au>)
|
||||
-> Rect<Au> {
|
||||
// FIXME(#2795): Get the real container size
|
||||
/// Given the stacking-context-relative position of the containing flow, returns the border box
|
||||
/// of this fragment relative to the parent stacking context. This takes `position: relative`
|
||||
/// into account.
|
||||
///
|
||||
/// If `coordinate_system` is `Parent`, this returns the border box in the parent stacking
|
||||
/// context's coordinate system. Otherwise, if `coordinate_system` is `Self` and this fragment
|
||||
/// establishes a stacking context itself, this returns a border box anchored at (0, 0). (If
|
||||
/// this fragment does not establish a stacking context, then it always belongs to its parent
|
||||
/// stacking context and thus `coordinate_system` is ignored.)
|
||||
///
|
||||
/// This is the method you should use for display list construction as well as
|
||||
/// `getBoundingClientRect()` and so forth.
|
||||
pub fn stacking_relative_border_box(&self,
|
||||
stacking_relative_flow_origin: &Point2D<Au>,
|
||||
relative_containing_block_size: &LogicalSize<Au>,
|
||||
coordinate_system: CoordinateSystem)
|
||||
-> Rect<Au> {
|
||||
// FIXME(pcwalton, #2795): Get the real container size.
|
||||
let container_size = Size2D::zero();
|
||||
self.border_box
|
||||
.to_physical(self.style.writing_mode, container_size)
|
||||
.translate(stacking_relative_flow_origin)
|
||||
let border_box = self.border_box.to_physical(self.style.writing_mode, container_size);
|
||||
if coordinate_system == CoordinateSystem::Self && self.establishes_stacking_context() {
|
||||
return Rect(ZERO_POINT, border_box.size)
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): This can double-count relative position sometimes for inlines (e.g.
|
||||
// `<div style="position:relative">x</div>`, because the `position:relative` trickles down
|
||||
// to the inline flow. Possibly we should extend the notion of "primary fragment" to fix
|
||||
// this.
|
||||
let relative_position = self.relative_position(relative_containing_block_size);
|
||||
border_box.translate_by_size(&relative_position.to_physical(self.style.writing_mode))
|
||||
.translate(stacking_relative_flow_origin)
|
||||
}
|
||||
|
||||
/// Given the stacking-context-relative border box, returns the stacking-context-relative
|
||||
/// content box.
|
||||
pub fn stacking_relative_content_box(&self, stacking_relative_border_box: &Rect<Au>)
|
||||
-> Rect<Au> {
|
||||
let border_padding = self.border_padding.to_physical(self.style.writing_mode);
|
||||
Rect(Point2D(stacking_relative_border_box.origin.x + border_padding.left,
|
||||
stacking_relative_border_box.origin.y + border_padding.top),
|
||||
Size2D(stacking_relative_border_box.size.width - border_padding.horizontal(),
|
||||
stacking_relative_border_box.size.height - border_padding.vertical()))
|
||||
}
|
||||
|
||||
/// Returns true if this fragment establishes a new stacking context and false otherwise.
|
||||
|
@ -1567,6 +1628,41 @@ impl Fragment {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the overflow rect of this fragment relative to the start of the flow.
|
||||
pub fn compute_overflow(&self) -> Rect<Au> {
|
||||
// FIXME(pcwalton, #2795): Get the real container size.
|
||||
let container_size = Size2D::zero();
|
||||
let mut border_box = self.border_box.to_physical(self.style.writing_mode, container_size);
|
||||
|
||||
// Relative position can cause us to draw outside our border box.
|
||||
//
|
||||
// FIXME(pcwalton): I'm not a fan of the way this makes us crawl though so many styles all
|
||||
// the time. Can't we handle relative positioning by just adjusting `border_box`?
|
||||
let relative_position =
|
||||
self.relative_position(&LogicalSize::zero(self.style.writing_mode));
|
||||
border_box =
|
||||
border_box.translate_by_size(&relative_position.to_physical(self.style.writing_mode));
|
||||
let mut overflow = border_box;
|
||||
|
||||
// Box shadows cause us to draw outside our border box.
|
||||
for box_shadow in self.style().get_effects().box_shadow.iter() {
|
||||
let offset = Point2D(box_shadow.offset_x, box_shadow.offset_y);
|
||||
let inflation = box_shadow.spread_radius +
|
||||
box_shadow.blur_radius * BOX_SHADOW_INFLATION_FACTOR;
|
||||
overflow = overflow.union(&border_box.translate(&offset).inflate(inflation, inflation))
|
||||
}
|
||||
|
||||
// Outlines cause us to draw outside our border box.
|
||||
let outline_width = self.style.get_outline().outline_width;
|
||||
if outline_width != Au(0) {
|
||||
overflow = overflow.union(&border_box.inflate(outline_width, outline_width))
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): Sometimes excessively fancy glyphs can make us draw outside our border
|
||||
// box too.
|
||||
overflow
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Show for Fragment {
|
||||
|
@ -1600,13 +1696,23 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
/// A top-down fragment bounds iteration handler.
|
||||
pub trait FragmentBoundsIterator {
|
||||
/// A top-down fragment border box iteration handler.
|
||||
pub trait FragmentBorderBoxIterator {
|
||||
/// The operation to perform.
|
||||
fn process(&mut self, fragment: &Fragment, bounds: Rect<Au>);
|
||||
fn process(&mut self, fragment: &Fragment, overflow: &Rect<Au>);
|
||||
|
||||
/// Returns true if this fragment must be processed in-order. If this returns false,
|
||||
/// we skip the operation for this fragment, but continue processing siblings.
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool;
|
||||
}
|
||||
|
||||
/// The coordinate system used in `stacking_relative_border_box()`. See the documentation of that
|
||||
/// method for details.
|
||||
#[deriving(Clone, PartialEq, Show)]
|
||||
pub enum CoordinateSystem {
|
||||
/// The border box returned is relative to the fragment's parent stacking context.
|
||||
Parent,
|
||||
/// The border box returned is relative to the fragment's own stacking context, if applicable.
|
||||
Self,
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
use css::node_style::StyledNode;
|
||||
use context::LayoutContext;
|
||||
use display_list_builder::{BackgroundAndBorderLevel, DisplayListBuildingResult, FragmentDisplayListBuilding};
|
||||
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
|
||||
use floats::{FloatKind, Floats, PlacementInfo};
|
||||
use flow::{BaseFlow, FlowClass, Flow, MutableFlowUtils, ForceNonfloatedFlag};
|
||||
use flow::{IS_ABSOLUTELY_POSITIONED};
|
||||
use flow;
|
||||
use fragment::{Fragment, SpecificFragmentInfo};
|
||||
use fragment::{FragmentBoundsIterator, ScannedTextFragmentInfo};
|
||||
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, ScannedTextFragmentInfo};
|
||||
use fragment::{SpecificFragmentInfo};
|
||||
use fragment::SplitInfo;
|
||||
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||
use layout_debug;
|
||||
|
@ -20,16 +20,14 @@ use model::IntrinsicISizesContribution;
|
|||
use text;
|
||||
|
||||
use collections::{RingBuf};
|
||||
use geom::Size2D;
|
||||
use gfx::display_list::DisplayList;
|
||||
use geom::{Point2D, Rect};
|
||||
use gfx::font::FontMetrics;
|
||||
use gfx::font_context::FontContext;
|
||||
use gfx::text::glyph::CharIndex;
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
|
||||
use servo_util::opts;
|
||||
use servo_util::range::{Range, RangeIndex};
|
||||
use servo_util::arc_ptr_eq;
|
||||
use servo_util::geometry::{Au, ZERO_RECT};
|
||||
use servo_util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
|
||||
use servo_util::range::{Range, RangeIndex};
|
||||
use std::cmp::max;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
|
@ -1186,44 +1184,29 @@ impl Flow for InlineFlow {
|
|||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
for fragment in self.fragments.fragments.iter_mut() {
|
||||
let stacking_relative_position = match fragment.specific {
|
||||
SpecificFragmentInfo::InlineBlock(ref mut info) => {
|
||||
let block_flow = info.flow_ref.as_block();
|
||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
||||
|
||||
// FIXME(#2795): Get the real container size
|
||||
let container_size = Size2D::zero();
|
||||
block_flow.base.stacking_relative_position =
|
||||
self.base.stacking_relative_position +
|
||||
fragment.border_box.start.to_physical(self.base.writing_mode,
|
||||
container_size);
|
||||
block_flow.base.stacking_relative_position
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => {
|
||||
let block_flow = info.flow_ref.as_block();
|
||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
||||
|
||||
// FIXME(#2795): Get the real container size
|
||||
let container_size = Size2D::zero();
|
||||
block_flow.base.stacking_relative_position =
|
||||
self.base.stacking_relative_position +
|
||||
fragment.border_box.start.to_physical(self.base.writing_mode,
|
||||
container_size);
|
||||
block_flow.base.stacking_relative_position
|
||||
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let stacking_relative_border_box =
|
||||
fragment.stacking_relative_border_box(&self.base.stacking_relative_position,
|
||||
&self.base
|
||||
.absolute_position_info
|
||||
.relative_containing_block_size,
|
||||
CoordinateSystem::Self);
|
||||
let clip = fragment.clipping_region_for_children(&self.base.clip,
|
||||
&stacking_relative_position);
|
||||
|
||||
&stacking_relative_border_box);
|
||||
match fragment.specific {
|
||||
SpecificFragmentInfo::InlineBlock(ref mut info) => {
|
||||
flow::mut_base(info.flow_ref.deref_mut()).clip = clip
|
||||
flow::mut_base(info.flow_ref.deref_mut()).clip = clip;
|
||||
let block_flow = info.flow_ref.as_block();
|
||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
||||
block_flow.base.stacking_relative_position =
|
||||
stacking_relative_border_box.origin;
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => {
|
||||
flow::mut_base(info.flow_ref.deref_mut()).clip = clip
|
||||
flow::mut_base(info.flow_ref.deref_mut()).clip = clip;
|
||||
let block_flow = info.flow_ref.as_block();
|
||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
||||
block_flow.base.stacking_relative_position =
|
||||
stacking_relative_border_box.origin
|
||||
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -1235,49 +1218,36 @@ impl Flow for InlineFlow {
|
|||
fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}
|
||||
|
||||
fn build_display_list(&mut self, layout_context: &LayoutContext) {
|
||||
// TODO(#228): Once we form lines and have their cached bounds, we can be smarter and
|
||||
// not recurse on a line if nothing in it can intersect the dirty region.
|
||||
debug!("Flow: building display list for {} inline fragments", self.fragments.len());
|
||||
|
||||
let mut display_list = box DisplayList::new();
|
||||
for fragment in self.fragments.fragments.iter_mut() {
|
||||
let fragment_origin = self.base.stacking_relative_position_of_child_fragment(fragment);
|
||||
fragment.build_display_list(&mut *display_list,
|
||||
layout_context,
|
||||
fragment_origin,
|
||||
BackgroundAndBorderLevel::Content,
|
||||
&self.base.clip);
|
||||
match fragment.specific {
|
||||
SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
|
||||
let block_flow = block_flow.flow_ref.deref_mut();
|
||||
flow::mut_base(block_flow).display_list_building_result
|
||||
.add_to(&mut *display_list)
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => {
|
||||
let block_flow = block_flow.flow_ref.deref_mut();
|
||||
flow::mut_base(block_flow).display_list_building_result
|
||||
.add_to(&mut *display_list)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
self.base.display_list_building_result = DisplayListBuildingResult::Normal(display_list);
|
||||
|
||||
if opts::get().validate_display_list_geometry {
|
||||
self.base.validate_display_list_geometry();
|
||||
}
|
||||
self.build_display_list_for_inline(layout_context)
|
||||
}
|
||||
|
||||
fn repair_style(&mut self, _: &Arc<ComputedValues>) {}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
let mut overflow = ZERO_RECT;
|
||||
for fragment in self.fragments.fragments.iter() {
|
||||
if iterator.should_process(fragment) {
|
||||
let fragment_origin =
|
||||
self.base.stacking_relative_position_of_child_fragment(fragment);
|
||||
iterator.process(fragment, fragment.stacking_relative_bounds(&fragment_origin));
|
||||
overflow = overflow.union(&fragment.compute_overflow())
|
||||
}
|
||||
overflow
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
// FIXME(#2795): Get the real container size.
|
||||
for fragment in self.fragments.fragments.iter() {
|
||||
if !iterator.should_process(fragment) {
|
||||
continue
|
||||
}
|
||||
|
||||
let stacking_relative_position = &self.base.stacking_relative_position;
|
||||
let relative_containing_block_size =
|
||||
&self.base.absolute_position_info.relative_containing_block_size;
|
||||
iterator.process(fragment,
|
||||
&fragment.stacking_relative_border_box(stacking_relative_position,
|
||||
relative_containing_block_size,
|
||||
CoordinateSystem::Parent)
|
||||
.translate(stacking_context_position))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use construct::ConstructionResult;
|
|||
use context::SharedLayoutContext;
|
||||
use flow::{mod, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
|
||||
use flow_ref::FlowRef;
|
||||
use fragment::{Fragment, FragmentBoundsIterator};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
|
||||
use layout_debug;
|
||||
use parallel::{mod, UnsafeFlow};
|
||||
|
@ -604,8 +604,8 @@ impl LayoutTask {
|
|||
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
|
||||
// stuff. So the position is wrong in most cases.
|
||||
let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node);
|
||||
let mut iterator = UnioningFragmentBoundsIterator::new(requested_node);
|
||||
sequential::iterate_through_flow_tree_fragment_bounds(layout_root, &mut iterator);
|
||||
let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node);
|
||||
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
|
||||
rw_data.content_box_response = iterator.rect;
|
||||
}
|
||||
|
||||
|
@ -616,8 +616,8 @@ impl LayoutTask {
|
|||
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
|
||||
// stuff. So the position is wrong in most cases.
|
||||
let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node);
|
||||
let mut iterator = CollectingFragmentBoundsIterator::new(requested_node);
|
||||
sequential::iterate_through_flow_tree_fragment_bounds(layout_root, &mut iterator);
|
||||
let mut iterator = CollectingFragmentBorderBoxIterator::new(requested_node);
|
||||
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
|
||||
rw_data.content_boxes_response = iterator.rects;
|
||||
}
|
||||
|
||||
|
@ -689,11 +689,12 @@ impl LayoutTask {
|
|||
flow::mut_base(layout_root.deref_mut()).display_list_building_result
|
||||
.add_to(&mut *display_list);
|
||||
let paint_layer = Arc::new(PaintLayer::new(layout_root.layer_id(0),
|
||||
color,
|
||||
Scrollable));
|
||||
color,
|
||||
Scrollable));
|
||||
let origin = Rect(Point2D(Au(0), Au(0)), root_size);
|
||||
let stacking_context = Arc::new(StackingContext::new(display_list,
|
||||
origin,
|
||||
&origin,
|
||||
&origin,
|
||||
0,
|
||||
1.0,
|
||||
Some(paint_layer)));
|
||||
|
@ -1016,26 +1017,26 @@ impl LayoutRPC for LayoutRPCImpl {
|
|||
}
|
||||
}
|
||||
|
||||
struct UnioningFragmentBoundsIterator {
|
||||
struct UnioningFragmentBorderBoxIterator {
|
||||
node_address: OpaqueNode,
|
||||
rect: Rect<Au>,
|
||||
}
|
||||
|
||||
impl UnioningFragmentBoundsIterator {
|
||||
fn new(node_address: OpaqueNode) -> UnioningFragmentBoundsIterator {
|
||||
UnioningFragmentBoundsIterator {
|
||||
impl UnioningFragmentBorderBoxIterator {
|
||||
fn new(node_address: OpaqueNode) -> UnioningFragmentBorderBoxIterator {
|
||||
UnioningFragmentBorderBoxIterator {
|
||||
node_address: node_address,
|
||||
rect: Rect::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FragmentBoundsIterator for UnioningFragmentBoundsIterator {
|
||||
fn process(&mut self, _: &Fragment, bounds: Rect<Au>) {
|
||||
if self.rect.is_empty() {
|
||||
self.rect = bounds;
|
||||
impl FragmentBorderBoxIterator for UnioningFragmentBorderBoxIterator {
|
||||
fn process(&mut self, _: &Fragment, border_box: &Rect<Au>) {
|
||||
self.rect = if self.rect.is_empty() {
|
||||
*border_box
|
||||
} else {
|
||||
self.rect = self.rect.union(&bounds);
|
||||
self.rect.union(border_box)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1044,23 +1045,23 @@ impl FragmentBoundsIterator for UnioningFragmentBoundsIterator {
|
|||
}
|
||||
}
|
||||
|
||||
struct CollectingFragmentBoundsIterator {
|
||||
struct CollectingFragmentBorderBoxIterator {
|
||||
node_address: OpaqueNode,
|
||||
rects: Vec<Rect<Au>>,
|
||||
}
|
||||
|
||||
impl CollectingFragmentBoundsIterator {
|
||||
fn new(node_address: OpaqueNode) -> CollectingFragmentBoundsIterator {
|
||||
CollectingFragmentBoundsIterator {
|
||||
impl CollectingFragmentBorderBoxIterator {
|
||||
fn new(node_address: OpaqueNode) -> CollectingFragmentBorderBoxIterator {
|
||||
CollectingFragmentBorderBoxIterator {
|
||||
node_address: node_address,
|
||||
rects: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FragmentBoundsIterator for CollectingFragmentBoundsIterator {
|
||||
fn process(&mut self, _: &Fragment, bounds: Rect<Au>) {
|
||||
self.rects.push(bounds);
|
||||
impl FragmentBorderBoxIterator for CollectingFragmentBorderBoxIterator {
|
||||
fn process(&mut self, _: &Fragment, border_box: &Rect<Au>) {
|
||||
self.rects.push(*border_box);
|
||||
}
|
||||
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool {
|
||||
|
|
|
@ -12,9 +12,10 @@ use construct::FlowConstructor;
|
|||
use context::LayoutContext;
|
||||
use display_list_builder::ListItemFlowDisplayListBuilding;
|
||||
use flow::{Flow, FlowClass};
|
||||
use fragment::{Fragment, FragmentBoundsIterator};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::{Point2D, Rect};
|
||||
use gfx::display_list::DisplayList;
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::opts;
|
||||
|
@ -111,8 +112,14 @@ impl Flow for ListItemFlow {
|
|||
self.block_flow.repair_style(new_style)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
self.block_flow.iterate_through_fragment_bounds(iterator);
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,10 @@
|
|||
//! Implements sequential traversals over the DOM and flow trees.
|
||||
|
||||
use context::{LayoutContext, SharedLayoutContext};
|
||||
use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal};
|
||||
use flow;
|
||||
use flow::{mod, Flow, ImmutableFlowUtils, MutableFlowUtils, PostorderFlowTraversal};
|
||||
use flow::{PreorderFlowTraversal};
|
||||
use flow_ref::FlowRef;
|
||||
use fragment::FragmentBoundsIterator;
|
||||
use servo_util::opts;
|
||||
use fragment::FragmentBorderBoxIterator;
|
||||
use traversal::{BubbleISizes, RecalcStyleForNode, ConstructFlows};
|
||||
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes};
|
||||
use traversal::{ComputeAbsolutePositions, BuildDisplayList};
|
||||
|
@ -17,6 +16,10 @@ use wrapper::LayoutNode;
|
|||
use wrapper::{PostorderNodeMutTraversal};
|
||||
use wrapper::{PreorderDomTraversal, PostorderDomTraversal};
|
||||
|
||||
use geom::point::Point2D;
|
||||
use servo_util::geometry::{Au, ZERO_POINT};
|
||||
use servo_util::opts;
|
||||
|
||||
pub fn traverse_dom_preorder(root: LayoutNode,
|
||||
shared_layout_context: &SharedLayoutContext) {
|
||||
fn doit(node: LayoutNode, recalc_style: RecalcStyleForNode, construct_flows: ConstructFlows) {
|
||||
|
@ -94,15 +97,25 @@ pub fn build_display_list_for_subtree(root: &mut FlowRef,
|
|||
doit(root.deref_mut(), compute_absolute_positions, build_display_list);
|
||||
}
|
||||
|
||||
pub fn iterate_through_flow_tree_fragment_bounds(root: &mut FlowRef,
|
||||
iterator: &mut FragmentBoundsIterator) {
|
||||
fn doit(flow: &mut Flow, iterator: &mut FragmentBoundsIterator) {
|
||||
flow.iterate_through_fragment_bounds(iterator);
|
||||
pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef,
|
||||
iterator: &mut FragmentBorderBoxIterator) {
|
||||
fn doit(flow: &mut Flow,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position);
|
||||
|
||||
for kid in flow::mut_base(flow).child_iter() {
|
||||
doit(kid, iterator);
|
||||
let stacking_context_position =
|
||||
if kid.is_block_flow() && kid.as_block().fragment.establishes_stacking_context() {
|
||||
*stacking_context_position + flow::base(kid).stacking_relative_position
|
||||
} else {
|
||||
*stacking_context_position
|
||||
};
|
||||
|
||||
// FIXME(#2795): Get the real container size.
|
||||
doit(kid, iterator, &stacking_context_position);
|
||||
}
|
||||
}
|
||||
|
||||
doit(root.deref_mut(), iterator);
|
||||
doit(root.deref_mut(), iterator, &ZERO_POINT);
|
||||
}
|
||||
|
|
|
@ -13,13 +13,14 @@ use context::LayoutContext;
|
|||
use floats::FloatKind;
|
||||
use flow::{mod, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
|
||||
use flow::ImmutableFlowUtils;
|
||||
use fragment::{Fragment, FragmentBoundsIterator};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use layout_debug;
|
||||
use model::{IntrinsicISizes, IntrinsicISizesContribution};
|
||||
use table_row::CellIntrinsicInlineSize;
|
||||
use table_wrapper::TableLayout;
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::{Point2D, Rect};
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::logical_geometry::LogicalRect;
|
||||
use std::cmp::max;
|
||||
|
@ -384,8 +385,14 @@ impl Flow for TableFlow {
|
|||
self.block_flow.repair_style(new_style)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
self.block_flow.iterate_through_fragment_bounds(iterator);
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ use block::BlockFlow;
|
|||
use construct::FlowConstructor;
|
||||
use context::LayoutContext;
|
||||
use flow::{FlowClass, Flow};
|
||||
use fragment::FragmentBoundsIterator;
|
||||
use fragment::FragmentBorderBoxIterator;
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::{Point2D, Rect};
|
||||
use servo_util::geometry::Au;
|
||||
use std::fmt;
|
||||
use style::ComputedValues;
|
||||
|
@ -81,8 +82,14 @@ impl Flow for TableCaptionFlow {
|
|||
self.block_flow.repair_style(new_style)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
self.block_flow.iterate_through_fragment_bounds(iterator);
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,13 @@
|
|||
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
|
||||
use context::LayoutContext;
|
||||
use flow::{Flow, FlowClass};
|
||||
use fragment::{Fragment, FragmentBoundsIterator};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use model::{MaybeAuto};
|
||||
use layout_debug;
|
||||
use table::InternalTable;
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::{Point2D, Rect};
|
||||
use servo_util::geometry::Au;
|
||||
use std::fmt;
|
||||
use style::{UnsignedIntegerAttribute, ComputedValues};
|
||||
|
@ -162,8 +163,14 @@ impl Flow for TableCellFlow {
|
|||
self.block_flow.repair_style(new_style)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
self.block_flow.iterate_through_fragment_bounds(iterator);
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
use context::LayoutContext;
|
||||
use css::node_style::StyledNode;
|
||||
use flow::{BaseFlow, FlowClass, Flow, ForceNonfloatedFlag};
|
||||
use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||
use layout_debug;
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use servo_util::geometry::Au;
|
||||
use geom::{Point2D, Rect};
|
||||
use servo_util::geometry::{Au, ZERO_RECT};
|
||||
use std::cmp::max;
|
||||
use std::fmt;
|
||||
use style::computed_values::LengthOrPercentageOrAuto;
|
||||
|
@ -96,8 +97,13 @@ impl Flow for TableColGroupFlow {
|
|||
|
||||
fn repair_style(&mut self, _: &Arc<ComputedValues>) {}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, _: &mut FragmentBoundsIterator) {
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
ZERO_RECT
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
_: &mut FragmentBorderBoxIterator,
|
||||
_: &Point2D<Au>) {}
|
||||
}
|
||||
|
||||
impl fmt::Show for TableColGroupFlow {
|
||||
|
|
|
@ -12,12 +12,13 @@ use construct::FlowConstructor;
|
|||
use context::LayoutContext;
|
||||
use flow::{FlowClass, Flow, ImmutableFlowUtils};
|
||||
use flow;
|
||||
use fragment::{Fragment, FragmentBoundsIterator};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use layout_debug;
|
||||
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable};
|
||||
use model::MaybeAuto;
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::{Point2D, Rect};
|
||||
use servo_util::geometry::Au;
|
||||
use std::cmp::max;
|
||||
use std::fmt;
|
||||
|
@ -315,8 +316,14 @@ impl Flow for TableRowFlow {
|
|||
self.block_flow.repair_style(new_style)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
self.block_flow.iterate_through_fragment_bounds(iterator);
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,11 +10,12 @@ use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
|
|||
use construct::FlowConstructor;
|
||||
use context::LayoutContext;
|
||||
use flow::{FlowClass, Flow};
|
||||
use fragment::{Fragment, FragmentBoundsIterator};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use layout_debug;
|
||||
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::{Point2D, Rect};
|
||||
use servo_util::geometry::Au;
|
||||
use std::fmt;
|
||||
use style::ComputedValues;
|
||||
|
@ -150,8 +151,14 @@ impl Flow for TableRowGroupFlow {
|
|||
self.block_flow.repair_style(new_style)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
self.block_flow.iterate_through_fragment_bounds(iterator);
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,11 @@ use context::LayoutContext;
|
|||
use floats::FloatKind;
|
||||
use flow::{FlowClass, Flow, ImmutableFlowUtils};
|
||||
use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
|
||||
use fragment::{Fragment, FragmentBoundsIterator};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::{Point2D, Rect};
|
||||
use servo_util::geometry::Au;
|
||||
use std::cmp::{max, min};
|
||||
use std::fmt;
|
||||
|
@ -358,8 +359,14 @@ impl Flow for TableWrapperFlow {
|
|||
self.block_flow.repair_style(new_style)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
self.block_flow.iterate_through_fragment_bounds(iterator);
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
iterator: &mut FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>) {
|
||||
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -332,12 +332,7 @@ impl<'a> PostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> {
|
|||
}
|
||||
|
||||
flow.assign_block_size(self.layout_context);
|
||||
|
||||
// Skip store-overflow for absolutely positioned flows. That will be
|
||||
// done in a separate traversal.
|
||||
if !flow.is_store_overflow_delayed() {
|
||||
flow.store_overflow(self.layout_context);
|
||||
}
|
||||
flow.store_overflow(self.layout_context);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -75,7 +75,7 @@ pub struct LayerMetadata {
|
|||
/// An opaque ID. This is usually the address of the flow and index of the box within it.
|
||||
pub id: LayerId,
|
||||
/// The position and size of the layer in pixels.
|
||||
pub position: Rect<uint>,
|
||||
pub position: Rect<i32>,
|
||||
/// The background color of the layer.
|
||||
pub background_color: Color,
|
||||
/// The scrolling policy of this layer.
|
||||
|
|
2
components/servo/Cargo.lock
generated
2
components/servo/Cargo.lock
generated
|
@ -248,7 +248,7 @@ source = "git+https://github.com/alexcrichton/gcc-rs#903e8f8a2e3766ad3d514404d45
|
|||
[[package]]
|
||||
name = "geom"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/servo/rust-geom#da6b4a36a5549cf78bf702f0b9387b5c8cf61498"
|
||||
source = "git+https://github.com/servo/rust-geom#0f77c6ad116748b7e6bedbf2414d4ceea17debc2"
|
||||
|
||||
[[package]]
|
||||
name = "gfx"
|
||||
|
|
|
@ -44,7 +44,7 @@ pub use selector_matching::{matches, matches_simple_selector, common_style_affec
|
|||
pub use selector_matching::{rare_style_affecting_attributes};
|
||||
pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE, SELECTOR_WHITESPACE};
|
||||
pub use properties::{cascade, cascade_anonymous, computed, longhands_from_shorthand};
|
||||
pub use properties::is_supported_property;
|
||||
pub use properties::{is_supported_property, make_inline};
|
||||
pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs};
|
||||
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
||||
pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult};
|
||||
|
|
|
@ -3183,6 +3183,15 @@ pub fn cascade_anonymous(parent_style: &ComputedValues) -> ComputedValues {
|
|||
result
|
||||
}
|
||||
|
||||
/// Sets `display` to `inline` and `position` to `static`.
|
||||
#[inline]
|
||||
pub fn make_inline(style: &ComputedValues) -> ComputedValues {
|
||||
let mut style = (*style).clone();
|
||||
style.box_.make_unique().display = longhands::display::computed_value::T::inline;
|
||||
style.box_.make_unique().position = longhands::position::computed_value::T::static_;
|
||||
style
|
||||
}
|
||||
|
||||
pub fn is_supported_property(property: &str) -> bool {
|
||||
match property {
|
||||
% for property in SHORTHANDS:
|
||||
|
|
2
ports/cef/Cargo.lock
generated
2
ports/cef/Cargo.lock
generated
|
@ -244,7 +244,7 @@ source = "git+https://github.com/alexcrichton/gcc-rs#903e8f8a2e3766ad3d514404d45
|
|||
[[package]]
|
||||
name = "geom"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/servo/rust-geom#da6b4a36a5549cf78bf702f0b9387b5c8cf61498"
|
||||
source = "git+https://github.com/servo/rust-geom#0f77c6ad116748b7e6bedbf2414d4ceea17debc2"
|
||||
|
||||
[[package]]
|
||||
name = "gfx"
|
||||
|
|
2
ports/gonk/Cargo.lock
generated
2
ports/gonk/Cargo.lock
generated
|
@ -227,7 +227,7 @@ source = "git+https://github.com/alexcrichton/gcc-rs#903e8f8a2e3766ad3d514404d45
|
|||
[[package]]
|
||||
name = "geom"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/servo/rust-geom#da6b4a36a5549cf78bf702f0b9387b5c8cf61498"
|
||||
source = "git+https://github.com/servo/rust-geom#0f77c6ad116748b7e6bedbf2414d4ceea17debc2"
|
||||
|
||||
[[package]]
|
||||
name = "gfx"
|
||||
|
|
|
@ -22,7 +22,7 @@ function _pass(s, m) {
|
|||
|
||||
function _printer(opstr, op) {
|
||||
return function (a, b, msg) {
|
||||
let f = op(a,b) ? _pass : _fail;
|
||||
var f = op(a,b) ? _pass : _fail;
|
||||
if (!msg) msg = "";
|
||||
f(a + " " + opstr + " " + b, msg);
|
||||
};
|
||||
|
|
|
@ -222,3 +222,5 @@ fragment=top != ../html/acid2.html acid2_ref.html
|
|||
!= inset_blackborder.html blackborder_ref.html
|
||||
!= outset_blackborder.html blackborder_ref.html
|
||||
== border_radius_clip_a.html border_radius_clip_ref.html
|
||||
== stacking_context_overflow_a.html stacking_context_overflow_ref.html
|
||||
== stacking_context_overflow_relative_outline_a.html stacking_context_overflow_relative_outline_ref.html
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
<div style="position: absolute; top: 0px; left: 0px;">
|
||||
<div style="position: absolute; background: green; margin-left: 512px; width: 20px; height: 20px;"></div>
|
||||
<div style="position: absolute; background: green; top: 0; margin-left: 512px; width: 20px; height: 20px;"></div>
|
||||
|
||||
<!-- This position:fixed sibling should force its sibling to be layerized. -->
|
||||
<div style="position: fixed;"></div>
|
||||
|
|
22
tests/ref/stacking_context_overflow_a.html
Normal file
22
tests/ref/stacking_context_overflow_a.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<html>
|
||||
<head>
|
||||
<!-- Tests that stacking contexts display overflow. -->
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
section {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border: solid black 2px;
|
||||
font: 24px Arial;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<section>CSS IS AWESOME</section>
|
||||
</body>
|
||||
</html>
|
||||
|
21
tests/ref/stacking_context_overflow_ref.html
Normal file
21
tests/ref/stacking_context_overflow_ref.html
Normal file
|
@ -0,0 +1,21 @@
|
|||
<html>
|
||||
<head>
|
||||
<!-- Tests that stacking contexts display overflow. -->
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
section {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border: solid black 2px;
|
||||
font: 24px Arial;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<section>CSS IS AWESOME</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
25
tests/ref/stacking_context_overflow_relative_outline_a.html
Normal file
25
tests/ref/stacking_context_overflow_relative_outline_a.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
section {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
h1 {
|
||||
position: relative;
|
||||
top: -50px;
|
||||
left: -50px;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
margin: 0;
|
||||
outline: solid 10px green;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<section><h1></h1></section>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
section {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 40px;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: solid 10px green;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<section></section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue