diff --git a/components/layout/block.rs b/components/layout/block.rs index b38595289a5..130ffe0b5c0 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -35,6 +35,7 @@ use gfx::display_list::{BackgroundAndBorderLevel, BlockLevel, ContentStackingLev use gfx::display_list::{FloatStackingLevel, PositionedDescendantStackingLevel}; use gfx::display_list::{RootOfStackingContextLevel}; use gfx::render_task::RenderLayer; +use serialize::{Encoder, Encodable}; use servo_msg::compositor_msg::{FixedPosition, LayerId, Scrollable}; use servo_util::geometry::{Au, MAX_AU}; use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize}; @@ -511,10 +512,6 @@ pub struct BlockFlow { /// The associated fragment. pub fragment: Fragment, - /// TODO: is_root should be a bit field to conserve memory. - /// Whether this block flow is the root flow. - pub is_root: bool, - /// Static y offset of an absolute flow from its CB. pub static_b_offset: Au, @@ -527,7 +524,23 @@ pub struct BlockFlow { inline_size_of_preceding_right_floats: Au, /// Additional floating flow members. - pub float: Option> + pub float: Option>, + + /// Various flags. + pub flags: BlockFlowFlags, +} + +bitflags! { + flags BlockFlowFlags: u8 { + #[doc="If this is set, then this block flow is the root flow."] + static IsRoot = 0x01, + } +} + +impl<'a,E,S> Encodable for BlockFlowFlags where S: Encoder { + fn encode(&self, e: &mut S) -> Result<(),E> { + self.bits().encode(e) + } } impl BlockFlow { @@ -535,11 +548,11 @@ impl BlockFlow { BlockFlow { base: BaseFlow::new((*node).clone()), fragment: Fragment::new(constructor, node), - is_root: false, static_b_offset: Au::new(0), inline_size_of_preceding_left_floats: Au(0), inline_size_of_preceding_right_floats: Au(0), - float: None + float: None, + flags: BlockFlowFlags::empty(), } } @@ -547,11 +560,11 @@ impl BlockFlow { BlockFlow { base: BaseFlow::new((*node).clone()), fragment: fragment, - is_root: false, static_b_offset: Au::new(0), inline_size_of_preceding_left_floats: Au(0), inline_size_of_preceding_right_floats: Au(0), - float: None + float: None, + flags: BlockFlowFlags::empty(), } } @@ -562,12 +575,12 @@ impl BlockFlow { let base = BaseFlow::new((*node).clone()); BlockFlow { fragment: Fragment::new(constructor, node), - is_root: false, static_b_offset: Au::new(0), inline_size_of_preceding_left_floats: Au(0), inline_size_of_preceding_right_floats: Au(0), float: Some(box FloatedBlockInfo::new(float_kind)), base: base, + flags: BlockFlowFlags::empty(), } } @@ -578,12 +591,12 @@ impl BlockFlow { let base = BaseFlow::new((*node).clone()); BlockFlow { fragment: fragment, - is_root: false, static_b_offset: Au::new(0), inline_size_of_preceding_left_floats: Au(0), inline_size_of_preceding_right_floats: Au(0), float: Some(box FloatedBlockInfo::new(float_kind)), base: base, + flags: BlockFlowFlags::empty(), } } @@ -1164,7 +1177,7 @@ impl BlockFlow { // Calculate used value of block-size just like we do for inline replaced elements. // TODO: Pass in the containing block block-size when Fragment's // assign-block-size can handle it correctly. - self.fragment.assign_replaced_block_size_if_necessary(); + self.fragment.assign_replaced_block_size_if_necessary(containing_block_block_size); // TODO: Right now, this content block-size value includes the // margin because of erroneous block-size calculation in fragment. // Check this when that has been fixed. @@ -1346,7 +1359,7 @@ impl BlockFlow { // The inline-start margin edge of the child flow is at our inline-start content edge, // and its inline-size is our content inline-size. flow::mut_base(kid).position.start.i = inline_start_content_edge; - flow::mut_base(kid).position.size.inline = content_inline_size; + flow::mut_base(kid).block_container_inline_size = content_inline_size; // Determine float impaction. match kid.float_clearance() { @@ -1575,7 +1588,7 @@ impl Flow for BlockFlow { if self.is_root() { debug!("Setting root position"); self.base.position.start = LogicalPoint::zero(self.base.writing_mode); - self.base.position.size.inline = LogicalSize::from_physical( + self.base.block_container_inline_size = LogicalSize::from_physical( self.base.writing_mode, layout_context.shared.screen_size).inline; self.base.floats = Floats::new(self.base.writing_mode); @@ -1584,9 +1597,9 @@ impl Flow for BlockFlow { self.base.flags.set_impacted_by_right_floats(false); } - // Our inline-size was set to the inline-size of the containing block by the flow's parent. Now compute - // the real value. - let containing_block_inline_size = self.base.position.size.inline; + // Our inline-size was set to the inline-size of the containing block by the flow's parent. + // Now compute the real value. + let containing_block_inline_size = self.base.block_container_inline_size; self.compute_used_inline_size(layout_context, containing_block_inline_size); if self.is_float() { self.float.as_mut().unwrap().containing_inline_size = containing_block_inline_size; @@ -1664,7 +1677,9 @@ impl Flow for BlockFlow { self.base.debug_id()); // Assign block-size for fragment if it is an image fragment. - self.fragment.assign_replaced_block_size_if_necessary(); + let containing_block_block_size = + self.base.block_container_explicit_block_size.unwrap_or(Au(0)); + self.fragment.assign_replaced_block_size_if_necessary(containing_block_block_size); self.base.position.size.block = self.fragment.border_box.size.block; } else if self.is_root() || self.is_float() { // Root element margins should never be collapsed according to CSS § 8.3.1. @@ -1742,7 +1757,7 @@ impl Flow for BlockFlow { } fn mark_as_root(&mut self) { - self.is_root = true + self.flags.insert(IsRoot) } /// Return true if store overflow is delayed for this flow. @@ -1753,7 +1768,7 @@ impl Flow for BlockFlow { } fn is_root(&self) -> bool { - self.is_root + self.flags.contains(IsRoot) } fn is_float(&self) -> bool { @@ -2017,7 +2032,8 @@ pub trait ISizeAndMarginsComputer { let containing_block_inline_size = self.containing_block_inline_size( block, - parent_flow_inline_size, ctx); + parent_flow_inline_size, + ctx); let mut solution = self.solve_inline_size_constraints(block, &input); @@ -2528,5 +2544,5 @@ fn propagate_column_inline_sizes_to_child(kid: &mut Flow, let kid_base = flow::mut_base(kid); kid_base.position.start.i = *inline_start_margin_edge; - kid_base.position.size.inline = inline_size; + kid_base.block_container_inline_size = inline_size; } diff --git a/components/layout/flow.rs b/components/layout/flow.rs index aeda813c1b3..a8711f62965 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -184,10 +184,10 @@ pub trait Flow: fmt::Show + ToString + Sync { /// Pass 1 of reflow: computes minimum and preferred inline-sizes. /// - /// Recursively (bottom-up) determine the flow's minimum and preferred inline-sizes. When called on - /// this flow, all child flows have had their minimum and preferred inline-sizes set. This function - /// must decide minimum/preferred inline-sizes based on its children's inline-sizes and the dimensions of - /// any boxes it is responsible for flowing. + /// Recursively (bottom-up) determine the flow's minimum and preferred inline-sizes. When + /// called on this flow, all child flows have had their minimum and preferred inline-sizes set. + /// This function must decide minimum/preferred inline-sizes based on its children's inline- + /// sizes and the dimensions of any boxes it is responsible for flowing. fn bubble_inline_sizes(&mut self, _ctx: &LayoutContext) { fail!("bubble_inline_sizes not yet implemented") } @@ -203,10 +203,11 @@ pub trait Flow: fmt::Show + ToString + Sync { } /// Assigns block-sizes in-order; or, if this is a float, places the float. The default - /// implementation simply assigns block-sizes if this flow is impacted by floats. Returns true if - /// this child was impacted by floats or false otherwise. - fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self, layout_context: &'a LayoutContext<'a>) - -> bool { + /// implementation simply assigns block-sizes if this flow is impacted by floats. Returns true + /// if this child was impacted by floats or false otherwise. + fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self, + layout_context: &'a LayoutContext<'a>) + -> bool { let impacted = base(&*self).flags.impacted_by_floats(); if impacted { self.assign_block_size(layout_context); @@ -745,6 +746,10 @@ pub struct BaseFlow { /// containing block. This is in tree order. This includes any direct children. pub abs_descendants: AbsDescendants, + /// The inline-size of the block container of this flow. Used for computing percentage and + /// automatic values for `width`. + pub block_container_inline_size: Au, + /// The block-size of the block container of this flow, if it is an explicit size (does not /// depend on content heights). Used for computing percentage values for `height`. pub block_container_explicit_block_size: Option, @@ -780,7 +785,8 @@ pub struct BaseFlow { impl fmt::Show for BaseFlow { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, - "CC {}, ADC {}, CADC {}", + "@ {}, CC {}, ADC {}, CADC {}", + self.position, self.parallel.children_count.load(SeqCst), self.abs_descendants.len(), self.parallel.children_and_absolute_descendant_count.load(SeqCst)) @@ -837,8 +843,9 @@ impl BaseFlow { collapsible_margins: CollapsibleMargins::new(), abs_position: Zero::zero(), abs_descendants: Descendants::new(), - absolute_static_i_offset: Au::new(0), - fixed_static_i_offset: Au::new(0), + absolute_static_i_offset: Au(0), + fixed_static_i_offset: Au(0), + block_container_inline_size: Au(0), block_container_explicit_block_size: None, absolute_cb: ContainingBlockLink::new(), display_list: DisplayList::new(), diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 835d5037b43..2ea2b5fc910 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -215,8 +215,8 @@ pub struct ImageFragmentInfo { impl ImageFragmentInfo { /// Creates a new image fragment from the given URL and local image cache. /// - /// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little sense to - /// me. + /// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little + /// sense to me. pub fn new(node: &ThreadSafeLayoutNode, image_url: Url, local_image_cache: Arc>>) @@ -1041,7 +1041,9 @@ impl Fragment { StackingLevel::from_background_and_border_level(background_and_border_level); // Add a pseudo-display item for content box queries. This is a very bogus thing to do. - let base_display_item = box BaseDisplayItem::new(absolute_fragment_bounds, self.node, level); + let base_display_item = box BaseDisplayItem::new(absolute_fragment_bounds, + self.node, + level); display_list.push(PseudoDisplayItemClass(base_display_item)); // Add the background to the list, if applicable. @@ -1061,11 +1063,12 @@ impl Fragment { match self.specific { ScannedTextFragment(_) => {}, _ => { - self.build_display_list_for_background_if_applicable(&*self.style, - display_list, - layout_context, - level, - &absolute_fragment_bounds); + self.build_display_list_for_background_if_applicable( + &*self.style, + display_list, + layout_context, + level, + &absolute_fragment_bounds); } } @@ -1075,10 +1078,11 @@ impl Fragment { match self.inline_context { Some(ref 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); + self.build_display_list_for_borders_if_applicable( + &**style, + display_list, + &absolute_fragment_bounds, + level); } } None => {} @@ -1187,42 +1191,37 @@ impl Fragment { // should have a real `SERVO_DEBUG` system. debug!("{:?}", self.build_debug_borders_around_fragment(display_list, flow_origin)) } - ImageFragment(_) => { - match self.specific { - ImageFragment(ref mut image_fragment) => { - let image_ref = &mut image_fragment.image; - match image_ref.get_image(self.node.to_untrusted_node_address()) { - Some(image) => { - debug!("(building display list) building image fragment"); + ImageFragment(ref mut image_fragment) => { + let image_ref = &mut image_fragment.image; + match image_ref.get_image(self.node.to_untrusted_node_address()) { + Some(image) => { + debug!("(building display list) building image fragment"); - // Place the image into the display list. - let image_display_item = box ImageDisplayItem { - base: BaseDisplayItem::new(absolute_content_box, - self.node, - ContentStackingLevel), - image: image.clone(), - stretch_size: absolute_content_box.size, - }; - accumulator.push(display_list, - ImageDisplayItemClass(image_display_item)) - } - None => { - // No image data at all? Do nothing. - // - // TODO: Add some kind of placeholder image. - debug!("(building display list) no image :("); - } - } + // Place the image into the display list. + let image_display_item = box ImageDisplayItem { + base: BaseDisplayItem::new(absolute_content_box, + self.node, + ContentStackingLevel), + image: image.clone(), + stretch_size: absolute_content_box.size, + }; + + accumulator.push(display_list, ImageDisplayItemClass(image_display_item)) + } + None => { + // No image data at all? Do nothing. + // + // TODO: Add some kind of placeholder image. + debug!("(building display list) no image :("); } - _ => fail!("shouldn't get here"), } - - // FIXME(pcwalton): This is a bit of an abuse of the logging - // infrastructure. We should have a real `SERVO_DEBUG` system. - debug!("{:?}", self.build_debug_borders_around_fragment(display_list, flow_origin)) } } + // FIXME(pcwalton): This is a bit of an abuse of the logging + // infrastructure. We should have a real `SERVO_DEBUG` system. + debug!("{:?}", self.build_debug_borders_around_fragment(display_list, flow_origin)) + // If this is an iframe, then send its position and size up to the constellation. // // FIXME(pcwalton): Doing this during display list construction seems potentially @@ -1538,7 +1537,7 @@ impl Fragment { match self.specific { InlineAbsoluteHypotheticalFragment(ref mut info) => { let block_flow = info.flow_ref.get_mut().as_block(); - block_flow.base.position.size.inline = + block_flow.base.block_container_inline_size = block_flow.base.intrinsic_inline_sizes.preferred_inline_size + block_flow.base.intrinsic_inline_sizes.surround_inline_size; @@ -1549,18 +1548,19 @@ impl Fragment { let block_flow = info.flow_ref.get_mut().as_block(); self.border_box.size.inline = block_flow.base.intrinsic_inline_sizes.preferred_inline_size + block_flow.base.intrinsic_inline_sizes.surround_inline_size; - block_flow.base.position.size.inline = self.border_box.size.inline; + block_flow.base.block_container_inline_size = self.border_box.size.inline; } ScannedTextFragment(_) => { - // Scanned text fragments will have already had their content inline-sizes assigned by this - // point. + // Scanned text fragments will have already had their content inline-sizes assigned + // by this point. self.border_box.size.inline = self.border_box.size.inline + noncontent_inline_size } ImageFragment(ref mut image_fragment_info) => { // TODO(ksh8281): compute border,margin - let inline_size = ImageFragmentInfo::style_length(style_inline_size, - image_fragment_info.dom_inline_size, - container_inline_size); + let inline_size = ImageFragmentInfo::style_length( + style_inline_size, + image_fragment_info.dom_inline_size, + container_inline_size); let inline_size = match inline_size { Auto => { @@ -1573,18 +1573,20 @@ impl Fragment { let ratio = intrinsic_width.to_f32().unwrap() / intrinsic_height.to_f32().unwrap(); - let specified_height = ImageFragmentInfo::style_length(style_block_size, - image_fragment_info.dom_block_size, - Au(0)); + let specified_height = ImageFragmentInfo::style_length( + style_block_size, + image_fragment_info.dom_block_size, + Au(0)); let specified_height = match specified_height { Auto => intrinsic_height, Specified(h) => h, }; - let specified_height = ImageFragmentInfo::clamp_size(specified_height, - style_min_block_size, - style_max_block_size, - Au(0)); - Au::new((specified_height.to_f32().unwrap() * ratio) as i32) + let specified_height = ImageFragmentInfo::clamp_size( + specified_height, + style_min_block_size, + style_max_block_size, + Au(0)); + Au((specified_height.to_f32().unwrap() * ratio) as i32) } }, Specified(w) => w, @@ -1606,7 +1608,7 @@ impl Fragment { /// been assigned first. /// /// Ideally, this should follow CSS 2.1 § 10.6.2. - pub fn assign_replaced_block_size_if_necessary(&mut self) { + pub fn assign_replaced_block_size_if_necessary(&mut self, containing_block_block_size: Au) { match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableRowFragment | TableWrapperFragment | InputFragment(_) => return, @@ -1627,17 +1629,17 @@ impl Fragment { ImageFragment(ref mut image_fragment_info) => { // TODO(ksh8281): compute border,margin,padding let inline_size = image_fragment_info.computed_inline_size(); - // FIXME(ksh8281): we shouldn't assign block-size this way - // we don't know about size of parent's block-size - let block_size = ImageFragmentInfo::style_length(style_block_size, - image_fragment_info.dom_block_size, - Au(0)); + let block_size = ImageFragmentInfo::style_length( + style_block_size, + image_fragment_info.dom_block_size, + containing_block_block_size); let block_size = match block_size { Auto => { let scale = image_fragment_info.image_inline_size().to_f32().unwrap() / inline_size.to_f32().unwrap(); - Au::new((image_fragment_info.image_block_size().to_f32().unwrap() / scale) as i32) + Au((image_fragment_info.image_block_size().to_f32().unwrap() / scale) + as i32) }, Specified(h) => { h @@ -1652,8 +1654,8 @@ impl Fragment { self.border_box.size.block = block_size + noncontent_block_size } ScannedTextFragment(_) => { - // Scanned text fragments' content block-sizes are calculated by the text run scanner - // during flow construction. + // Scanned text fragments' content block-sizes are calculated by the text run + // scanner during flow construction. self.border_box.size.block = self.border_box.size.block + noncontent_block_size } InlineBlockFragment(ref mut info) => { diff --git a/components/layout/inline.rs b/components/layout/inline.rs index f6bcc0a3394..130b2ac9eae 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -775,6 +775,10 @@ impl InlineFlow { pub fn build_display_list_inline(&mut self, layout_context: &LayoutContext) { let size = self.base.position.size.to_physical(self.base.writing_mode); if !Rect(self.base.abs_position, size).intersects(&layout_context.shared.dirty) { + println!("inline block (abs pos {}, size {}) didn't intersect \ + dirty rect owo", + self.base.abs_position, + size); return } @@ -1030,10 +1034,13 @@ impl Flow for InlineFlow { // Initialize content fragment inline-sizes if they haven't been initialized already. // - // TODO: Combine this with `LineBreaker`'s walk in the fragment list, or put this into `Fragment`. + // TODO: Combine this with `LineBreaker`'s walk in the fragment list, or put this into + // `Fragment`. debug!("InlineFlow::assign_inline_sizes: floats in: {:?}", self.base.floats); + self.base.position.size.inline = self.base.block_container_inline_size; + { let inline_size = self.base.position.size.inline; let this = &mut *self; @@ -1070,8 +1077,11 @@ impl Flow for InlineFlow { debug!("assign_block_size_inline: floats in: {:?}", self.base.floats); // assign block-size for inline fragments + let containing_block_block_size = + self.base.block_container_explicit_block_size.unwrap_or(Au(0)); for fragment in self.fragments.fragments.iter_mut() { - fragment.assign_replaced_block_size_if_necessary(); + fragment.assign_replaced_block_size_if_necessary( + containing_block_block_size); } let scanner_floats = self.base.floats.clone(); diff --git a/components/layout/table.rs b/components/layout/table.rs index 6be3d900020..979667d4ba1 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -256,7 +256,7 @@ impl Flow for TableFlow { debug!("assign_inline_sizes({}): assigning inline_size for flow", "table"); // The position was set to the containing block by the flow's parent. - let containing_block_inline_size = self.block_flow.base.position.size.inline; + let containing_block_inline_size = self.block_flow.base.block_container_inline_size; let mut num_unspecified_inline_sizes = 0; let mut total_column_inline_size = Au::new(0); diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 6aeb6b8f8e9..0a3300256a3 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -100,7 +100,7 @@ impl Flow for TableCellFlow { debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_cell"); // The position was set to the column inline-size by the parent flow, table row flow. - let containing_block_inline_size = self.block_flow.base.position.size.inline; + let containing_block_inline_size = self.block_flow.base.block_container_inline_size; let inline_size_computer = InternalTable; inline_size_computer.compute_used_inline_size(&mut self.block_flow, ctx, containing_block_inline_size); diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index 23d392dd2da..55cc67632fa 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -209,7 +209,7 @@ impl Flow for TableRowFlow { debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_row"); // The position was set to the containing block by the flow's parent. - let containing_block_inline_size = self.block_flow.base.position.size.inline; + let containing_block_inline_size = self.block_flow.base.block_container_inline_size; // FIXME: In case of border-collapse: collapse, inline-start_content_edge should be border-inline-start let inline_start_content_edge = Au::new(0); diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs index c1e56bc5219..1b8cabf63e4 100644 --- a/components/layout/table_rowgroup.rs +++ b/components/layout/table_rowgroup.rs @@ -190,7 +190,7 @@ impl Flow for TableRowGroupFlow { debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_rowgroup"); // The position was set to the containing block by the flow's parent. - let containing_block_inline_size = self.block_flow.base.position.size.inline; + let containing_block_inline_size = self.block_flow.base.block_container_inline_size; // FIXME: In case of border-collapse: collapse, inline-start_content_edge should be // the border width on the inline-start side. let inline_start_content_edge = Au::new(0); diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index d4d6486f425..ca05f6e1d53 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -288,7 +288,7 @@ impl Flow for TableWrapperFlow { // Our inline-size was set to the inline-size of the containing block by the flow's parent. // Now compute the real value. - let containing_block_inline_size = self.block_flow.base.position.size.inline; + let containing_block_inline_size = self.block_flow.base.block_container_inline_size; if self.is_float() { self.block_flow.float.as_mut().unwrap().containing_inline_size = containing_block_inline_size;