removing @ from flowtree. (but cloning boxes when creating a display list)

This commit is contained in:
Ryan Choi 2013-12-09 14:22:38 +09:00
parent 6014bd3813
commit d26bf36833
9 changed files with 156 additions and 158 deletions

View file

@ -93,7 +93,7 @@ pub struct SolidColorDisplayItem<E> {
/// Renders text.
pub struct TextDisplayItem<E> {
base: BaseDisplayItem<E>,
text_run: ~TextRun,
text_run: Arc<~TextRun>,
range: Range,
color: Color,
}
@ -163,7 +163,8 @@ impl<E> DisplayItem<E> {
debug!("Drawing text at {:?}.", text.base.bounds);
// FIXME(pcwalton): Allocating? Why?
let font = render_context.font_ctx.get_font_by_descriptor(&text.text_run.font_descriptor).unwrap();
let text_run = text.text_run.get();
let font = render_context.font_ctx.get_font_by_descriptor(&text_run.font_descriptor).unwrap();
let font_metrics = font.with_borrow( |font| {
font.metrics.clone()
@ -172,7 +173,7 @@ impl<E> DisplayItem<E> {
let baseline_origin = Point2D(origin.x, origin.y + font_metrics.ascent);
font.with_mut_borrow( |font| {
font.draw_text_into_context(render_context,
&text.text_run,
text.text_run.get(),
&text.range,
baseline_origin,
text.color);
@ -183,18 +184,18 @@ impl<E> DisplayItem<E> {
let strikeout_size = font_metrics.strikeout_size;
let strikeout_offset = font_metrics.strikeout_offset;
if text.text_run.decoration.underline {
if text_run.decoration.underline {
let underline_y = baseline_origin.y - underline_offset;
let underline_bounds = Rect(Point2D(baseline_origin.x, underline_y),
Size2D(width, underline_size));
render_context.draw_solid_color(&underline_bounds, text.color);
}
if text.text_run.decoration.overline {
if text_run.decoration.overline {
let overline_bounds = Rect(Point2D(baseline_origin.x, origin.y),
Size2D(width, underline_size));
render_context.draw_solid_color(&overline_bounds, text.color);
}
if text.text_run.decoration.line_through {
if text_run.decoration.line_through {
let strikeout_y = baseline_origin.y - strikeout_offset;
let strikeout_bounds = Rect(Point2D(baseline_origin.x, strikeout_y),
Size2D(width, strikeout_size));

View file

@ -53,7 +53,7 @@ pub struct BlockFlow {
base: FlowData,
/// The associated box.
box: Option<@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: @Box) -> 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: @Box) -> BlockFlow {
pub fn float_from_box(base: FlowData, float_type: FloatType, box: ~Box) -> BlockFlow {
BlockFlow {
base: base,
box: Some(box),
@ -172,7 +172,7 @@ impl BlockFlow {
(width_Au, left_margin_Au, right_margin_Au)
}
fn compute_block_margins(&self, box: @Box, remaining_width: Au, available_width: Au)
fn compute_block_margins(&self, box: &Box, remaining_width: Au, available_width: Au)
-> (Au, Au, Au) {
let style = box.style();
@ -215,7 +215,7 @@ impl BlockFlow {
return (width, margin_left, margin_right);
}
fn compute_float_margins(&self, box: @Box, remaining_width: Au) -> (Au, Au, Au) {
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();
@ -240,7 +240,7 @@ impl BlockFlow {
let mut left_offset = Au::new(0);
let mut float_ctx = Invalid;
for &box in self.box.iter() {
for box in self.box.iter() {
clearance = match box.clear() {
None => Au::new(0),
Some(clear) => {
@ -279,7 +279,7 @@ impl BlockFlow {
let mut top_margin_collapsible = false;
let mut bottom_margin_collapsible = false;
let mut first_in_flow = true;
for &box in self.box.iter() {
for box in self.box.iter() {
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;
@ -328,7 +328,7 @@ impl BlockFlow {
cur_y - top_offset - collapsing
};
for &box in self.box.iter() {
for box in self.box.iter() {
let style = box.style();
height = match MaybeAuto::from_style(style.Box.height, Au::new(0)) {
Auto => height,
@ -419,7 +419,7 @@ impl BlockFlow {
let mut cur_y = Au(0);
let mut top_offset = Au(0);
for &box in self.box.iter() {
for box in self.box.iter() {
top_offset = box.margin.get().top + box.border.get().top + box.padding.get().top;
cur_y = cur_y + top_offset;
}
@ -464,16 +464,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 x = self.base.abs_position.x + do self.box.as_ref().map_default(Au::new(0)) |box| {
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 y = self.base.abs_position.y + do self.box.as_ref().map_default(Au::new(0)) |box| {
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| {
let w = self.base.position.size.width - do self.box.as_ref().map_default(Au::new(0)) |box| {
box.noncontent_width()
};
let h = self.base.position.size.height - do self.box.map_default(Au::new(0)) |box| {
let h = self.base.position.size.height - do self.box.as_ref().map_default(Au::new(0)) |box| {
box.noncontent_height()
};
do self.base.node.with_mut_iframe_element |iframe_element| {
@ -627,7 +627,7 @@ impl Flow for BlockFlow {
self.base.is_inorder = false;
}
for &box in self.box.iter() {
for box in self.box.iter() {
let style = box.style();
// Can compute padding here since we know containing block width.
@ -643,9 +643,9 @@ impl Flow for BlockFlow {
remaining_width).specified_or_zero();
let (width, margin_left, margin_right) = if self.is_float() {
self.compute_float_margins(box, remaining_width)
self.compute_float_margins(*box, remaining_width)
} else {
self.compute_block_margins(box, remaining_width, available_width)
self.compute_block_margins(*box, remaining_width, available_width)
};
box.margin.set(SideOffsets2D::new(margin_top,
@ -727,7 +727,7 @@ impl Flow for BlockFlow {
return;
}
for &box in self.box.iter() {
for box in self.box.iter() {
// 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 {
@ -760,7 +760,7 @@ impl Flow for BlockFlow {
} else {
let txt = if self.is_float() { ~"FloatFlow: " } else { ~"BlockFlow: " };
txt.append(match self.box {
Some(rb) => {
Some(ref rb) => {
rb.debug_str()
}
None => { ~"" }

View file

@ -5,7 +5,7 @@
//! The `Box` type, which represents the leaves of the layout tree.
use extra::url::Url;
use extra::arc::MutexArc;
use extra::arc::{MutexArc, Arc};
use geom::{Point2D, Rect, Size2D, SideOffsets2D};
use gfx::color::rgb;
use gfx::display_list::{BaseDisplayItem, BorderDisplayItem, BorderDisplayItemClass};
@ -55,6 +55,7 @@ use layout::model::{MaybeAuto, specified};
/// types of boxes may also contain custom data; for example, text boxes contain text.
///
/// FIXME(pcwalton): This can be slimmed down quite a bit.
#[deriving(Clone)]
pub struct Box {
/// The DOM node that this `Box` originates from.
node: AbstractNode<LayoutView>,
@ -81,6 +82,7 @@ pub struct Box {
}
/// Info specific to the kind of box. Keep this enum small.
#[deriving(Clone)]
pub enum SpecificBoxInfo {
GenericBox,
ImageBox(ImageBoxInfo),
@ -89,6 +91,7 @@ pub enum SpecificBoxInfo {
}
/// A box that represents a replaced content image and its accompanying borders, shadows, etc.
#[deriving(Clone)]
pub struct ImageBoxInfo {
/// The image held within this box.
image: Slot<ImageHolder>,
@ -158,9 +161,10 @@ impl ImageBoxInfo {
/// split into two or more boxes across line breaks. Several `TextBox`es may correspond to a single
/// DOM text node. Split text boxes are implemented by referring to subsets of a single `TextRun`
/// object.
#[deriving(Clone)]
pub struct ScannedTextBoxInfo {
/// The text run that this represents.
run: @TextRun,
run: Arc<~TextRun>,
/// The range within the above text run that this represents.
range: Range,
@ -168,7 +172,7 @@ pub struct ScannedTextBoxInfo {
impl ScannedTextBoxInfo {
/// Creates the information specific to a scanned text box from a range and a text run.
pub fn new(run: @TextRun, range: Range) -> ScannedTextBoxInfo {
pub fn new(run: Arc<~TextRun>, range: Range) -> ScannedTextBoxInfo {
ScannedTextBoxInfo {
run: run,
range: range,
@ -178,6 +182,7 @@ impl ScannedTextBoxInfo {
/// Data for an unscanned text box. Unscanned text boxes are the results of flow construction that
/// have not yet had their width determined.
#[deriving(Clone)]
pub struct UnscannedTextBoxInfo {
/// The text inside the box.
text: ~str,
@ -197,11 +202,11 @@ impl UnscannedTextBoxInfo {
/// Represents the outcome of attempting to split a box.
pub enum SplitBoxResult {
CannotSplit(@Box),
CannotSplit,
// in general, when splitting the left or right side can
// be zero length, due to leading/trailing trimmable whitespace
SplitDidFit(Option<@Box>, Option<@Box>),
SplitDidNotFit(Option<@Box>, Option<@Box>)
SplitDidFit(Option<~Box>, Option<~Box>),
SplitDidNotFit(Option<~Box>, Option<~Box>)
}
impl Box {
@ -499,7 +504,7 @@ impl Box {
/// Adds the display items necessary to paint the background of this box to the display list if
/// necessary.
pub fn paint_background_if_applicable<E:ExtraDisplayListData>(
@self,
&self,
list: &Cell<DisplayList<E>>,
absolute_bounds: &Rect<Au>) {
// FIXME: This causes a lot of background colors to be displayed when they are clearly not
@ -515,7 +520,7 @@ impl Box {
let solid_color_display_item = ~SolidColorDisplayItem {
base: BaseDisplayItem {
bounds: *absolute_bounds,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
color: background_color.to_gfx_color(),
};
@ -528,7 +533,7 @@ impl Box {
/// Adds the display items necessary to paint the borders of this box to a display list if
/// necessary.
pub fn paint_borders_if_applicable<E:ExtraDisplayListData>(
@self,
&self,
list: &Cell<DisplayList<E>>,
abs_bounds: &Rect<Au>) {
// Fast path.
@ -552,7 +557,7 @@ impl Box {
let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem {
bounds: *abs_bounds,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
border: border,
color: SideOffsets2D::new(top_color.to_gfx_color(),
@ -584,7 +589,7 @@ impl Box {
/// items, each box puts its display items into the correct stack layer according to CSS 2.1
/// Appendix E. Finally, the builder flattens the list.
pub fn build_display_list<E:ExtraDisplayListData>(
@self,
&self,
_: &DisplayListBuilder,
dirty: &Rect<Au>,
offset: &Point2D<Au>,
@ -616,7 +621,7 @@ impl Box {
let item = ~ClipDisplayItem {
base: BaseDisplayItem {
bounds: absolute_box_bounds,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
child_list: ~[],
need_clip: false
@ -631,18 +636,11 @@ impl Box {
// Create the text box.
do list.with_mut_ref |list| {
// FIXME(pcwalton): Allocation? Why?!
let run = ~TextRun {
text: text_box.run.text.clone(),
font_descriptor: text_box.run.font_descriptor.clone(),
font_metrics: text_box.run.font_metrics.clone(),
font_style: text_box.run.font_style.clone(),
decoration: text_box.run.decoration.clone(),
glyphs: text_box.run.glyphs.clone()
};
let run = text_box.run.clone();
let text_display_item = ~TextDisplayItem {
base: BaseDisplayItem {
bounds: absolute_box_bounds,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
text_run: run,
range: text_box.range,
@ -664,7 +662,7 @@ impl Box {
let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem {
bounds: absolute_box_bounds,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
border: debug_border,
color: SideOffsets2D::new_all_same(rgb(0, 0, 200)),
@ -677,7 +675,7 @@ impl Box {
// Draw a rectangle representing the baselines.
//
// TODO(Issue #221): Create and use a Line display item for the baseline.
let ascent = text_box.run.metrics_for_range(
let ascent = text_box.run.get().metrics_for_range(
&text_box.range).ascent;
let baseline = Rect(absolute_box_bounds.origin + Point2D(Au(0), ascent),
Size2D(absolute_box_bounds.size.width, Au(0)));
@ -686,7 +684,7 @@ impl Box {
let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem {
bounds: baseline,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
border: debug_border,
color: SideOffsets2D::new_all_same(rgb(0, 200, 0)),
@ -704,7 +702,7 @@ impl Box {
let item = ~ClipDisplayItem {
base: BaseDisplayItem {
bounds: absolute_box_bounds,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
child_list: ~[],
need_clip: self.needs_clip()
@ -721,7 +719,7 @@ impl Box {
let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem {
bounds: absolute_box_bounds,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
border: debug_border,
color: SideOffsets2D::new_all_same(rgb(0, 0, 200)),
@ -739,7 +737,7 @@ impl Box {
let item = ~ClipDisplayItem {
base: BaseDisplayItem {
bounds: absolute_box_bounds,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
child_list: ~[],
need_clip: false
@ -756,7 +754,7 @@ impl Box {
let image_display_item = ~ImageDisplayItem {
base: BaseDisplayItem {
bounds: absolute_box_bounds,
extra: ExtraDisplayListData::new(&self),
extra: ExtraDisplayListData::new(self),
},
image: image.clone(),
};
@ -790,11 +788,11 @@ impl Box {
}
ScannedTextBox(ref text_box_info) => {
let range = &text_box_info.range;
let min_line_width = text_box_info.run.min_width_for_range(range);
let min_line_width = text_box_info.run.get().min_width_for_range(range);
let mut max_line_width = Au::new(0);
for line_range in text_box_info.run.iter_natural_lines_for_range(range) {
let line_metrics = text_box_info.run.metrics_for_range(&line_range);
for line_range in text_box_info.run.get().iter_natural_lines_for_range(range) {
let line_metrics = text_box_info.run.get().metrics_for_range(&line_range);
max_line_width = Au::max(max_line_width, line_metrics.advance_width);
}
@ -825,7 +823,7 @@ impl Box {
ScannedTextBox(ref text_box_info) => {
// Compute the height based on the line-height and font size.
let (range, run) = (&text_box_info.range, &text_box_info.run);
let text_bounds = run.metrics_for_range(range).bounding_box;
let text_bounds = run.get().metrics_for_range(range).bounding_box;
let em_size = text_bounds.size.height;
self.calculate_line_height(em_size)
}
@ -834,9 +832,9 @@ impl Box {
}
/// Attempts to split this box so that its width is no more than `max_width`.
pub fn split_to_width(@self, max_width: Au, starts_line: bool) -> SplitBoxResult {
pub fn split_to_width(&self, max_width: Au, starts_line: bool) -> SplitBoxResult {
match self.specific {
GenericBox | ImageBox(_) => CannotSplit(self),
GenericBox | ImageBox(_) => CannotSplit,
UnscannedTextBox(_) => fail!("Unscanned text boxes should have been scanned by now!"),
ScannedTextBox(ref text_box_info) => {
let mut pieces_processed_count: uint = 0;
@ -846,11 +844,11 @@ impl Box {
debug!("split_to_width: splitting text box (strlen={:u}, range={}, \
avail_width={})",
text_box_info.run.text.get().len(),
text_box_info.run.get().text.get().len(),
text_box_info.range,
max_width);
for (glyphs, offset, slice_range) in text_box_info.run.iter_slices_for_range(
for (glyphs, offset, slice_range) in text_box_info.run.get().iter_slices_for_range(
&text_box_info.range) {
debug!("split_to_width: considering slice (offset={}, range={}, \
remain_width={})",
@ -858,7 +856,7 @@ impl Box {
slice_range,
remaining_width);
let metrics = text_box_info.run.metrics_for_slice(glyphs, &slice_range);
let metrics = text_box_info.run.get().metrics_for_slice(glyphs, &slice_range);
let advance = metrics.advance_width;
let should_continue;
@ -909,9 +907,9 @@ impl Box {
}
let left_box = if left_range.length() > 0 {
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run, left_range);
let new_text_box = @Box::new(self.node, ScannedTextBox(new_text_box_info));
let new_metrics = new_text_box_info.run.metrics_for_range(&left_range);
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), left_range);
let new_metrics = new_text_box_info.run.get().metrics_for_range(&left_range);
let new_text_box = ~Box::new(self.node, ScannedTextBox(new_text_box_info));
new_text_box.set_size(new_metrics.bounding_box.size);
Some(new_text_box)
} else {
@ -919,9 +917,9 @@ impl Box {
};
let right_box = right_range.map_default(None, |range: Range| {
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run, range);
let new_text_box = @Box::new(self.node, ScannedTextBox(new_text_box_info));
let new_metrics = new_text_box_info.run.metrics_for_range(&range);
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), range);
let new_metrics = new_text_box_info.run.get().metrics_for_range(&range);
let new_text_box = ~Box::new(self.node, ScannedTextBox(new_text_box_info));
new_text_box.set_size(new_metrics.bounding_box.size);
Some(new_text_box)
});
@ -975,7 +973,7 @@ impl Box {
/// Cleans up all the memory associated with this box.
pub fn teardown(&self) {
match self.specific {
ScannedTextBox(ref text_box_info) => text_box_info.run.teardown(),
ScannedTextBox(ref text_box_info) => text_box_info.run.get().teardown(),
_ => {}
}
}

View file

@ -7,7 +7,7 @@
//! 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" yetmaybe it's a box,
//! 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.
//!
@ -70,7 +70,7 @@ struct InlineBoxesConstructionResult {
splits: Option<~[InlineBlockSplit]>,
/// Any boxes that succeed the {ib} splits.
boxes: ~[@Box],
boxes: ~[~Box],
}
/// Represents an {ib} split that has not yet found the containing block that it belongs to. This
@ -99,7 +99,7 @@ struct InlineBlockSplit {
/// The inline boxes that precede the flow.
///
/// TODO(pcwalton): Small vector optimization.
predecessor_boxes: ~[@Box],
predecessor_boxes: ~[~Box],
/// The flow that caused this {ib} split.
flow: ~Flow:,
@ -215,7 +215,7 @@ impl<'self> FlowConstructor<'self> {
}
/// Builds a `Box` for the given node.
fn build_box_for_node(&self, node: AbstractNode<LayoutView>) -> @Box {
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) {
@ -226,7 +226,7 @@ impl<'self> FlowConstructor<'self> {
TextNodeTypeId => UnscannedTextBox(UnscannedTextBoxInfo::new(&node)),
_ => GenericBox,
};
@Box::new(node, specific)
~Box::new(node, specific)
}
/// Creates an inline flow from a set of inline boxes and adds it as a child of the given flow.
@ -235,7 +235,7 @@ impl<'self> FlowConstructor<'self> {
/// otherwise.
#[inline(always)]
fn flush_inline_boxes_to_flow(&self,
boxes: ~[@Box],
boxes: ~[~Box],
flow: &mut ~Flow:,
node: AbstractNode<LayoutView>) {
if boxes.len() > 0 {
@ -249,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<~[@Box]>,
opt_boxes: &mut Option<~[~Box]>,
flow: &mut ~Flow:,
node: AbstractNode<LayoutView>) {
let opt_boxes = util::replace(opt_boxes, None);
@ -564,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<~[@Box]>) {
fn strip_ignorable_whitespace_from_start(opt_boxes: &mut Option<~[~Box]>) {
match util::replace(opt_boxes, None) {
None => return,
Some(boxes) => {
@ -586,7 +586,7 @@ fn strip_ignorable_whitespace_from_start(opt_boxes: &mut Option<~[@Box]>) {
}
/// Strips ignorable whitespace from the end of a list of boxes.
fn strip_ignorable_whitespace_from_end(opt_boxes: &mut Option<~[@Box]>) {
fn strip_ignorable_whitespace_from_end(opt_boxes: &mut Option<~[~Box]>) {
match *opt_boxes {
None => {}
Some(ref mut boxes) => {

View file

@ -16,13 +16,13 @@ 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: &@Box) -> Self;
fn new(box: &Box) -> Self;
}
pub type Nothing = ();
impl ExtraDisplayListData for AbstractNode<()> {
fn new(box: &@Box) -> AbstractNode<()> {
fn new(box: &Box) -> AbstractNode<()> {
unsafe {
transmute(box.node)
}
@ -30,7 +30,7 @@ impl ExtraDisplayListData for AbstractNode<()> {
}
impl ExtraDisplayListData for Nothing {
fn new(_: &@Box) -> Nothing {
fn new(_: &Box) -> Nothing {
()
}
}

View file

@ -58,15 +58,13 @@ struct LineBox {
struct LineboxScanner {
floats: FloatContext,
new_boxes: ~[@Box],
work_list: RingBuf<@Box>,
new_boxes: ~[~Box],
work_list: RingBuf<~Box>,
pending_line: LineBox,
lines: ~[LineBox],
cur_y: Au,
}
local_data_key!(local_linebox_scanner: LineboxScanner)
impl LineboxScanner {
pub fn new(float_ctx: FloatContext) -> LineboxScanner {
LineboxScanner {
@ -116,15 +114,13 @@ impl LineboxScanner {
pub fn scan_for_lines(&mut self, flow: &mut InlineFlow) {
self.reset_scanner(flow);
let mut i = 0u;
loop {
// acquire the next box to lay out from work list or box list
let cur_box = if self.work_list.is_empty() {
if i == flow.boxes.len() {
break
if flow.boxes.is_empty() {
break;
}
let box = flow.boxes[i]; i += 1;
let box = flow.boxes.remove(0); // FIXME: use a linkedlist
debug!("LineboxScanner: Working with box from box list: b{}", box.debug_id());
box
} else {
@ -188,7 +184,7 @@ impl LineboxScanner {
/// 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)
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());
@ -238,7 +234,7 @@ impl LineboxScanner {
// We should find a better abstraction or merge it with the call in
// try_append_to_line.
match first_box.split_to_width(line_bounds.size.width, line_is_empty) {
CannotSplit(_) => {
CannotSplit => {
error!("LineboxScanner: Tried to split unsplittable render box! {:s}",
first_box.debug_str());
return (line_bounds, first_box_size.width);
@ -292,7 +288,7 @@ impl LineboxScanner {
///
/// Returns false if and only if we should break the line.
fn avoid_floats(&mut self,
in_box: @Box,
in_box: ~Box,
flow: &mut InlineFlow,
new_height: Au,
line_is_empty: bool)
@ -325,7 +321,7 @@ impl LineboxScanner {
/// Tries to append the given box to the line, splitting it if necessary. Returns false only if
/// we should break the line.
fn try_append_to_line(&mut self, in_box: @Box, flow: &mut InlineFlow) -> bool {
fn try_append_to_line(&mut self, in_box: ~Box, flow: &mut InlineFlow) -> bool {
let line_is_empty = self.pending_line.range.length() == 0;
if line_is_empty {
let (line_bounds, _) = self.initial_line_placement(in_box, self.cur_y, flow);
@ -348,7 +344,7 @@ impl LineboxScanner {
let new_height = self.new_height_for_line(in_box);
if new_height > green_zone.height {
// Uh-oh. Float collision imminent. Enter the float collision avoider
// Uh-oh. Float collision imminent. Enter the float collision avoider
return self.avoid_floats(in_box, flow, new_height, line_is_empty)
}
@ -379,7 +375,7 @@ impl LineboxScanner {
let available_width = green_zone.width - self.pending_line.bounds.size.width;
let split = in_box.split_to_width(available_width, line_is_empty);
let (left, right) = match (split, line_is_empty) {
(CannotSplit(_), _) => {
(CannotSplit, _) => {
error!("LineboxScanner: Tried to split unsplittable render box! {:s}",
in_box.debug_str());
return false
@ -418,8 +414,8 @@ impl LineboxScanner {
true
}
// An unconditional push.
fn push_box_to_line(&mut self, box: @Box) {
// An unconditional push
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 {
@ -440,7 +436,7 @@ pub struct InlineFlow {
base: FlowData,
/// A vector of all inline render boxes. Several boxes may correspond to one node/element.
boxes: ~[@Box],
boxes: ~[~Box],
// vec of ranges into boxes that represents line positions.
// these ranges are disjoint, and are the result of inline layout.
@ -462,7 +458,7 @@ impl InlineFlow {
}
}
pub fn from_boxes(base: FlowData, boxes: ~[@Box]) -> InlineFlow {
pub fn from_boxes(base: FlowData, boxes: ~[~Box]) -> InlineFlow {
InlineFlow {
base: base,
boxes: boxes,
@ -516,7 +512,7 @@ impl InlineFlow {
///
/// The extra boolean is set if and only if `biggest_top` and/or `biggest_bottom` were updated.
/// That is, if the box has a `top` or `bottom` value, true is returned.
fn relative_offset_from_baseline(cur_box: @Box,
fn relative_offset_from_baseline(cur_box: &Box,
ascent: Au,
parent_text_top: Au,
parent_text_bottom: Au,
@ -583,7 +579,7 @@ impl InlineFlow {
}
/// Sets box X positions based on alignment for one line.
fn set_horizontal_box_positions(boxes: &[@Box], line: &LineBox) {
fn set_horizontal_box_positions(boxes: &[~Box], line: &LineBox) {
// Figure out how much width we have.
let slack_width = Au::max(Au(0), line.green_zone.width - line.bounds.size.width);
@ -592,7 +588,7 @@ impl InlineFlow {
// TODO(burg, 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() < boxes.len() {
let first_box = boxes[line.range.begin()];
let first_box = &boxes[line.range.begin()];
first_box.nearest_ancestor_element().style().Text.text_align
} else {
// Nothing to lay out, so assume left alignment.
@ -668,7 +664,7 @@ impl Flow for InlineFlow {
debug!("assign_widths_inline: floats_in: {:?}", self.base.floats_in);
{
let this = &mut *self;
for &box in this.boxes.iter() {
for box in this.boxes.iter() {
box.assign_width();
}
}
@ -732,12 +728,12 @@ impl Flow for InlineFlow {
let (mut biggest_top, mut biggest_bottom) = (Au(0), Au(0));
for box_i in line.range.eachi() {
let cur_box = self.boxes[box_i];
let cur_box = &self.boxes[box_i];
// 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);
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.
@ -765,13 +761,13 @@ impl Flow for InlineFlow {
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 text_bounds = run.get().metrics_for_range(range).bounding_box;
let em_size = text_bounds.size.height;
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'
let text_ascent = text_box.run.font_metrics.ascent;
let text_ascent = text_box.run.get().font_metrics.ascent;
// 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);
@ -818,7 +814,7 @@ impl Flow for InlineFlow {
// updated or not. That is, if the box has a `top` or `bottom` value,
// `no_update_flag` becomes true.
let (offset, no_update_flag) =
InlineFlow::relative_offset_from_baseline(cur_box,
InlineFlow::relative_offset_from_baseline(*cur_box,
ascent,
parent_text_top,
parent_text_bottom,
@ -858,7 +854,7 @@ 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 = &self.boxes[box_i];
let adjust_offset = match cur_box.vertical_align() {
vertical_align::top => Au::new(0),
vertical_align::bottom => baseline_offset + bottommost,

View file

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Text layout.
use extra::arc::Arc;
use layout::box::{Box, ScannedTextBox, ScannedTextBoxInfo, UnscannedTextBox};
use layout::context::LayoutContext;
use layout::flow::Flow;
@ -56,7 +56,7 @@ impl TextRunScanner {
flow.as_inline().boxes = out_boxes;
// A helper function.
fn can_coalesce_text_nodes(boxes: &[@Box], 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);
@ -78,17 +78,17 @@ impl TextRunScanner {
ctx: &LayoutContext,
flow: &mut Flow,
last_whitespace: bool,
out_boxes: &mut ~[@Box])
out_boxes: &mut ~[~Box])
-> bool {
let inline = flow.as_inline();
let in_boxes = &inline.boxes;
let in_boxes = &mut inline.boxes;
assert!(self.clump.length() > 0);
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 = match possible_text_clump.specific {
let is_text_clump = match in_boxes[self.clump.begin()].specific {
UnscannedTextBox(_) => true,
_ => false,
};
@ -100,10 +100,12 @@ impl TextRunScanner {
}
(true, false) => {
debug!("TextRunScanner: pushing single non-text box in range: {}", self.clump);
out_boxes.push(in_boxes[self.clump.begin()]);
// out_boxes.push(in_boxes[self.clump.begin()]);
let first_box = in_boxes.remove(self.clump.begin());
out_boxes.push(first_box);
},
(true, true) => {
let old_box = in_boxes[self.clump.begin()];
let old_box = &in_boxes[self.clump.begin()];
let text = match old_box.specific {
UnscannedTextBox(ref text_box_info) => &text_box_info.text,
_ => fail!("Expected an unscanned text box!"),
@ -125,15 +127,15 @@ 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 fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
let run = @fontgroup.with_borrow(|fg| fg.create_textrun(transformed_text.clone(), decoration));
let run = ~fontgroup.with_borrow(|fg| fg.create_textrun(transformed_text.clone(), decoration));
debug!("TextRunScanner: pushing single text box in range: {} ({})",
self.clump,
*text);
let range = Range::new(0, run.char_len());
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,
let new_text_box_info = ScannedTextBoxInfo::new(Arc::new(run), range);
let new_box = ~old_box.transform(new_metrics.bounding_box.size,
ScannedTextBox(new_text_box_info));
out_boxes.push(new_box)
}
@ -179,7 +181,7 @@ impl TextRunScanner {
// TODO(#177): Text run creation must account for the renderability of text by
// 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 in_box = &in_boxes[self.clump.begin()];
let font_style = in_box.font_style();
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
let decoration = in_box.text_decoration();
@ -190,7 +192,7 @@ impl TextRunScanner {
let run = if clump.length() != 0 && run_str.len() > 0 {
fontgroup.with_borrow( |fg| {
fg.fonts[0].with_mut_borrow( |font| {
Some(@TextRun::new(font, run_str.clone(), decoration))
Some(Arc::new(~TextRun::new(font, run_str.clone(), decoration)))
})
})
} else {
@ -208,9 +210,9 @@ impl TextRunScanner {
continue
}
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,
let new_text_box_info = ScannedTextBoxInfo::new(run.get_ref().clone(), range);
let new_metrics = new_text_box_info.run.get().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)
}

View file

@ -56,7 +56,7 @@ impl ElementMapping {
self.entries.iter().enumerate()
}
pub fn repair_for_box_changes(&mut self, old_boxes: &[@Box], new_boxes: &[@Box]) {
pub fn repair_for_box_changes(&mut self, old_boxes: &[~Box], new_boxes: &[~Box]) {
let entries = &mut self.entries;
debug!("--- Old boxes: ---");

View file

@ -17,6 +17,7 @@ use extra::arc::{Arc, MutexArc};
/// A struct to store image data. The image will be loaded once the first time it is requested,
/// and an Arc will be stored. Clones of this Arc are given out on demand.
#[deriving(Clone)]
pub struct ImageHolder {
url: Url,
image: Option<Arc<~Image>>,