layout: Change RenderBox to an enum and shorten its name in

preparation for removing its `@`-ness.

Also removes a few text copies that were taking place.

This sure does remove a lot of code!
This commit is contained in:
Patrick Walton 2013-12-02 21:45:25 -08:00
parent 2c4714e803
commit 4fda26f76e
8 changed files with 679 additions and 957 deletions

View file

@ -2,9 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! CSS block layout.
//! CSS block formatting contexts.
use layout::box::{RenderBox, RenderBoxUtils};
use layout::box::Box;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{BlockFlowClass, FlowClass, Flow, FlowData, ImmutableFlowUtils};
@ -13,13 +13,12 @@ use layout::model::{MaybeAuto, Specified, Auto, specified_or_none, specified};
use layout::float_context::{FloatContext, PlacementInfo, Invalid, FloatType};
use std::cell::Cell;
use geom::point::Point2D;
use geom::size::Size2D;
use geom::rect::Rect;
use geom::{Point2D, Rect, SideOffsets2D, Size2D};
use gfx::display_list::DisplayList;
use servo_util::geometry::{Au, to_frac_px};
use servo_util::geometry;
/// Information specific to floated blocks.
pub struct FloatedBlockInfo {
containing_width: Au,
@ -48,12 +47,13 @@ impl FloatedBlockInfo {
}
}
/// A block formatting context.
pub struct BlockFlow {
/// Data common to all flows.
base: FlowData,
/// The associated render box.
box: Option<@RenderBox>,
/// The associated box.
box: Option<@Box>,
/// Whether this block flow is the root flow.
is_root: bool,
@ -72,7 +72,7 @@ impl BlockFlow {
}
}
pub fn from_box(base: FlowData, box: @RenderBox) -> BlockFlow {
pub fn from_box(base: FlowData, box: @Box) -> BlockFlow {
BlockFlow {
base: base,
box: Some(box),
@ -81,7 +81,7 @@ impl BlockFlow {
}
}
pub fn float_from_box(base: FlowData, float_type: FloatType, box: @RenderBox) -> BlockFlow {
pub fn float_from_box(base: FlowData, float_type: FloatType, box: @Box) -> BlockFlow {
BlockFlow {
base: base,
box: Some(box),
@ -172,9 +172,9 @@ impl BlockFlow {
(width_Au, left_margin_Au, right_margin_Au)
}
fn compute_block_margins(&self, box: @RenderBox, remaining_width: Au, available_width: Au) -> (Au, Au, Au) {
let base = box.base();
let style = base.style();
fn compute_block_margins(&self, box: @Box, remaining_width: Au, available_width: Au)
-> (Au, Au, Au) {
let style = box.style();
let (width, maybe_margin_left, maybe_margin_right) =
(MaybeAuto::from_style(style.Box.width, remaining_width),
@ -215,8 +215,8 @@ impl BlockFlow {
return (width, margin_left, margin_right);
}
fn compute_float_margins(&self, box: @RenderBox, remaining_width: Au) -> (Au, Au, Au) {
let style = box.base().style();
fn compute_float_margins(&self, box: @Box, remaining_width: Au) -> (Au, Au, Au) {
let style = box.style();
let margin_left = MaybeAuto::from_style(style.Margin.margin_left,
remaining_width).specified_or_zero();
let margin_right = MaybeAuto::from_style(style.Margin.margin_right,
@ -241,18 +241,19 @@ impl BlockFlow {
let mut float_ctx = Invalid;
for &box in self.box.iter() {
let base = box.base();
clearance = match base.clear() {
clearance = match box.clear() {
None => Au::new(0),
Some(clear) => {
self.base.floats_in.clearance(clear)
}
};
top_offset = clearance + base.margin.top + base.border.top + base.padding.top;
top_offset = clearance + box.margin.get().top + box.border.get().top +
box.padding.get().top;
cur_y = cur_y + top_offset;
bottom_offset = base.margin.bottom + base.border.bottom + base.padding.bottom;
left_offset = base.offset();
bottom_offset = box.margin.get().bottom + box.border.get().bottom +
box.padding.get().bottom;
left_offset = box.offset();
}
if inorder {
@ -279,16 +280,16 @@ impl BlockFlow {
let mut bottom_margin_collapsible = false;
let mut first_in_flow = true;
for &box in self.box.iter() {
let base = box.base();
if !self.is_root && base.border.top == Au::new(0) && base.padding.top == Au::new(0) {
collapsible = base.margin.top;
if !self.is_root && box.border.get().top == Au(0) && box.padding.get().top == Au(0) {
collapsible = box.margin.get().top;
top_margin_collapsible = true;
}
if !self.is_root && base.border.bottom == Au::new(0) && base.padding.bottom == Au::new(0) {
if !self.is_root && box.border.get().bottom == Au(0) &&
box.padding.get().bottom == Au(0) {
bottom_margin_collapsible = true;
}
margin_top = base.margin.top;
margin_bottom = base.margin.bottom;
margin_top = box.margin.get().top;
margin_bottom = box.margin.get().bottom;
}
for kid in self.base.child_iter() {
@ -328,8 +329,7 @@ impl BlockFlow {
};
for &box in self.box.iter() {
let base = box.base();
let style = base.style();
let style = box.style();
height = match MaybeAuto::from_style(style.Box.height, Au::new(0)) {
Auto => height,
Specified(value) => value
@ -338,22 +338,23 @@ impl BlockFlow {
let mut noncontent_height = Au::new(0);
for box in self.box.iter() {
let base = box.mut_base();
let mut position_ref = base.position.mutate();
let position = &mut position_ref.ptr;
let mut position = box.position.get();
let mut margin = box.margin.get();
// The associated box is the border box of this flow.
base.margin.top = margin_top;
base.margin.bottom = margin_bottom;
margin.top = margin_top;
margin.bottom = margin_bottom;
position.origin.y = clearance + base.margin.top;
position.origin.y = clearance + margin.top;
noncontent_height = base.padding.top + base.padding.bottom + base.border.top +
base.border.bottom;
noncontent_height = box.padding.get().top + box.padding.get().bottom +
box.border.get().top + box.border.get().bottom;
position.size.height = height + noncontent_height;
noncontent_height = noncontent_height + clearance + base.margin.top +
base.margin.bottom;
noncontent_height = noncontent_height + clearance + margin.top + margin.bottom;
box.position.set(position);
box.margin.set(margin);
}
self.base.position.size.height = height + noncontent_height;
@ -376,18 +377,18 @@ impl BlockFlow {
let mut margin_height = Au(0);
for box in self.box.iter() {
let base = box.base();
height = base.position.borrow().ptr.size.height;
clearance = match base.clear() {
height = box.position.get().size.height;
clearance = match box.clear() {
None => Au(0),
Some(clear) => self.base.floats_in.clearance(clear),
};
let noncontent_width = base.padding.left + base.padding.right + base.border.left +
base.border.right;
let noncontent_width = box.padding.get().left + box.padding.get().right +
box.border.get().left + box.border.get().right;
full_noncontent_width = noncontent_width + base.margin.left + base.margin.right;
margin_height = base.margin.top + base.margin.bottom;
full_noncontent_width = noncontent_width + box.margin.get().left +
box.margin.get().right;
margin_height = box.margin.get().top + box.margin.get().bottom;
}
let info = PlacementInfo {
@ -419,8 +420,7 @@ impl BlockFlow {
let mut top_offset = Au(0);
for &box in self.box.iter() {
let base = box.base();
top_offset = base.margin.top + base.border.top + base.padding.top;
top_offset = box.margin.get().top + box.border.get().top + box.padding.get().top;
cur_y = cur_y + top_offset;
}
@ -434,24 +434,23 @@ impl BlockFlow {
let mut noncontent_height;
let box = self.box.as_ref().unwrap();
let base = box.base();
let mut position_ref = base.position.mutate();
let position = &mut position_ref.ptr;
let mut position = box.position.get();
// The associated box is the border box of this flow.
position.origin.y = base.margin.top;
position.origin.y = box.margin.get().top;
noncontent_height = base.padding.top + base.padding.bottom + base.border.top +
base.border.bottom;
noncontent_height = box.padding.get().top + box.padding.get().bottom +
box.border.get().top + box.border.get().bottom;
//TODO(eatkinson): compute heights properly using the 'height' property.
let height_prop = MaybeAuto::from_style(base.style().Box.height,
let height_prop = MaybeAuto::from_style(box.style().Box.height,
Au::new(0)).specified_or_zero();
height = geometry::max(height, height_prop) + noncontent_height;
debug!("assign_height_float -- height: {}", height);
position.size.height = height;
box.position.set(position);
}
pub fn build_display_list_block<E:ExtraDisplayListData>(
@ -466,18 +465,16 @@ impl BlockFlow {
if self.base.node.is_iframe_element() {
let x = self.base.abs_position.x + do self.box.map_default(Au::new(0)) |box| {
let base = box.base();
base.margin.left + base.border.left + base.padding.left
box.margin.get().left + box.border.get().left + box.padding.get().left
};
let y = self.base.abs_position.y + do self.box.map_default(Au::new(0)) |box| {
let base = box.base();
base.margin.top + base.border.top + base.padding.top
box.margin.get().top + box.border.get().top + box.padding.get().top
};
let w = self.base.position.size.width - do self.box.map_default(Au::new(0)) |box| {
box.base().noncontent_width()
box.noncontent_width()
};
let h = self.base.position.size.height - do self.box.map_default(Au::new(0)) |box| {
box.base().noncontent_height()
box.noncontent_height()
};
do self.base.node.with_mut_iframe_element |iframe_element| {
iframe_element.size.get_mut_ref().set_rect(Rect(Point2D(to_frac_px(x) as f32,
@ -587,7 +584,7 @@ impl Flow for BlockFlow {
for box in self.box.iter() {
{
// Can compute border width here since it doesn't depend on anything.
box.mut_base().compute_borders(box.base().style());
box.compute_borders(box.style())
}
let (this_minimum_width, this_preferred_width) = box.minimum_and_preferred_widths();
@ -631,16 +628,13 @@ impl Flow for BlockFlow {
}
for &box in self.box.iter() {
let base = box.base();
let mut_base = box.mut_base();
let style = base.style();
let mut_position = &mut base.position.mutate().ptr;
let style = box.style();
// Can compute padding here since we know containing block width.
mut_base.compute_padding(style, remaining_width);
box.compute_padding(style, remaining_width);
// Margins are 0 right now so base.noncontent_width() is just borders + padding.
let available_width = remaining_width - base.noncontent_width();
let available_width = remaining_width - box.noncontent_width();
// Top and bottom margins for blocks are 0 if auto.
let margin_top = MaybeAuto::from_style(style.Margin.margin_top,
@ -654,20 +648,20 @@ impl Flow for BlockFlow {
self.compute_block_margins(box, remaining_width, available_width)
};
mut_base.margin.top = margin_top;
mut_base.margin.right = margin_right;
mut_base.margin.bottom = margin_bottom;
mut_base.margin.left = margin_left;
box.margin.set(SideOffsets2D::new(margin_top,
margin_right,
margin_bottom,
margin_left));
x_offset = base.offset();
x_offset = box.offset();
remaining_width = width;
//The associated box is the border box of this flow
mut_position.origin.x = base.margin.left;
let padding_and_borders = base.padding.left + base.padding.right +
base.border.left + base.border.right;
mut_position.size.width = remaining_width + padding_and_borders;
// The associated box is the border box of this flow.
let position_ref = box.position.mutate();
position_ref.ptr.origin.x = box.margin.get().left;
let padding_and_borders = box.padding.get().left + box.padding.get().right +
box.border.get().left + box.border.get().right;
position_ref.ptr.size.width = remaining_width + padding_and_borders;
}
if self.is_float() {
@ -734,25 +728,23 @@ impl Flow for BlockFlow {
}
for &box in self.box.iter() {
let base = box.base();
// The top margin collapses with its first in-flow block-level child's
// top margin if the parent has no top border, no top padding.
if *first_in_flow && top_margin_collapsible {
// If top-margin of parent is less than top-margin of its first child,
// the parent box goes down until its top is aligned with the child.
if *margin_top < base.margin.top {
if *margin_top < box.margin.get().top {
// TODO: The position of child floats should be updated and this
// would influence clearance as well. See #725
let extra_margin = base.margin.top - *margin_top;
let extra_margin = box.margin.get().top - *margin_top;
*top_offset = *top_offset + extra_margin;
*margin_top = base.margin.top;
*margin_top = box.margin.get().top;
}
}
// The bottom margin of an in-flow block-level element collapses
// with the top margin of its next in-flow block-level sibling.
*collapsing = geometry::min(base.margin.top, *collapsible);
*collapsible = base.margin.bottom;
*collapsing = geometry::min(box.margin.get().top, *collapsible);
*collapsible = box.margin.get().bottom;
}
*first_in_flow = false;

File diff suppressed because it is too large Load diff

View file

@ -7,8 +7,8 @@
//! Each step of the traversal considers the node and existing flow, if there is one. If a node is
//! not dirty and an existing flow exists, then the traversal reuses that flow. Otherwise, it
//! proceeds to construct either a flow or a `ConstructionItem`. A construction item is a piece of
//! intermediate data that goes with a DOM node and hasn't found its "home" yet—maybe it's a render
//! box, maybe it's an absolute or fixed position thing that hasn't found its containing block yet.
//! intermediate data that goes with a DOM node and hasn't found its "home" yet—maybe it's a box,
//! maybe it's an absolute or fixed position thing that hasn't found its containing block yet.
//! Construction items bubble up the tree from children to parents until they find their homes.
//!
//! TODO(pcwalton): There is no incremental reflow yet. This scheme requires that nodes either have
@ -22,8 +22,7 @@
use css::node_style::StyledNode;
use layout::block::BlockFlow;
use layout::box::{GenericRenderBox, ImageRenderBox, RenderBox, RenderBoxBase};
use layout::box::{UnscannedTextRenderBox};
use layout::box::{Box, GenericBox, ImageBox, ImageBoxInfo, UnscannedTextBox, UnscannedTextBoxInfo};
use layout::context::LayoutContext;
use layout::float_context::FloatType;
use layout::flow::{Flow, FlowData, MutableFlowUtils};
@ -70,8 +69,8 @@ struct InlineBoxesConstructionResult {
/// TODO(pcwalton): Small vector optimization.
splits: Option<~[InlineBlockSplit]>,
/// Any render boxes that succeed the {ib} splits.
boxes: ~[@RenderBox],
/// Any boxes that succeed the {ib} splits.
boxes: ~[@Box],
}
/// Represents an {ib} split that has not yet found the containing block that it belongs to. This
@ -97,10 +96,10 @@ struct InlineBoxesConstructionResult {
/// C
/// ])
struct InlineBlockSplit {
/// The inline render boxes that precede the flow.
/// The inline boxes that precede the flow.
///
/// TODO(pcwalton): Small vector optimization.
predecessor_boxes: ~[@RenderBox],
predecessor_boxes: ~[@Box],
/// The flow that caused this {ib} split.
flow: ~Flow:,
@ -180,11 +179,6 @@ pub struct FlowConstructor<'self> {
///
/// FIXME(pcwalton): This is going to have to be atomic; can't we do something better?
next_flow_id: Slot<int>,
/// The next box ID to assign.
///
/// FIXME(pcwalton): This is going to have to be atomic; can't we do something better?
next_box_id: Slot<int>,
}
impl<'self> FlowConstructor<'self> {
@ -193,7 +187,6 @@ impl<'self> FlowConstructor<'self> {
FlowConstructor {
layout_context: layout_context,
next_flow_id: Slot::init(0),
next_box_id: Slot::init(0),
}
}
@ -204,40 +197,37 @@ impl<'self> FlowConstructor<'self> {
id
}
/// Returns the next render box ID and bumps the internal counter.
fn next_box_id(&self) -> int {
let id = self.next_box_id.get();
self.next_box_id.set(id + 1);
id
}
/// Builds a `RenderBox` for the given image. This is out of line to guide inlining.
fn build_box_for_image(&self, base: RenderBoxBase, node: AbstractNode<LayoutView>)
-> @RenderBox {
/// Builds the `ImageBoxInfo` for the given image. This is out of line to guide inlining.
fn build_box_info_for_image(&self, node: AbstractNode<LayoutView>) -> Option<ImageBoxInfo> {
// FIXME(pcwalton): Don't copy URLs.
let url = node.with_imm_image_element(|image_element| {
image_element.image.as_ref().map(|url| (*url).clone())
});
match url {
None => @GenericRenderBox::new(base) as @RenderBox,
None => None,
Some(url) => {
// FIXME(pcwalton): The fact that image render boxes store the cache in the
// box makes little sense to me.
@ImageRenderBox::new(base, url, self.layout_context.image_cache) as @RenderBox
// FIXME(pcwalton): The fact that image boxes store the cache within them makes
// little sense to me.
Some(ImageBoxInfo::new(url, self.layout_context.image_cache))
}
}
}
/// Builds a `RenderBox` for the given node.
fn build_box_for_node(&self, node: AbstractNode<LayoutView>) -> @RenderBox {
let base = RenderBoxBase::new(node, self.next_box_id());
match node.type_id() {
ElementNodeTypeId(HTMLImageElementTypeId) => self.build_box_for_image(base, node),
TextNodeTypeId => @UnscannedTextRenderBox::new(base) as @RenderBox,
_ => @GenericRenderBox::new(base) as @RenderBox,
/// Builds a `Box` for the given node.
fn build_box_for_node(&self, node: AbstractNode<LayoutView>) -> @Box {
let specific = match node.type_id() {
ElementNodeTypeId(HTMLImageElementTypeId) => {
match self.build_box_info_for_image(node) {
None => GenericBox,
Some(image_box_info) => ImageBox(image_box_info),
}
}
TextNodeTypeId => UnscannedTextBox(UnscannedTextBoxInfo::new(&node)),
_ => GenericBox,
};
@Box::new(node, specific)
}
/// Creates an inline flow from a set of inline boxes and adds it as a child of the given flow.
///
@ -245,7 +235,7 @@ impl<'self> FlowConstructor<'self> {
/// otherwise.
#[inline(always)]
fn flush_inline_boxes_to_flow(&self,
boxes: ~[@RenderBox],
boxes: ~[@Box],
flow: &mut ~Flow:,
node: AbstractNode<LayoutView>) {
if boxes.len() > 0 {
@ -259,7 +249,7 @@ impl<'self> FlowConstructor<'self> {
/// Creates an inline flow from a set of inline boxes, if present, and adds it as a child of
/// the given flow.
fn flush_inline_boxes_to_flow_if_necessary(&self,
opt_boxes: &mut Option<~[@RenderBox]>,
opt_boxes: &mut Option<~[@Box]>,
flow: &mut ~Flow:,
node: AbstractNode<LayoutView>) {
let opt_boxes = util::replace(opt_boxes, None);
@ -378,13 +368,13 @@ impl<'self> FlowConstructor<'self> {
let mut opt_inline_block_splits = None;
let mut opt_box_accumulator = None;
// Concatenate all the render boxes of our kids, creating {ib} splits as necessary.
// Concatenate all the boxes of our kids, creating {ib} splits as necessary.
for kid in node.children() {
match kid.swap_out_construction_result() {
NoConstructionResult => {}
FlowConstructionResult(flow) => {
// {ib} split. Flush the accumulator to our new split and make a new
// accumulator to hold any subsequent `RenderBox`es we come across.
// accumulator to hold any subsequent boxes we come across.
let split = InlineBlockSplit {
predecessor_boxes: util::replace(&mut opt_box_accumulator, None).to_vec(),
flow: flow,
@ -438,7 +428,7 @@ impl<'self> FlowConstructor<'self> {
}
/// Creates an `InlineBoxesConstructionResult` for replaced content. Replaced content doesn't
/// render its children, so this just nukes a child's boxes and creates a `RenderBox`.
/// render its children, so this just nukes a child's boxes and creates a `Box`.
fn build_boxes_for_replaced_inline_content(&self, node: AbstractNode<LayoutView>)
-> ConstructionResult {
for kid in node.children() {
@ -454,7 +444,7 @@ impl<'self> FlowConstructor<'self> {
ConstructionItemConstructionResult(construction_item)
}
/// Builds one or more render boxes for a node with `display: inline`. This yields an
/// Builds one or more boxes for a node with `display: inline`. This yields an
/// `InlineBoxesConstructionResult`.
fn build_boxes_for_inline(&self, node: AbstractNode<LayoutView>) -> ConstructionResult {
// Is this node replaced content?
@ -462,8 +452,7 @@ impl<'self> FlowConstructor<'self> {
// Go to a path that concatenates our kids' boxes.
self.build_boxes_for_nonreplaced_inline_content(node)
} else {
// Otherwise, just nuke our kids' boxes, create our `RenderBox` if any, and be done
// with it.
// Otherwise, just nuke our kids' boxes, create our box if any, and be done with it.
self.build_boxes_for_replaced_inline_content(node)
}
}
@ -494,7 +483,7 @@ impl<'self> PostorderNodeTraversal for FlowConstructor<'self> {
}
}
// Inline items contribute inline render box construction results.
// Inline items contribute inline box construction results.
(display::inline, float::none) => {
let construction_result = self.build_boxes_for_inline(node);
node.set_flow_construction_result(construction_result)
@ -575,7 +564,7 @@ impl NodeUtils for AbstractNode<LayoutView> {
}
/// Strips ignorable whitespace from the start of a list of boxes.
fn strip_ignorable_whitespace_from_start(opt_boxes: &mut Option<~[@RenderBox]>) {
fn strip_ignorable_whitespace_from_start(opt_boxes: &mut Option<~[@Box]>) {
match util::replace(opt_boxes, None) {
None => return,
Some(boxes) => {
@ -597,7 +586,7 @@ fn strip_ignorable_whitespace_from_start(opt_boxes: &mut Option<~[@RenderBox]>)
}
/// Strips ignorable whitespace from the end of a list of boxes.
fn strip_ignorable_whitespace_from_end(opt_boxes: &mut Option<~[@RenderBox]>) {
fn strip_ignorable_whitespace_from_end(opt_boxes: &mut Option<~[@Box]>) {
match *opt_boxes {
None => {}
Some(ref mut boxes) => {

View file

@ -2,9 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Constructs display lists from render boxes.
//! Constructs display lists from boxes.
use layout::box::{RenderBox, RenderBoxUtils};
use layout::box::Box;
use layout::context::LayoutContext;
use std::cast::transmute;
use script::dom::node::AbstractNode;
@ -16,27 +16,27 @@ use style;
/// that nodes in this view shoud not really be touched. The idea is to
/// store the nodes in the display list and have layout transmute them.
pub trait ExtraDisplayListData {
fn new(box: &@RenderBox) -> Self;
fn new(box: &@Box) -> Self;
}
pub type Nothing = ();
impl ExtraDisplayListData for AbstractNode<()> {
fn new(box: &@RenderBox) -> AbstractNode<()> {
fn new(box: &@Box) -> AbstractNode<()> {
unsafe {
transmute(box.base().node)
transmute(box.node)
}
}
}
impl ExtraDisplayListData for Nothing {
fn new(_: &@RenderBox) -> Nothing {
fn new(_: &@Box) -> Nothing {
()
}
}
impl ExtraDisplayListData for @RenderBox {
fn new(box: &@RenderBox) -> @RenderBox {
impl ExtraDisplayListData for @Box {
fn new(box: &@Box) -> @Box {
*box
}
}

View file

@ -2,23 +2,23 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Servo's experimental layout system builds a tree of `Flow` and `RenderBox` objects and
/// solves layout constraints to obtain positions and display attributes of tree nodes. Positions
/// are computed in several tree traversals driven by the fundamental data dependencies required by
//! Servo's experimental layout system builds a tree of `Flow` and `Box` objects and solves
//! layout constraints to obtain positions and display attributes of tree nodes. Positions are
//! computed in several tree traversals driven by the fundamental data dependencies required by
/// inline and block layout.
///
/// Flows are interior nodes in the layout tree and correspond closely to *flow contexts* in the
/// CSS specification. Flows are responsible for positioning their child flow contexts and render
/// boxes. Flows have purpose-specific fields, such as auxiliary line box structs, out-of-flow
/// child lists, and so on.
/// CSS specification. Flows are responsible for positioning their child flow contexts and boxes.
/// Flows have purpose-specific fields, such as auxiliary line box structs, out-of-flow child
/// lists, and so on.
///
/// Currently, the important types of flows are:
///
/// * `BlockFlow`: A flow that establishes a block context. It has several child flows, each of
/// which are positioned according to block formatting context rules (CSS block boxes). Block
/// flows also contain a single `GenericBox` to represent their rendered borders, padding, etc.
/// (In the future, this render box may be folded into `BlockFlow` to save space.) The BlockFlow
/// at the root of the tree has special behavior: it stretches to the boundaries of the viewport.
/// (In the future, this box may be folded into `BlockFlow` to save space.) The BlockFlow at the
/// root of the tree has special behavior: it stretches to the boundaries of the viewport.
///
/// * `InlineFlow`: A flow that establishes an inline context. It has a flat list of child
/// boxes/flows that are subject to inline layout and line breaking and structs to represent
@ -27,7 +27,7 @@
use css::node_style::StyledNode;
use layout::block::BlockFlow;
use layout::box::RenderBox;
use layout::box::Box;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::float_context::{FloatContext, Invalid};
@ -340,12 +340,12 @@ pub struct FlowData {
}
pub struct BoxIterator {
priv boxes: ~[@RenderBox],
priv boxes: ~[@Box],
priv index: uint,
}
impl Iterator<@RenderBox> for BoxIterator {
fn next(&mut self) -> Option<@RenderBox> {
impl Iterator<@Box> for BoxIterator {
fn next(&mut self) -> Option<@Box> {
if self.index >= self.boxes.len() {
None
} else {

View file

@ -3,8 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use css::node_style::StyledNode;
use layout::box::{CannotSplit, GenericRenderBoxClass, ImageRenderBoxClass, RenderBox};
use layout::box::{RenderBoxUtils, SplitDidFit, SplitDidNotFit, TextRenderBoxClass};
use layout::box::{Box, CannotSplit, GenericBox, ImageBox, ScannedTextBox, SplitDidFit};
use layout::box::{SplitDidNotFit, UnscannedTextBox};
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{FlowClass, Flow, FlowData, InlineFlowClass};
@ -25,34 +25,31 @@ use std::cell::Cell;
use std::u16;
use std::util;
/*
Lineboxes are represented as offsets into the child list, rather than
as an object that "owns" boxes. Choosing a different set of line
breaks requires a new list of offsets, and possibly some splitting and
merging of TextBoxes.
A similar list will keep track of the mapping between CSS boxes and
the corresponding render boxes in the inline flow.
After line breaks are determined, render boxes in the inline flow may
overlap visually. For example, in the case of nested inline CSS boxes,
outer inlines must be at least as large as the inner inlines, for
purposes of drawing noninherited things like backgrounds, borders,
outlines.
N.B. roc has an alternative design where the list instead consists of
things like "start outer box, text, start inner box, text, end inner
box, text, end outer box, text". This seems a little complicated to
serve as the starting point, but the current design doesn't make it
hard to try out that alternative.
Line boxes also contain some metadata used during line breaking. The
green zone is the area that the line can expand to before it collides
with a float or a horizontal wall of the containing block. The top
left corner of the green zone is the same as that of the line, but
the green zone can be taller and wider than the line itself.
*/
/// Lineboxes are represented as offsets into the child list, rather than
/// as an object that "owns" boxes. Choosing a different set of line
/// breaks requires a new list of offsets, and possibly some splitting and
/// merging of TextBoxes.
///
/// A similar list will keep track of the mapping between CSS boxes and
/// the corresponding boxes in the inline flow.
///
/// After line breaks are determined, render boxes in the inline flow may
/// overlap visually. For example, in the case of nested inline CSS boxes,
/// outer inlines must be at least as large as the inner inlines, for
/// purposes of drawing noninherited things like backgrounds, borders,
/// outlines.
///
/// N.B. roc has an alternative design where the list instead consists of
/// things like "start outer box, text, start inner box, text, end inner
/// box, text, end outer box, text". This seems a little complicated to
/// serve as the starting point, but the current design doesn't make it
/// hard to try out that alternative.
///
/// Line boxes also contain some metadata used during line breaking. The
/// green zone is the area that the line can expand to before it collides
/// with a float or a horizontal wall of the containing block. The top
/// left corner of the green zone is the same as that of the line, but
/// the green zone can be taller and wider than the line itself.
struct LineBox {
range: Range,
bounds: Rect<Au>,
@ -61,8 +58,9 @@ struct LineBox {
struct LineboxScanner {
floats: FloatContext,
new_boxes: ~[@RenderBox],
work_list: @mut RingBuf<@RenderBox>,
new_boxes: ~[@Box],
/// FIXME(pcwalton): `@mut`? :(
work_list: @mut RingBuf<@Box>,
pending_line: LineBox,
lines: ~[LineBox],
cur_y: Au,
@ -128,11 +126,11 @@ impl LineboxScanner {
break
}
let box = flow.boxes[i]; i += 1;
debug!("LineboxScanner: Working with box from box list: b{:d}", box.base().id());
debug!("LineboxScanner: Working with box from box list: b{}", box.debug_id());
box
} else {
let box = self.work_list.pop_front().unwrap();
debug!("LineboxScanner: Working with box from work list: b{:d}", box.base().id());
debug!("LineboxScanner: Working with box from work list: b{}", box.debug_id());
box
};
@ -179,7 +177,7 @@ impl LineboxScanner {
// FIXME(eatkinson): this assumes that the tallest box in the line determines the line height
// This might not be the case with some weird text fonts.
fn new_height_for_line(&self, new_box: &RenderBox) -> Au {
fn new_height_for_line(&self, new_box: &Box) -> Au {
let box_height = new_box.box_height();
if box_height > self.pending_line.bounds.size.height {
box_height
@ -188,14 +186,14 @@ impl LineboxScanner {
}
}
/// Computes the position of a line that has only the provided RenderBox.
/// Returns: the bounding rect of the line's green zone (whose origin coincides
/// with the line's origin) and the actual width of the first box after splitting.
fn initial_line_placement(&self, first_box: @RenderBox, ceiling: Au, flow: &mut InlineFlow)
/// Computes the position of a line that has only the provided box. Returns the bounding rect
/// of the line's green zone (whose origin coincides with the line's origin) and the actual
/// width of the first box after splitting.
fn initial_line_placement(&self, first_box: @Box, ceiling: Au, flow: &mut InlineFlow)
-> (Rect<Au>, Au) {
debug!("LineboxScanner: Trying to place first box of line {}", self.lines.len());
let first_box_size = first_box.base().position.get().size;
let first_box_size = first_box.position.get().size;
let splittable = first_box.can_split();
debug!("LineboxScanner: box size: {}, splittable: {}", first_box_size, splittable);
let line_is_empty: bool = self.pending_line.range.length() == 0;
@ -250,9 +248,9 @@ impl LineboxScanner {
debug!("LineboxScanner: case=box split and fit");
let actual_box_width = match (left, right) {
(Some(l_box), Some(_)) => l_box.base().position.get().size.width,
(Some(l_box), None) => l_box.base().position.get().size.width,
(None, Some(r_box)) => r_box.base().position.get().size.width,
(Some(l_box), Some(_)) => l_box.position.get().size.width,
(Some(l_box), None) => l_box.position.get().size.width,
(None, Some(r_box)) => r_box.position.get().size.width,
(None, None) => fail!("This case makes no sense.")
};
return (line_bounds, actual_box_width);
@ -264,9 +262,9 @@ impl LineboxScanner {
debug!("LineboxScanner: case=box split and fit didn't fit; trying to push it down");
let actual_box_width = match (left, right) {
(Some(l_box), Some(_)) => l_box.base().position.get().size.width,
(Some(l_box), None) => l_box.base().position.get().size.width,
(None, Some(r_box)) => r_box.base().position.get().size.width,
(Some(l_box), Some(_)) => l_box.position.get().size.width,
(Some(l_box), None) => l_box.position.get().size.width,
(None, Some(r_box)) => r_box.position.get().size.width,
(None, None) => fail!("This case makes no sense.")
};
@ -281,7 +279,7 @@ impl LineboxScanner {
}
/// Returns false only if we should break the line.
fn try_append_to_line(&mut self, in_box: @RenderBox, flow: &mut InlineFlow) -> bool {
fn try_append_to_line(&mut self, in_box: @Box, flow: &mut InlineFlow) -> bool {
let line_is_empty: bool = self.pending_line.range.length() == 0;
if line_is_empty {
@ -293,7 +291,7 @@ impl LineboxScanner {
debug!("LineboxScanner: Trying to append box to line {:u} (box size: {}, green zone: \
{}): {:s}",
self.lines.len(),
in_box.base().position.get().size,
in_box.position.get().size,
self.pending_line.green_zone,
in_box.debug_str());
@ -349,8 +347,7 @@ impl LineboxScanner {
// horizontally. We'll try to place the whole box on this line and break somewhere
// if it doesn't fit.
let new_width = self.pending_line.bounds.size.width +
in_box.base().position.get().size.width;
let new_width = self.pending_line.bounds.size.width + in_box.position.get().size.width;
if new_width <= green_zone.width {
debug!("LineboxScanner: case=box fits without splitting");
@ -424,8 +421,8 @@ impl LineboxScanner {
}
// unconditional push
fn push_box_to_line(&mut self, box: @RenderBox) {
debug!("LineboxScanner: Pushing box b{:d} to line {:u}", box.base().id(), self.lines.len());
fn push_box_to_line(&mut self, box: @Box) {
debug!("LineboxScanner: Pushing box {} to line {:u}", box.debug_id(), self.lines.len());
if self.pending_line.range.length() == 0 {
assert!(self.new_boxes.len() <= (u16::max_value as uint));
@ -433,9 +430,9 @@ impl LineboxScanner {
}
self.pending_line.range.extend_by(1);
self.pending_line.bounds.size.width = self.pending_line.bounds.size.width +
box.base().position.get().size.width;
box.position.get().size.width;
self.pending_line.bounds.size.height = Au::max(self.pending_line.bounds.size.height,
box.base().position.get().size.height);
box.position.get().size.height);
self.new_boxes.push(box);
}
}
@ -444,9 +441,9 @@ pub struct InlineFlow {
/// Data common to all flows.
base: FlowData,
// A vec of all inline render boxes. Several boxes may
// correspond to one Node/Element.
boxes: ~[@RenderBox],
/// A vector of all inline render boxes. Several boxes may correspond to one node/element.
boxes: ~[@Box],
// vec of ranges into boxes that represents line positions.
// these ranges are disjoint, and are the result of inline layout.
// also some metadata used for positioning lines
@ -467,7 +464,7 @@ impl InlineFlow {
}
}
pub fn from_boxes(base: FlowData, boxes: ~[@RenderBox]) -> InlineFlow {
pub fn from_boxes(base: FlowData, boxes: ~[@Box]) -> InlineFlow {
InlineFlow {
base: base,
boxes: boxes,
@ -560,8 +557,7 @@ impl Flow for InlineFlow {
fn assign_widths(&mut self, _: &mut LayoutContext) {
// Initialize content box widths if they haven't been initialized already.
//
// TODO: Combine this with `LineboxScanner`'s walk in the box list, or put this into
// `RenderBox`.
// TODO: Combine this with `LineboxScanner`'s walk in the box list, or put this into `Box`.
debug!("assign_widths_inline: floats_in: {:?}", self.base.floats_in);
{
@ -620,14 +616,13 @@ impl Flow for InlineFlow {
if slack_width < Au::new(0) {
slack_width = Au::new(0);
}
//assert!(slack_width >= Au::new(0), "Too many boxes on line");
// Get the text alignment.
// TODO(Issue #222): use 'text-align' property from InlineFlow's
// block container, not from the style of the first box child.
let linebox_align = if line.range.begin() < self.boxes.len() {
let first_box = self.boxes[line.range.begin()];
first_box.base().nearest_ancestor_element().style().Text.text_align
first_box.nearest_ancestor_element().style().Text.text_align
} else {
// Nothing to lay out, so assume left alignment.
text_align::left
@ -640,7 +635,7 @@ impl Flow for InlineFlow {
// TODO(Issue #213): implement `text-align: justify`
text_align::left | text_align::justify => {
for i in line.range.eachi() {
let box = self.boxes[i].base();
let box = &self.boxes[i];
box.position.mutate().ptr.origin.x = offset_x;
offset_x = offset_x + box.position.get().size.width;
}
@ -648,7 +643,7 @@ impl Flow for InlineFlow {
text_align::center => {
offset_x = offset_x + slack_width.scale_by(0.5);
for i in line.range.eachi() {
let box = self.boxes[i].base();
let box = &self.boxes[i];
box.position.mutate().ptr.origin.x = offset_x;
offset_x = offset_x + box.position.get().size.width;
}
@ -656,7 +651,7 @@ impl Flow for InlineFlow {
text_align::right => {
offset_x = offset_x + slack_width;
for i in line.range.eachi() {
let box = self.boxes[i].base();
let box = &self.boxes[i];
box.position.mutate().ptr.origin.x = offset_x;
offset_x = offset_x + box.position.get().size.width;
}
@ -680,41 +675,40 @@ impl Flow for InlineFlow {
for box_i in line.range.eachi() {
let cur_box = self.boxes[box_i];
let (top_from_base, bottom_from_base, ascent) = match cur_box.class() {
ImageRenderBoxClass => {
let image_box = cur_box.as_image_render_box();
let mut height = image_box.image_height();
// FIXME(pcwalton): Move into `box.rs` like the rest of box-specific layout code?
let (top_from_base, bottom_from_base, ascent) = match cur_box.specific {
ImageBox(ref image_box) => {
let mut height = image_box.image_height(cur_box);
// TODO: margin, border, padding's top and bottom should be calculated in advance,
// since baseline of image is bottom margin edge.
let mut top;
let mut bottom;
{
let base = &image_box.base;
top = base.border.top + base.padding.top + base.margin.top;
bottom = base.border.bottom + base.padding.bottom +
base.margin.bottom;
top = cur_box.border.get().top + cur_box.padding.get().top +
cur_box.margin.get().top;
bottom = cur_box.border.get().bottom + cur_box.padding.get().bottom +
cur_box.margin.get().bottom;
}
let noncontent_height = top + bottom;
height = height + noncontent_height;
let position_ref = image_box.base.position.mutate();
let position_ref = cur_box.position.mutate();
position_ref.ptr.size.height = height;
position_ref.ptr.translate(&Point2D(Au::new(0), -height));
let ascent = height + bottom;
(height, Au::new(0), ascent)
},
TextRenderBoxClass => {
let text_box = cur_box.as_text_render_box();
ScannedTextBox(ref text_box) => {
let range = &text_box.range;
let run = &text_box.run;
// Compute the height based on the line-height and font size
let text_bounds = run.metrics_for_range(range).bounding_box;
let em_size = text_bounds.size.height;
let line_height = text_box.base.calculate_line_height(em_size);
let line_height = cur_box.calculate_line_height(em_size);
// Find the top and bottom of the content area.
// Those are used in text-top and text-bottom value of 'vertical-align'
@ -722,20 +716,16 @@ impl Flow for InlineFlow {
// Offset from the top of the box is 1/2 of the leading + ascent
let text_offset = text_ascent + (line_height - em_size).scale_by(0.5);
text_bounds.translate(&Point2D(text_box.base.position.get().origin.x,
Au::new(0)));
text_bounds.translate(&Point2D(cur_box.position.get().origin.x, Au(0)));
(text_offset, line_height - text_offset, text_ascent)
},
GenericRenderBoxClass => {
let base = cur_box.base();
let height = base.position.get().size.height;
GenericBox => {
let height = cur_box.position.get().size.height;
(height, Au::new(0), height)
},
// FIXME(pcwalton): This isn't very type safe!
_ => {
fail!("Tried to assign height to unknown Box variant: {:s}",
cur_box.debug_str())
UnscannedTextBox(_) => {
fail!("Unscanned text boxes should have been scanned by now.")
}
};
let mut top_from_base = top_from_base;
@ -753,9 +743,8 @@ impl Flow for InlineFlow {
// It should calculate the distance from baseline to the bottom of parent's content area.
// But, it is assumed now as 0.
let parent_text_bottom = Au::new(0);
let cur_box_base = cur_box.base();
// Get parent node
let parent = cur_box_base.node.parent_node();
let parent = cur_box.node.parent_node();
let font_size = parent.unwrap().style().Font.font_size;
parent_text_top = font_size;
@ -764,7 +753,7 @@ impl Flow for InlineFlow {
// That is, if the box has top or bottom value, no_update_flag becomes true.
let mut no_update_flag = false;
// Calculate a relative offset from baseline.
let offset = match cur_box_base.vertical_align() {
let offset = match cur_box.vertical_align() {
vertical_align::baseline => {
-ascent
},
@ -819,9 +808,8 @@ impl Flow for InlineFlow {
-(length + ascent)
},
vertical_align::Percentage(p) => {
let pt_size = cur_box.base().font_style().pt_size;
let line_height = cur_box.base()
.calculate_line_height(Au::from_pt(pt_size));
let pt_size = cur_box.font_style().pt_size;
let line_height = cur_box.calculate_line_height(Au::from_pt(pt_size));
let percent_offset = line_height.scale_by(p);
-(percent_offset + ascent)
}
@ -836,7 +824,7 @@ impl Flow for InlineFlow {
bottommost = bottom_from_base;
}
cur_box.base().position.mutate().ptr.origin.y = line.bounds.origin.y + offset;
cur_box.position.mutate().ptr.origin.y = line.bounds.origin.y + offset;
}
// Calculate the distance from baseline to the top of the biggest box with 'bottom' value.
@ -859,15 +847,14 @@ impl Flow for InlineFlow {
// All boxes' y position is updated following the new baseline offset.
for box_i in line.range.eachi() {
let cur_box = self.boxes[box_i];
let cur_box_base = cur_box.base();
let adjust_offset = match cur_box_base.vertical_align() {
let adjust_offset = match cur_box.vertical_align() {
vertical_align::top => Au::new(0),
vertical_align::bottom => baseline_offset + bottommost,
_ => baseline_offset,
};
cur_box_base.position.mutate().ptr.origin.y =
cur_box_base.position.get().origin.y + adjust_offset;
cur_box.position.mutate().ptr.origin.y = cur_box.position.get().origin.y +
adjust_offset;
}
// This is used to set the top y position of the next linebox in the next loop.

View file

@ -4,13 +4,13 @@
//! Text layout.
use std::vec;
use layout::box::{Box, ScannedTextBox, ScannedTextBoxInfo, UnscannedTextBox};
use layout::context::LayoutContext;
use layout::flow::Flow;
use gfx::text::text_run::TextRun;
use gfx::text::util::{CompressWhitespaceNewline, transform_text};
use layout::box::{RenderBox, RenderBoxUtils, TextRenderBox, UnscannedTextRenderBoxClass};
use layout::context::LayoutContext;
use layout::flow::Flow;
use std::vec;
use servo_util::range::Range;
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextBox`es.
@ -56,27 +56,20 @@ impl TextRunScanner {
flow.as_inline().boxes = out_boxes;
// A helper function.
fn can_coalesce_text_nodes(boxes: &[@RenderBox], left_i: uint, right_i: uint) -> bool {
fn can_coalesce_text_nodes(boxes: &[@Box], left_i: uint, right_i: uint) -> bool {
assert!(left_i < boxes.len());
assert!(right_i > 0 && right_i < boxes.len());
assert!(left_i != right_i);
let (left, right) = (boxes[left_i], boxes[right_i]);
match (left.class(), right.class()) {
(UnscannedTextRenderBoxClass, UnscannedTextRenderBoxClass) => {
left.can_merge_with_box(right)
}
(_, _) => false
}
boxes[left_i].can_merge_with_box(boxes[right_i])
}
}
/// A "clump" is a range of inline flow leaves that can be merged together into a single
/// `RenderBox`. Adjacent text with the same style can be merged, and nothing else can.
/// A "clump" is a range of inline flow leaves that can be merged together into a single box.
/// Adjacent text with the same style can be merged, and nothing else can.
///
/// The flow keeps track of the `RenderBox`es contained by all non-leaf DOM nodes. This is
/// necessary for correct painting order. Since we compress several leaf `RenderBox`es here,
/// the mapping must be adjusted.
/// The flow keeps track of the boxes contained by all non-leaf DOM nodes. This is necessary
/// for correct painting order. Since we compress several leaf boxes here, the mapping must be
/// adjusted.
///
/// N.B. `in_boxes` is passed by reference, since the old code used a `DVec`. The caller is
/// responsible for swapping out the list. It is not clear to me (pcwalton) that this is still
@ -85,7 +78,7 @@ impl TextRunScanner {
ctx: &LayoutContext,
flow: &mut Flow,
last_whitespace: bool,
out_boxes: &mut ~[@RenderBox])
out_boxes: &mut ~[@Box])
-> bool {
let inline = flow.as_inline();
let in_boxes = &inline.boxes;
@ -95,10 +88,12 @@ impl TextRunScanner {
debug!("TextRunScanner: flushing boxes in range={}", self.clump);
let is_singleton = self.clump.length() == 1;
let possible_text_clump = in_boxes[self.clump.begin()]; // FIXME(pcwalton): Rust bug
let is_text_clump = possible_text_clump.class() == UnscannedTextRenderBoxClass;
let is_text_clump = match possible_text_clump.specific {
UnscannedTextBox(_) => true,
_ => false,
};
let mut new_whitespace = last_whitespace;
match (is_singleton, is_text_clump) {
(false, false) => {
fail!(~"WAT: can't coalesce non-text nodes in flush_clump_to_list()!")
@ -109,14 +104,20 @@ impl TextRunScanner {
},
(true, true) => {
let old_box = in_boxes[self.clump.begin()];
let text = old_box.as_unscanned_text_render_box().raw_text();
let font_style = old_box.base().font_style();
let decoration = old_box.base().text_decoration();
let text = match old_box.specific {
UnscannedTextBox(ref text_box_info) => &text_box_info.text,
_ => fail!("Expected an unscanned text box!"),
};
let font_style = old_box.font_style();
let decoration = old_box.text_decoration();
// TODO(#115): Use the actual CSS `white-space` property of the relevant style.
let compression = CompressWhitespaceNewline;
let (transformed_text, whitespace) = transform_text(text, compression, last_whitespace);
let (transformed_text, whitespace) = transform_text(*text,
compression,
last_whitespace);
new_whitespace = whitespace;
if transformed_text.len() > 0 {
@ -126,11 +127,15 @@ impl TextRunScanner {
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
let run = @fontgroup.create_textrun(transformed_text, decoration);
debug!("TextRunScanner: pushing single text box in range: {} ({})", self.clump, text);
debug!("TextRunScanner: pushing single text box in range: {} ({})",
self.clump,
*text);
let range = Range::new(0, run.char_len());
let new_box = @TextRenderBox::new((*old_box.base()).clone(), run, range);
out_boxes.push(new_box as @RenderBox);
let new_text_box_info = ScannedTextBoxInfo::new(run, range);
let new_metrics = run.metrics_for_range(&range);
let new_box = @old_box.transform(new_metrics.bounding_box.size,
ScannedTextBox(new_text_box_info));
out_boxes.push(new_box)
}
},
(false, true) => {
@ -144,8 +149,12 @@ impl TextRunScanner {
// `transform_text`, so that boxes starting and/or ending with whitespace can
// be compressed correctly with respect to the text run.
let idx = i + self.clump.begin();
let in_box = in_boxes[idx].as_unscanned_text_render_box().raw_text();
let (new_str, new_whitespace) = transform_text(in_box,
let in_box = match in_boxes[idx].specific {
UnscannedTextBox(ref text_box_info) => &text_box_info.text,
_ => fail!("Expected an unscanned text box!"),
};
let (new_str, new_whitespace) = transform_text(*in_box,
compression,
last_whitespace_in_clump);
last_whitespace_in_clump = new_whitespace;
@ -171,9 +180,9 @@ impl TextRunScanner {
// font group fonts. This is probably achieved by creating the font group above
// and then letting `FontGroup` decide which `Font` to stick into the text run.
let in_box = in_boxes[self.clump.begin()];
let font_style = in_box.base().font_style();
let font_style = in_box.font_style();
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
let decoration = in_box.base().text_decoration();
let decoration = in_box.text_decoration();
// TextRuns contain a cycle which is usually resolved by the teardown
// sequence. If no clump takes ownership, however, it will leak.
@ -195,10 +204,11 @@ impl TextRunScanner {
continue
}
let new_box = @TextRenderBox::new((*in_boxes[i].base()).clone(),
run.unwrap(),
range);
out_boxes.push(new_box as @RenderBox);
let new_text_box_info = ScannedTextBoxInfo::new(run.unwrap(), range);
let new_metrics = new_text_box_info.run.metrics_for_range(&range);
let new_box = @in_boxes[i].transform(new_metrics.bounding_box.size,
ScannedTextBox(new_text_box_info));
out_boxes.push(new_box)
}
}
} // End of match.

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use layout::box::{RenderBox, RenderBoxUtils};
use layout::box::Box;
use layout::construct::{ConstructionResult, NoConstructionResult};
use extra::arc::Arc;
@ -76,7 +76,7 @@ impl ElementMapping {
self.entries.iter().enumerate()
}
pub fn repair_for_box_changes(&mut self, old_boxes: &[@RenderBox], new_boxes: &[@RenderBox]) {
pub fn repair_for_box_changes(&mut self, old_boxes: &[@Box], new_boxes: &[@Box]) {
let entries = &mut self.entries;
debug!("--- Old boxes: ---");
@ -118,8 +118,7 @@ impl ElementMapping {
repair_stack.push(item);
entries_k += 1;
}
while new_j < new_boxes.len() &&
old_boxes[old_i].base().node != new_boxes[new_j].base().node {
while new_j < new_boxes.len() && old_boxes[old_i].node != new_boxes[new_j].node {
debug!("repair_for_box_changes: Slide through new box {:u}", new_j);
new_j += 1;
}