aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/main/layout/block.rs19
-rw-r--r--src/components/main/layout/box.rs24
-rw-r--r--src/components/main/layout/display_list_builder.rs14
-rw-r--r--src/components/main/layout/flow.rs29
-rw-r--r--src/components/main/layout/inline.rs24
-rw-r--r--src/components/main/layout/layout_task.rs96
-rw-r--r--src/components/main/layout/util.rs33
-rw-r--r--src/components/main/pipeline.rs10
-rw-r--r--src/components/style/properties.rs.mako2
9 files changed, 160 insertions, 91 deletions
diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs
index 7171887378e..ff85f4e14ad 100644
--- a/src/components/main/layout/block.rs
+++ b/src/components/main/layout/block.rs
@@ -585,11 +585,13 @@ impl Flow for BlockFlow {
/// Dual boxes consume some width first, and the remainder is assigned to all child (block)
/// contexts.
fn assign_widths(&mut self, ctx: &mut LayoutContext) {
- if self.is_float() {
- debug!("assign_widths_float: assigning width for flow {}", self.base.id);
- } else {
- debug!("assign_widths_block: assigning width for flow {}", self.base.id);
- }
+ debug!("assign_widths({}): assigning width for flow {}",
+ if self.is_float() {
+ "float"
+ } else {
+ "block"
+ },
+ self.base.id);
if self.is_root {
debug!("Setting root position");
@@ -613,6 +615,9 @@ impl Flow for BlockFlow {
for box in self.box.iter() {
let style = box.style();
+ // The text alignment of a block flow is the text alignment of its box's style.
+ self.base.flags.set_text_align(style.Text.text_align);
+
// Can compute padding here since we know containing block width.
box.compute_padding(style, remaining_width);
@@ -672,7 +677,9 @@ impl Flow for BlockFlow {
// Per CSS 2.1 § 16.3.1, text decoration propagates to all children in flow.
//
// TODO(pcwalton): When we have out-of-flow children, don't unconditionally propagate.
- child_base.flags.propagate_text_decoration_from_parent(self.base.flags)
+ child_base.flags.propagate_text_decoration_from_parent(self.base.flags);
+
+ child_base.flags.propagate_text_alignment_from_parent(self.base.flags)
}
}
diff --git a/src/components/main/layout/box.rs b/src/components/main/layout/box.rs
index 79293d85730..0479892f280 100644
--- a/src/components/main/layout/box.rs
+++ b/src/components/main/layout/box.rs
@@ -40,6 +40,7 @@ use layout::float_context::{ClearType, ClearLeft, ClearRight, ClearBoth};
use layout::flow::Flow;
use layout::flow;
use layout::model::{MaybeAuto, specified};
+use layout::util::OpaqueNode;
/// Boxes (`struct Box`) are the leaves of the layout tree. They cannot position themselves. In
/// general, boxes do not have a simple correspondence with CSS boxes in the specification:
@@ -63,8 +64,8 @@ use layout::model::{MaybeAuto, specified};
/// 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>,
+ /// An opaque reference to the DOM node that this `Box` originates from.
+ node: OpaqueNode,
/// The CSS style of this box.
style: Arc<ComputedValues>,
@@ -250,7 +251,7 @@ impl Box {
}
Box {
- node: node,
+ node: OpaqueNode::from_node(&node),
style: (*nearest_ancestor_element.style()).clone(),
position: Slot::init(Au::zero_rect()),
border: Slot::init(Zero::zero()),
@@ -284,9 +285,12 @@ impl Box {
}
}
+ /// Returns the shared part of the width for computation of minimum and preferred width per
+ /// CSS 2.1.
fn guess_width(&self) -> Au {
- if !self.node.is_element() {
- return Au(0)
+ match self.specific {
+ GenericBox | IframeBox(_) | ImageBox(_) => {}
+ ScannedTextBox(_) | UnscannedTextBox(_) => return Au(0),
}
let style = self.style();
@@ -921,9 +925,8 @@ impl Box {
let left_box = if left_range.length() > 0 {
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)
+ Some(self.transform(new_metrics.bounding_box.size,
+ ScannedTextBox(new_text_box_info)))
} else {
None
};
@@ -931,9 +934,8 @@ impl Box {
let right_box = right_range.map_default(None, |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)
+ Some(self.transform(new_metrics.bounding_box.size,
+ ScannedTextBox(new_text_box_info)))
});
if pieces_processed_count == 1 || left_box.is_none() {
diff --git a/src/components/main/layout/display_list_builder.rs b/src/components/main/layout/display_list_builder.rs
index d87e3c5d70d..7dd538d493d 100644
--- a/src/components/main/layout/display_list_builder.rs
+++ b/src/components/main/layout/display_list_builder.rs
@@ -6,26 +6,20 @@
use layout::box::Box;
use layout::context::LayoutContext;
-use std::cast::transmute;
-use script::dom::node::AbstractNode;
+use layout::util::OpaqueNode;
use gfx;
use style;
-/// Display list data is usually an AbstractNode with view () to indicate
-/// 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;
}
pub type Nothing = ();
-impl ExtraDisplayListData for AbstractNode<()> {
- fn new(box: &Box) -> AbstractNode<()> {
- unsafe {
- transmute(box.node)
- }
+impl ExtraDisplayListData for OpaqueNode {
+ fn new(box: &Box) -> OpaqueNode {
+ box.node
}
}
diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs
index 25d9d08e522..4b612286b30 100644
--- a/src/components/main/layout/flow.rs
+++ b/src/components/main/layout/flow.rs
@@ -44,6 +44,7 @@ use servo_util::geometry::Au;
use std::cast;
use std::cell::Cell;
use style::ComputedValues;
+use style::computed_values::text_align;
/// Virtual methods that make up a float context.
///
@@ -313,6 +314,16 @@ pub struct FlowFlags(u8);
/// NB: If you update this field, you must update the bitfields below.
static TEXT_DECORATION_OVERRIDE_BITMASK: u8 = 0b00001110;
+/// The bitmask of flags that represent the text alignment field.
+///
+/// NB: If you update this field, you must update the bitfields below.
+static TEXT_ALIGN_BITMASK: u8 = 0b00110000;
+
+/// The number of bits we must shift off to handle the text alignment field.
+///
+/// NB: If you update this field, you must update the bitfields below.
+static TEXT_ALIGN_SHIFT: u8 = 4;
+
impl FlowFlags {
/// Creates a new set of flow flags from the given style.
fn new(style: &ComputedValues) -> FlowFlags {
@@ -328,6 +339,11 @@ impl FlowFlags {
pub fn propagate_text_decoration_from_parent(&mut self, parent: FlowFlags) {
*self = FlowFlags(**self | (*parent & TEXT_DECORATION_OVERRIDE_BITMASK))
}
+
+ /// Propagates text alignment flags from an appropriate parent flow per CSS 2.1.
+ pub fn propagate_text_alignment_from_parent(&mut self, parent: FlowFlags) {
+ *self = FlowFlags(**self | (*parent & TEXT_ALIGN_BITMASK))
+ }
}
// Whether we need an in-order traversal.
@@ -348,6 +364,19 @@ bitfield!(FlowFlags, override_overline, set_override_overline, 0x04)
// NB: If you update this, you need to update TEXT_DECORATION_OVERRIDE_BITMASK.
bitfield!(FlowFlags, override_line_through, set_override_line_through, 0x08)
+// The text alignment for this flow.
+impl FlowFlags {
+ #[inline]
+ pub fn text_align(self) -> text_align::T {
+ FromPrimitive::from_u8((*self & TEXT_ALIGN_BITMASK) >> TEXT_ALIGN_SHIFT).unwrap()
+ }
+
+ #[inline]
+ pub fn set_text_align(&mut self, value: text_align::T) {
+ *self = FlowFlags((**self & !TEXT_ALIGN_BITMASK) | ((value as u8) << TEXT_ALIGN_SHIFT))
+ }
+}
+
/// Data common to all flows.
///
/// FIXME: We need a naming convention for pseudo-inheritance like this. How about
diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs
index 17603d7e52f..2f2eea797ff 100644
--- a/src/components/main/layout/inline.rs
+++ b/src/components/main/layout/inline.rs
@@ -17,13 +17,13 @@ use extra::container::Deque;
use extra::ringbuf::RingBuf;
use geom::{Point2D, Rect, Size2D};
use gfx::display_list::DisplayList;
-use style::computed_values::text_align;
-use style::computed_values::vertical_align;
use servo_util::geometry::Au;
use servo_util::range::Range;
use std::cell::Cell;
use std::u16;
use std::util;
+use style::computed_values::text_align;
+use style::computed_values::vertical_align;
/// Lineboxes are represented as offsets into the child list, rather than
/// as an object that "owns" boxes. Choosing a different set of line
@@ -644,7 +644,8 @@ impl Flow for InlineFlow {
//
// 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);
+ debug!("InlineFlow::assign_widths: floats_in: {:?}", self.base.floats_in);
+
{
let this = &mut *self;
for box in this.boxes.iter() {
@@ -656,6 +657,7 @@ impl Flow for InlineFlow {
let child_base = flow::mut_base(*kid);
child_base.position.size.width = self.base.position.size.width;
child_base.flags.set_inorder(self.base.flags.inorder());
+ child_base.flags.propagate_text_alignment_from_parent(self.base.flags)
}
// There are no child contexts, so stop here.
@@ -695,8 +697,8 @@ impl Flow for InlineFlow {
let mut line_height_offset = Au::new(0);
- // All lines use text alignment from base (non-inline) node
- let text_align = self.base.node.style().get().Text.text_align;
+ // All lines use text alignment of the flow.
+ let text_align = self.base.flags.text_align();
// Now, go through each line and lay out the boxes inside.
for line in self.lines.mut_iter() {
@@ -783,18 +785,16 @@ impl Flow for InlineFlow {
// parent's content area.
// We should calculate the distance from baseline to the top of parent's content
- // area. But for now we assume it's the parent's font size.
- let mut parent_text_top;
+ // area. But for now we assume it's the font size.
+ //
+ // The spec does not state which font to use. Previous versions of the code used
+ // the parent's font; this code uses the current font.
+ let parent_text_top = cur_box.style().Font.font_size;
// We should calculate the distance from baseline to the bottom of the parent's
// content area. But for now we assume it's zero.
let parent_text_bottom = Au::new(0);
- let parent = cur_box.node.parent_node().unwrap();
- let parent_style = parent.style();
- let font_size = parent_style.get().Font.font_size;
- parent_text_top = font_size;
-
// Calculate a relative offset from the baseline.
//
// The no-update flag decides whether `biggest_top` and `biggest_bottom` are
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index d6576e89d51..6d177ec34dd 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -16,7 +16,7 @@ use layout::flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, PreorderFlowTrave
use layout::flow::{PostorderFlowTraversal};
use layout::flow;
use layout::incremental::{RestyleDamage};
-use layout::util::{LayoutData, LayoutDataAccess};
+use layout::util::{LayoutData, LayoutDataAccess, OpaqueNode};
use extra::arc::{Arc, RWArc, MutexArc};
use geom::point::Point2D;
@@ -69,7 +69,7 @@ struct LayoutTask {
script_chan: ScriptChan,
/// The channel on which messages can be sent to the painting task.
- render_chan: RenderChan<AbstractNode<()>>,
+ render_chan: RenderChan<OpaqueNode>,
/// The channel on which messages can be sent to the image cache.
image_cache_task: ImageCacheTask,
@@ -81,7 +81,7 @@ struct LayoutTask {
screen_size: Option<Size2D<Au>>,
/// A cached display list.
- display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
+ display_list: Option<Arc<DisplayList<OpaqueNode>>>,
stylist: RWArc<Stylist>,
@@ -204,7 +204,7 @@ impl LayoutTask {
port: Port<Msg>,
constellation_chan: ConstellationChan,
script_chan: ScriptChan,
- render_chan: RenderChan<AbstractNode<()>>,
+ render_chan: RenderChan<OpaqueNode>,
img_cache_task: ImageCacheTask,
opts: Opts,
profiler_chan: ProfilerChan,
@@ -232,7 +232,7 @@ impl LayoutTask {
port: Port<Msg>,
constellation_chan: ConstellationChan,
script_chan: ScriptChan,
- render_chan: RenderChan<AbstractNode<()>>,
+ render_chan: RenderChan<OpaqueNode>,
image_cache_task: ImageCacheTask,
opts: &Opts,
profiler_chan: ProfilerChan)
@@ -478,34 +478,36 @@ impl LayoutTask {
if data.goal == ReflowForDisplay {
do profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone()) {
let root_size = flow::base(layout_root).position.size;
- let display_list= ~Cell::new(DisplayList::<AbstractNode<()>>::new());
+ let display_list = ~Cell::new(DisplayList::<OpaqueNode>::new());
let dirty = flow::base(layout_root).position.clone();
- layout_root.build_display_list(
- &DisplayListBuilder {
- ctx: &layout_ctx,
- },
- &dirty,
- display_list);
+ let display_list_builder = DisplayListBuilder {
+ ctx: &layout_ctx,
+ };
+ layout_root.build_display_list(&display_list_builder, &dirty, display_list);
let display_list = Arc::new(display_list.take());
- let mut color = color::rgba(255.0, 255.0, 255.0, 255.0);
-
- for child in node.traverse_preorder() {
- if child.type_id() == ElementNodeTypeId(HTMLHtmlElementTypeId) ||
- child.type_id() == ElementNodeTypeId(HTMLBodyElementTypeId) {
- let element_bg_color = child.style().get().resolve_color(
- child.style().get().Background.background_color
- ).to_gfx_color();
- match element_bg_color {
- color::rgba(0., 0., 0., 0.) => {}
- _ => {
- color = element_bg_color;
- break;
- }
- }
- }
+ let mut color = color::rgba(255.0, 255.0, 255.0, 255.0);
+
+ for child in node.traverse_preorder() {
+ if child.type_id() == ElementNodeTypeId(HTMLHtmlElementTypeId) ||
+ child.type_id() == ElementNodeTypeId(HTMLBodyElementTypeId) {
+ let element_bg_color = child.style()
+ .get()
+ .resolve_color(child.style()
+ .get()
+ .Background
+ .background_color)
+ .to_gfx_color();
+ match element_bg_color {
+ color::rgba(0., 0., 0., 0.) => {}
+ _ => {
+ color = element_bg_color;
+ break;
+ }
+ }
}
+ }
let render_layer = RenderLayer {
display_list: display_list.clone(),
@@ -532,16 +534,15 @@ impl LayoutTask {
/// `getClientRects()` or `getBoundingClientRect()` ultimately invoke.
fn handle_query(&self, query: LayoutQuery) {
match query {
+ // The neat thing here is that in order to answer the following two queries we only
+ // need to compare nodes for equality. Thus we can safely work only with `OpaqueNode`.
ContentBoxQuery(node, reply_chan) => {
- // FIXME: Isolate this transmutation into a single "bridge" module.
- let node: AbstractNode<()> = unsafe {
- transmute(node)
- };
+ let node = OpaqueNode::from_node(&node);
fn union_boxes_for_node<'a>(
accumulator: &mut Option<Rect<Au>>,
- mut iter: DisplayItemIterator<'a,AbstractNode<()>>,
- node: AbstractNode<()>) {
+ mut iter: DisplayItemIterator<'a,OpaqueNode>,
+ node: OpaqueNode) {
for item in iter {
union_boxes_for_node(accumulator, item.children(), node);
if item.base().extra == node {
@@ -559,15 +560,12 @@ impl LayoutTask {
reply_chan.send(ContentBoxResponse(rect.unwrap_or(Au::zero_rect())))
}
ContentBoxesQuery(node, reply_chan) => {
- // FIXME: Isolate this transmutation into a single "bridge" module.
- let node: AbstractNode<()> = unsafe {
- transmute(node)
- };
+ let node = OpaqueNode::from_node(&node);
fn add_boxes_for_node<'a>(
accumulator: &mut ~[Rect<Au>],
- mut iter: DisplayItemIterator<'a,AbstractNode<()>>,
- node: AbstractNode<()>) {
+ mut iter: DisplayItemIterator<'a,OpaqueNode>,
+ node: OpaqueNode) {
for item in iter {
add_boxes_for_node(accumulator, item.children(), node);
if item.base().extra == node {
@@ -582,7 +580,7 @@ impl LayoutTask {
reply_chan.send(ContentBoxesResponse(boxes))
}
HitTestQuery(_, point, reply_chan) => {
- fn hit_test(x: Au, y: Au, list: &[DisplayItem<AbstractNode<()>>])
+ fn hit_test(x: Au, y: Au, list: &[DisplayItem<OpaqueNode>])
-> Option<HitTestResponse> {
for item in list.rev_iter() {
match *item {
@@ -602,13 +600,19 @@ impl LayoutTask {
_ => {}
}
let bounds = item.bounds();
- // TODO this check should really be performed by a method of DisplayItem
+
+ // TODO(tikue): This check should really be performed by a method of
+ // DisplayItem.
if x < bounds.origin.x + bounds.size.width &&
- bounds.origin.x <= x &&
- y < bounds.origin.y + bounds.size.height &&
- bounds.origin.y <= y {
+ bounds.origin.x <= x &&
+ y < bounds.origin.y + bounds.size.height &&
+ bounds.origin.y <= y {
+ // FIXME(pcwalton): This `unsafe` block is too unsafe, since incorrect
+ // incremental flow construction could create this. Paranoid validation
+ // against the set of valid nodes should occur in the script task to
+ // ensure that this is a valid address instead of transmuting here.
let node: AbstractNode<LayoutView> = unsafe {
- transmute(item.base().extra)
+ item.base().extra.to_node()
};
let resp = Some(HitTestResponse(node));
return resp;
diff --git a/src/components/main/layout/util.rs b/src/components/main/layout/util.rs
index 9fb3257de24..712ba97ec54 100644
--- a/src/components/main/layout/util.rs
+++ b/src/components/main/layout/util.rs
@@ -12,6 +12,7 @@ use servo_util::slot::{MutSlotRef, SlotRef};
use servo_util::tree::TreeNodeRef;
use std::cast;
use std::iter::Enumerate;
+use std::libc::uintptr_t;
use std::vec::VecIterator;
use style::{ComputedValues, PropertyDeclaration};
@@ -182,3 +183,35 @@ impl LayoutDataAccess for AbstractNode<LayoutView> {
}
}
+/// An opaque handle to a node. The only safe operation that can be performed on this node is to
+/// compare it to another opaque handle or to another node.
+///
+/// Because the script task's GC does not trace layout, node data cannot be safely stored in layout
+/// data structures. Also, layout code tends to be faster when the DOM is not being accessed, for
+/// locality reasons. Using `OpaqueNode` enforces this invariant.
+#[deriving(Clone, Eq)]
+pub struct OpaqueNode(uintptr_t);
+
+impl<T> Equiv<AbstractNode<T>> for OpaqueNode {
+ fn equiv(&self, node: &AbstractNode<T>) -> bool {
+ unsafe {
+ **self == cast::transmute_copy::<AbstractNode<T>,uintptr_t>(node)
+ }
+ }
+}
+
+impl OpaqueNode {
+ /// Converts a DOM node to an `OpaqueNode`.
+ pub fn from_node<T>(node: &AbstractNode<T>) -> OpaqueNode {
+ unsafe {
+ OpaqueNode(cast::transmute_copy(node))
+ }
+ }
+
+ /// Unsafely converts an `OpaqueNode` to a DOM node. Use this only if you absolutely know what
+ /// you're doing.
+ pub unsafe fn to_node<T>(&self) -> AbstractNode<T> {
+ cast::transmute(**self)
+ }
+}
+
diff --git a/src/components/main/pipeline.rs b/src/components/main/pipeline.rs
index bd750df0357..b5f469598ca 100644
--- a/src/components/main/pipeline.rs
+++ b/src/components/main/pipeline.rs
@@ -9,7 +9,7 @@ use extra::url::Url;
use gfx::opts::Opts;
use gfx::render_task::{PaintPermissionGranted, PaintPermissionRevoked};
use gfx::render_task::{RenderChan, RenderTask};
-use script::dom::node::AbstractNode;
+use layout::util::OpaqueNode;
use script::layout_interface::LayoutChan;
use script::script_task::LoadMsg;
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
@@ -27,19 +27,19 @@ pub struct Pipeline {
subpage_id: Option<SubpageId>,
script_chan: ScriptChan,
layout_chan: LayoutChan,
- render_chan: RenderChan<AbstractNode<()>>,
+ render_chan: RenderChan<OpaqueNode>,
layout_shutdown_port: Port<()>,
render_shutdown_port: Port<()>,
/// The most recently loaded url
url: Option<Url>,
}
-/// A subset of the Pipeline nthat is eeded for layer composition
+/// The subset of the pipeline that is needed for layer composition.
#[deriving(Clone)]
pub struct CompositionPipeline {
id: PipelineId,
script_chan: ScriptChan,
- render_chan: RenderChan<AbstractNode<()>>,
+ render_chan: RenderChan<OpaqueNode>,
}
impl Pipeline {
@@ -182,7 +182,7 @@ impl Pipeline {
subpage_id: Option<SubpageId>,
script_chan: ScriptChan,
layout_chan: LayoutChan,
- render_chan: RenderChan<AbstractNode<()>>,
+ render_chan: RenderChan<OpaqueNode>,
layout_shutdown_port: Port<()>,
render_shutdown_port: Port<()>)
-> Pipeline {
diff --git a/src/components/style/properties.rs.mako b/src/components/style/properties.rs.mako
index ca0bcac6b0c..e8b10bc4669 100644
--- a/src/components/style/properties.rs.mako
+++ b/src/components/style/properties.rs.mako
@@ -106,7 +106,7 @@ pub mod longhands {
<%self:single_component_value name="${name}" inherited="${inherited}">
${caller.body()}
pub mod computed_value {
- #[deriving(Eq, Clone)]
+ #[deriving(Eq, Clone, FromPrimitive)]
pub enum T {
% for value in values.split():
${to_rust_ident(value)},