layout: Implement basic style sharing.

No improvement on the rainbow page, but necessary for some other
optimizations we want to do.
This commit is contained in:
Patrick Walton 2014-02-07 15:15:56 -08:00
parent cf8203848a
commit 1678cc9a88
16 changed files with 502 additions and 274 deletions

View file

@ -13,7 +13,7 @@ use layout::wrapper::LayoutNode;
use extra::arc::Arc; use extra::arc::Arc;
use script::layout_interface::LayoutChan; use script::layout_interface::LayoutChan;
use servo_util::smallvec::{SmallVec, SmallVec0, SmallVec16}; use servo_util::smallvec::{SmallVec, SmallVec0, SmallVec16};
use style::{After, Before, PropertyDeclaration, Stylist, TNode, cascade}; use style::{After, Before, ComputedValues, PropertyDeclaration, Stylist, TNode, cascade};
pub struct ApplicableDeclarations { pub struct ApplicableDeclarations {
normal: SmallVec16<Arc<~[PropertyDeclaration]>>, normal: SmallVec16<Arc<~[PropertyDeclaration]>>,
@ -43,12 +43,14 @@ pub trait MatchMethods {
stylist: &Stylist, stylist: &Stylist,
layout_chan: &LayoutChan, layout_chan: &LayoutChan,
applicable_declarations: &mut ApplicableDeclarations, applicable_declarations: &mut ApplicableDeclarations,
initial_values: &ComputedValues,
parent: Option<LayoutNode>); parent: Option<LayoutNode>);
fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations); fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations);
unsafe fn cascade_node(&self, unsafe fn cascade_node(&self,
parent: Option<LayoutNode>, parent: Option<LayoutNode>,
initial_values: &ComputedValues,
applicable_declarations: &ApplicableDeclarations); applicable_declarations: &ApplicableDeclarations);
} }
@ -79,6 +81,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
stylist: &Stylist, stylist: &Stylist,
layout_chan: &LayoutChan, layout_chan: &LayoutChan,
applicable_declarations: &mut ApplicableDeclarations, applicable_declarations: &mut ApplicableDeclarations,
initial_values: &ComputedValues,
parent: Option<LayoutNode>) { parent: Option<LayoutNode>) {
self.initialize_layout_data((*layout_chan).clone()); self.initialize_layout_data((*layout_chan).clone());
@ -87,7 +90,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
} }
unsafe { unsafe {
self.cascade_node(parent, applicable_declarations) self.cascade_node(parent, initial_values, applicable_declarations)
} }
applicable_declarations.clear(); applicable_declarations.clear();
@ -96,12 +99,14 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
kid.match_and_cascade_subtree(stylist, kid.match_and_cascade_subtree(stylist,
layout_chan, layout_chan,
applicable_declarations, applicable_declarations,
initial_values,
Some(*self)) Some(*self))
} }
} }
unsafe fn cascade_node(&self, unsafe fn cascade_node(&self,
parent: Option<LayoutNode>, parent: Option<LayoutNode>,
initial_values: &ComputedValues,
applicable_declarations: &ApplicableDeclarations) { applicable_declarations: &ApplicableDeclarations) {
macro_rules! cascade_node( macro_rules! cascade_node(
($applicable_declarations: expr, $style: ident) => {{ ($applicable_declarations: expr, $style: ident) => {{
@ -124,30 +129,33 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
} }
} }
} }
}; };
let computed_values = match parent_style { let computed_values = match parent_style {
Some(ref style) => { Some(ref style) => {
Arc::new(cascade($applicable_declarations.as_slice(), Arc::new(cascade($applicable_declarations.as_slice(),
Some(style.get()))) Some(style.get()),
} initial_values))
None => Arc::new(cascade($applicable_declarations.as_slice(), None)), }
}; None => Arc::new(cascade($applicable_declarations.as_slice(),
None,
let mut layout_data_ref = self.mutate_layout_data(); initial_values)),
match *layout_data_ref.get() { };
None => fail!("no layout data"),
Some(ref mut layout_data) => { let mut layout_data_ref = self.mutate_layout_data();
let style = &mut layout_data.data.$style; match *layout_data_ref.get() {
match *style { None => fail!("no layout data"),
None => (), Some(ref mut layout_data) => {
Some(ref previous_style) => { let style = &mut layout_data.data.$style;
layout_data.data.restyle_damage = Some(incremental::compute_damage( match *style {
previous_style.get(), computed_values.get()).to_int()) None => (),
} Some(ref previous_style) => {
} layout_data.data.restyle_damage = Some(incremental::compute_damage(
*style = Some(computed_values) previous_style.get(), computed_values.get()).to_int())
} }
}
*style = Some(computed_values)
}
} }
}} }}
); );

View file

@ -88,7 +88,12 @@ u, ins { text-decoration: underline }
br:before { content: "\A"; white-space: pre-line } br:before { content: "\A"; white-space: pre-line }
center { text-align: center } center { text-align: center }
:link, :visited { text-decoration: underline } a:link,
a:visited,
area:link,
area:visited,
link:link,
link:visited { text-decoration: underline }
:focus { outline: thin dotted invert } :focus { outline: thin dotted invert }
/* Begin bidirectionality settings (do not change) */ /* Begin bidirectionality settings (do not change) */
@ -106,6 +111,8 @@ ul, ol, dl { page-break-before: avoid }
} }
/* Servo additions */ /* Servo additions */
:link { color: blue } a:link,
area:link,
link:link { color: blue }
script { display: none } script { display: none }
style { display: none } style { display: none }

View file

@ -193,9 +193,9 @@ impl BlockFlow {
let style = box_.style(); let style = box_.style();
let (width, maybe_margin_left, maybe_margin_right) = let (width, maybe_margin_left, maybe_margin_right) =
(MaybeAuto::from_style(style.Box.width, remaining_width), (MaybeAuto::from_style(style.Box.get().width, remaining_width),
MaybeAuto::from_style(style.Margin.margin_left, remaining_width), MaybeAuto::from_style(style.Margin.get().margin_left, remaining_width),
MaybeAuto::from_style(style.Margin.margin_right, remaining_width)); MaybeAuto::from_style(style.Margin.get().margin_right, remaining_width));
let (width, margin_left, margin_right) = self.compute_horiz(width, let (width, margin_left, margin_right) = self.compute_horiz(width,
maybe_margin_left, maybe_margin_left,
@ -206,7 +206,7 @@ impl BlockFlow {
// If the tentative used width is greater than 'max-width', width should be recalculated, // If the tentative used width is greater than 'max-width', width should be recalculated,
// but this time using the computed value of 'max-width' as the computed value for 'width'. // but this time using the computed value of 'max-width' as the computed value for 'width'.
let (width, margin_left, margin_right) = { let (width, margin_left, margin_right) = {
match specified_or_none(style.Box.max_width, remaining_width) { match specified_or_none(style.Box.get().max_width, remaining_width) {
Some(value) if value < width => self.compute_horiz(Specified(value), Some(value) if value < width => self.compute_horiz(Specified(value),
maybe_margin_left, maybe_margin_left,
maybe_margin_right, maybe_margin_right,
@ -218,7 +218,7 @@ impl BlockFlow {
// If the resulting width is smaller than 'min-width', width should be recalculated, // If the resulting width is smaller than 'min-width', width should be recalculated,
// but this time using the value of 'min-width' as the computed value for 'width'. // but this time using the value of 'min-width' as the computed value for 'width'.
let (width, margin_left, margin_right) = { let (width, margin_left, margin_right) = {
let computed_min_width = specified(style.Box.min_width, remaining_width); let computed_min_width = specified(style.Box.get().min_width, remaining_width);
if computed_min_width > width { if computed_min_width > width {
self.compute_horiz(Specified(computed_min_width), self.compute_horiz(Specified(computed_min_width),
maybe_margin_left, maybe_margin_left,
@ -235,13 +235,13 @@ impl BlockFlow {
// CSS Section 10.3.5 // CSS Section 10.3.5
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 style = box_.style();
let margin_left = MaybeAuto::from_style(style.Margin.margin_left, let margin_left = MaybeAuto::from_style(style.Margin.get().margin_left,
remaining_width).specified_or_zero(); remaining_width).specified_or_zero();
let margin_right = MaybeAuto::from_style(style.Margin.margin_right, let margin_right = MaybeAuto::from_style(style.Margin.get().margin_right,
remaining_width).specified_or_zero(); remaining_width).specified_or_zero();
let shrink_to_fit = geometry::min(self.base.pref_width, let shrink_to_fit = geometry::min(self.base.pref_width,
geometry::max(self.base.min_width, remaining_width)); geometry::max(self.base.min_width, remaining_width));
let width = MaybeAuto::from_style(style.Box.width, let width = MaybeAuto::from_style(style.Box.get().width,
remaining_width).specified_or_default(shrink_to_fit); remaining_width).specified_or_default(shrink_to_fit);
debug!("assign_widths_float -- width: {}", width); debug!("assign_widths_float -- width: {}", width);
return (width, margin_left, margin_right); return (width, margin_left, margin_right);
@ -376,7 +376,7 @@ impl BlockFlow {
// block per CSS 2.1 § 10.5. // block per CSS 2.1 § 10.5.
// TODO: We need to pass in the correct containing block height // TODO: We need to pass in the correct containing block height
// for absolutely positioned elems // for absolutely positioned elems
height = match MaybeAuto::from_style(style.Box.height, height) { height = match MaybeAuto::from_style(style.Box.get().height, height) {
Auto => height, Auto => height,
Specified(value) => value Specified(value) => value
}; };
@ -516,7 +516,7 @@ impl BlockFlow {
box_.border.get().top + box_.border.get().bottom; box_.border.get().top + box_.border.get().bottom;
//TODO(eatkinson): compute heights properly using the 'height' property. //TODO(eatkinson): compute heights properly using the 'height' property.
let height_prop = MaybeAuto::from_style(box_.style().Box.height, let height_prop = MaybeAuto::from_style(box_.style().Box.get().height,
Au::new(0)).specified_or_zero(); Au::new(0)).specified_or_zero();
height = geometry::max(height, height_prop) + noncontent_height; height = geometry::max(height, height_prop) + noncontent_height;
@ -719,7 +719,7 @@ impl Flow for BlockFlow {
let style = box_.style(); let style = box_.style();
// The text alignment of a block flow is the text alignment of its box's style. // The text alignment of a block flow is the text alignment of its box's style.
self.base.flags_info.flags.set_text_align(style.InheritedText.text_align); self.base.flags_info.flags.set_text_align(style.InheritedText.get().text_align);
box_.assign_width(remaining_width); box_.assign_width(remaining_width);
// Can compute padding here since we know containing block width. // Can compute padding here since we know containing block width.
@ -729,9 +729,9 @@ impl Flow for BlockFlow {
let available_width = remaining_width - box_.noncontent_width(); let available_width = remaining_width - box_.noncontent_width();
// Top and bottom margins for blocks are 0 if auto. // Top and bottom margins for blocks are 0 if auto.
let margin_top = MaybeAuto::from_style(style.Margin.margin_top, let margin_top = MaybeAuto::from_style(style.Margin.get().margin_top,
remaining_width).specified_or_zero(); remaining_width).specified_or_zero();
let margin_bottom = MaybeAuto::from_style(style.Margin.margin_bottom, let margin_bottom = MaybeAuto::from_style(style.Margin.get().margin_bottom,
remaining_width).specified_or_zero(); remaining_width).specified_or_zero();
let (width, margin_left, margin_right) = if self.is_float() { let (width, margin_left, margin_right) = if self.is_float() {

View file

@ -373,7 +373,7 @@ impl Box {
} }
(_, _) => { (_, _) => {
y = position_offsets.top; y = position_offsets.top;
match MaybeAuto::from_style(self.style().Box.height, Au(0)) { match MaybeAuto::from_style(self.style().Box.get().height, Au(0)) {
Auto => { Auto => {
height = screen_height - position_offsets.top - position_offsets.bottom; height = screen_height - position_offsets.top - position_offsets.bottom;
} }
@ -408,7 +408,7 @@ impl Box {
} }
(_, _) => { (_, _) => {
x = position_offsets.left; x = position_offsets.left;
match MaybeAuto::from_style(self.style().Box.width, Au(0)) { match MaybeAuto::from_style(self.style().Box.get().width, Au(0)) {
Auto => { Auto => {
width = screen_width - position_offsets.left - position_offsets.right; width = screen_width - position_offsets.left - position_offsets.right;
} }
@ -446,14 +446,14 @@ impl Box {
} }
let style = self.style(); let style = self.style();
let width = MaybeAuto::from_style(style.Box.width, Au::new(0)).specified_or_zero(); let width = MaybeAuto::from_style(style.Box.get().width, Au::new(0)).specified_or_zero();
let margin_left = MaybeAuto::from_style(style.Margin.margin_left, let margin_left = MaybeAuto::from_style(style.Margin.get().margin_left,
Au::new(0)).specified_or_zero(); Au::new(0)).specified_or_zero();
let margin_right = MaybeAuto::from_style(style.Margin.margin_right, let margin_right = MaybeAuto::from_style(style.Margin.get().margin_right,
Au::new(0)).specified_or_zero(); Au::new(0)).specified_or_zero();
let padding_left = self.compute_padding_length(style.Padding.padding_left, Au::new(0)); let padding_left = self.compute_padding_length(style.Padding.get().padding_left, Au(0));
let padding_right = self.compute_padding_length(style.Padding.padding_right, Au::new(0)); let padding_right = self.compute_padding_length(style.Padding.get().padding_right, Au(0));
width + margin_left + margin_right + padding_left + padding_right + width + margin_left + margin_right + padding_left + padding_right +
self.border.get().left + self.border.get().right self.border.get().left + self.border.get().right
@ -480,37 +480,45 @@ impl Box {
} }
} }
self.border.set(SideOffsets2D::new(width(style.Border.border_top_width, self.border.set(SideOffsets2D::new(width(style.Border.get().border_top_width,
style.Border.border_top_style), style.Border.get().border_top_style),
width(style.Border.border_right_width, width(style.Border.get().border_right_width,
style.Border.border_right_style), style.Border.get().border_right_style),
width(style.Border.border_bottom_width, width(style.Border.get().border_bottom_width,
style.Border.border_bottom_style), style.Border.get().border_bottom_style),
width(style.Border.border_left_width, width(style.Border.get().border_left_width,
style.Border.border_left_style))) style.Border.get().border_left_style)))
} }
pub fn compute_positioned_offsets(&self, style: &ComputedValues, containing_width: Au, containing_height: Au) { pub fn compute_positioned_offsets(&self, style: &ComputedValues, containing_width: Au, containing_height: Au) {
self.position_offsets.set(SideOffsets2D::new( self.position_offsets.set(SideOffsets2D::new(
MaybeAuto::from_style(style.PositionOffsets.top, containing_height) MaybeAuto::from_style(style.PositionOffsets.get().top, containing_height)
.specified_or_zero(), .specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.right, containing_width) MaybeAuto::from_style(style.PositionOffsets.get().right, containing_width)
.specified_or_zero(), .specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.bottom, containing_height) MaybeAuto::from_style(style.PositionOffsets.get().bottom, containing_height)
.specified_or_zero(), .specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.left, containing_width) MaybeAuto::from_style(style.PositionOffsets.get().left, containing_width)
.specified_or_zero())); .specified_or_zero()));
} }
/// Populates the box model padding parameters from the given computed style. /// Populates the box model padding parameters from the given computed style.
pub fn compute_padding(&self, style: &ComputedValues, containing_block_width: Au) { pub fn compute_padding(&self, style: &ComputedValues, containing_block_width: Au) {
let padding = SideOffsets2D::new(self.compute_padding_length(style.Padding.padding_top, let padding = SideOffsets2D::new(self.compute_padding_length(style.Padding
.get()
.padding_top,
containing_block_width), containing_block_width),
self.compute_padding_length(style.Padding.padding_right, self.compute_padding_length(style.Padding
.get()
.padding_right,
containing_block_width), containing_block_width),
self.compute_padding_length(style.Padding.padding_bottom, self.compute_padding_length(style.Padding
.get()
.padding_bottom,
containing_block_width), containing_block_width),
self.compute_padding_length(style.Padding.padding_left, self.compute_padding_length(style.Padding
.get()
.padding_left,
containing_block_width)); containing_block_width));
self.padding.set(padding) self.padding.set(padding)
} }
@ -679,28 +687,28 @@ impl Box {
} }
} }
pub fn relative_position(&self, container_block_size: &Size2D<Au>) -> Point2D<Au> { pub fn relative_position(&self, container_block_size: &Size2D<Au>) -> Point2D<Au> {
fn left_right(style: &ComputedValues,block_width: Au) -> Au { fn left_right(style: &ComputedValues, block_width: Au) -> Au {
// TODO(ksh8281) : consider RTL(right-to-left) culture // TODO(ksh8281) : consider RTL(right-to-left) culture
match (style.PositionOffsets.left, style.PositionOffsets.right) { match (style.PositionOffsets.get().left, style.PositionOffsets.get().right) {
(LPA_Auto, _) => { (LPA_Auto, _) => {
-MaybeAuto::from_style(style.PositionOffsets.right, block_width) -MaybeAuto::from_style(style.PositionOffsets.get().right, block_width)
.specified_or_zero() .specified_or_zero()
} }
(_, _) => { (_, _) => {
MaybeAuto::from_style(style.PositionOffsets.left, block_width) MaybeAuto::from_style(style.PositionOffsets.get().left, block_width)
.specified_or_zero() .specified_or_zero()
} }
} }
} }
fn top_bottom(style: &ComputedValues,block_height: Au) -> Au { fn top_bottom(style: &ComputedValues,block_height: Au) -> Au {
match (style.PositionOffsets.top, style.PositionOffsets.bottom) { match (style.PositionOffsets.get().top, style.PositionOffsets.get().bottom) {
(LPA_Auto, _) => { (LPA_Auto, _) => {
-MaybeAuto::from_style(style.PositionOffsets.bottom, block_height) -MaybeAuto::from_style(style.PositionOffsets.get().bottom, block_height)
.specified_or_zero() .specified_or_zero()
} }
(_, _) => { (_, _) => {
MaybeAuto::from_style(style.PositionOffsets.top, block_height) MaybeAuto::from_style(style.PositionOffsets.get().top, block_height)
.specified_or_zero() .specified_or_zero()
} }
} }
@ -711,7 +719,7 @@ impl Box {
y: Au::new(0), y: Au::new(0),
}; };
if self.style().Box.position == position::relative { if self.style().Box.get().position == position::relative {
rel_pos.x = rel_pos.x + left_right(self.style(), container_block_size.width); rel_pos.x = rel_pos.x + left_right(self.style(), container_block_size.width);
rel_pos.y = rel_pos.y + top_bottom(self.style(), container_block_size.height); rel_pos.y = rel_pos.y + top_bottom(self.style(), container_block_size.height);
} }
@ -720,9 +728,11 @@ impl Box {
match info.get() { match info.get() {
&Some(ref info) => { &Some(ref info) => {
for info in info.parent_info.iter() { for info in info.parent_info.iter() {
if info.style.get().Box.position == position::relative { if info.style.get().Box.get().position == position::relative {
rel_pos.x = rel_pos.x + left_right(info.style.get(), container_block_size.width); rel_pos.x = rel_pos.x + left_right(info.style.get(),
rel_pos.y = rel_pos.y + top_bottom(info.style.get(), container_block_size.height); container_block_size.width);
rel_pos.y = rel_pos.y + top_bottom(info.style.get(),
container_block_size.height);
} }
} }
}, },
@ -737,7 +747,7 @@ impl Box {
#[inline(always)] #[inline(always)]
pub fn clear(&self) -> Option<ClearType> { pub fn clear(&self) -> Option<ClearType> {
let style = self.style(); let style = self.style();
match style.Box.clear { match style.Box.get().clear {
clear::none => None, clear::none => None,
clear::left => Some(ClearLeft), clear::left => Some(ClearLeft),
clear::right => Some(ClearRight), clear::right => Some(ClearRight),
@ -755,20 +765,20 @@ impl Box {
debug!("(font style) start"); debug!("(font style) start");
// FIXME: Too much allocation here. // FIXME: Too much allocation here.
let font_families = my_style.Font.font_family.map(|family| { let font_families = my_style.Font.get().font_family.map(|family| {
match *family { match *family {
font_family::FamilyName(ref name) => (*name).clone(), font_family::FamilyName(ref name) => (*name).clone(),
} }
}); });
debug!("(font style) font families: `{:?}`", font_families); debug!("(font style) font families: `{:?}`", font_families);
let font_size = my_style.Font.font_size.to_f64().unwrap() / 60.0; let font_size = my_style.Font.get().font_size.to_f64().unwrap() / 60.0;
debug!("(font style) font size: `{:f}px`", font_size); debug!("(font style) font size: `{:f}px`", font_size);
FontStyle { FontStyle {
pt_size: font_size, pt_size: font_size,
weight: my_style.Font.font_weight, weight: my_style.Font.get().font_weight,
style: my_style.Font.font_style, style: my_style.Font.get().font_style,
families: font_families, families: font_families,
} }
} }
@ -781,19 +791,19 @@ impl Box {
/// Returns the text alignment of the computed style of the nearest ancestor-or-self `Element` /// Returns the text alignment of the computed style of the nearest ancestor-or-self `Element`
/// node. /// node.
pub fn text_align(&self) -> text_align::T { pub fn text_align(&self) -> text_align::T {
self.style().InheritedText.text_align self.style().InheritedText.get().text_align
} }
pub fn line_height(&self) -> line_height::T { pub fn line_height(&self) -> line_height::T {
self.style().InheritedBox.line_height self.style().InheritedBox.get().line_height
} }
pub fn vertical_align(&self) -> vertical_align::T { pub fn vertical_align(&self) -> vertical_align::T {
self.style().Box.vertical_align self.style().Box.get().vertical_align
} }
pub fn white_space(&self) -> white_space::T { pub fn white_space(&self) -> white_space::T {
self.style().InheritedText.white_space self.style().InheritedText.get().white_space
} }
/// Returns the text decoration of this box, according to the style of the nearest ancestor /// Returns the text decoration of this box, according to the style of the nearest ancestor
@ -804,7 +814,7 @@ impl Box {
/// model. Therefore, this is a best lower bound approximation, but the end result may actually /// model. Therefore, this is a best lower bound approximation, but the end result may actually
/// have the various decoration flags turned on afterward. /// have the various decoration flags turned on afterward.
pub fn text_decoration(&self) -> text_decoration::T { pub fn text_decoration(&self) -> text_decoration::T {
self.style().Text.text_decoration self.style().Text.get().text_decoration
} }
/// Returns the sum of margin, border, and padding on the left. /// Returns the sum of margin, border, and padding on the left.
@ -862,7 +872,7 @@ impl Box {
bg_rect.origin.y = box_info.baseline + offset.y - info.font_ascent; bg_rect.origin.y = box_info.baseline + offset.y - info.font_ascent;
bg_rect.size.height = info.font_ascent + info.font_descent; bg_rect.size.height = info.font_ascent + info.font_descent;
let background_color = info.style.get().resolve_color( let background_color = info.style.get().resolve_color(
info.style.get().Background.background_color); info.style.get().Background.get().background_color);
if !background_color.alpha.approx_eq(&0.0) { if !background_color.alpha.approx_eq(&0.0) {
lists.with_mut(|lists| { lists.with_mut(|lists| {
@ -886,14 +896,14 @@ impl Box {
bg_rect.size.height = bg_rect.size.height + border.top + border.bottom; bg_rect.size.height = bg_rect.size.height + border.top + border.bottom;
let style = info.style.get(); let style = info.style.get();
let top_color = style.resolve_color(style.Border.border_top_color); let top_color = style.resolve_color(style.Border.get().border_top_color);
let right_color = style.resolve_color(style.Border.border_right_color); let right_color = style.resolve_color(style.Border.get().border_right_color);
let bottom_color = style.resolve_color(style.Border.border_bottom_color); let bottom_color = style.resolve_color(style.Border.get().border_bottom_color);
let left_color = style.resolve_color(style.Border.border_left_color); let left_color = style.resolve_color(style.Border.get().border_left_color);
let top_style = style.Border.border_top_style; let top_style = style.Border.get().border_top_style;
let right_style = style.Border.border_right_style; let right_style = style.Border.get().border_right_style;
let bottom_style = style.Border.border_bottom_style; let bottom_style = style.Border.get().border_bottom_style;
let left_style = style.Border.border_left_style; let left_style = style.Border.get().border_left_style;
lists.with_mut(|lists| { lists.with_mut(|lists| {
@ -935,7 +945,7 @@ impl Box {
// inefficient. What we really want is something like "nearest ancestor element that // inefficient. What we really want is something like "nearest ancestor element that
// doesn't have a box". // doesn't have a box".
let style = self.style(); let style = self.style();
let background_color = style.resolve_color(style.Background.background_color); let background_color = style.resolve_color(style.Background.get().background_color);
if !background_color.alpha.approx_eq(&0.0) { if !background_color.alpha.approx_eq(&0.0) {
lists.with_mut(|lists| { lists.with_mut(|lists| {
let solid_color_display_item = ~SolidColorDisplayItem { let solid_color_display_item = ~SolidColorDisplayItem {
@ -965,14 +975,14 @@ impl Box {
} }
let style = self.style(); let style = self.style();
let top_color = style.resolve_color(style.Border.border_top_color); let top_color = style.resolve_color(style.Border.get().border_top_color);
let right_color = style.resolve_color(style.Border.border_right_color); let right_color = style.resolve_color(style.Border.get().border_right_color);
let bottom_color = style.resolve_color(style.Border.border_bottom_color); let bottom_color = style.resolve_color(style.Border.get().border_bottom_color);
let left_color = style.resolve_color(style.Border.border_left_color); let left_color = style.resolve_color(style.Border.get().border_left_color);
let top_style = style.Border.border_top_style; let top_style = style.Border.get().border_top_style;
let right_style = style.Border.border_right_style; let right_style = style.Border.get().border_right_style;
let bottom_style = style.Border.border_bottom_style; let bottom_style = style.Border.get().border_bottom_style;
let left_style = style.Border.border_left_style; let left_style = style.Border.get().border_left_style;
let mut abs_bounds = abs_bounds.clone(); let mut abs_bounds = abs_bounds.clone();
abs_bounds.origin.x = abs_bounds.origin.x + self.noncontent_inline_left(); abs_bounds.origin.x = abs_bounds.origin.x + self.noncontent_inline_left();
@ -1029,7 +1039,7 @@ impl Box {
box_bounds, absolute_box_bounds, self.debug_str()); box_bounds, absolute_box_bounds, self.debug_str());
debug!("Box::build_display_list: dirty={}, offset={}", *dirty, offset); debug!("Box::build_display_list: dirty={}, offset={}", *dirty, offset);
if self.style().InheritedBox.visibility != visibility::visible { if self.style().InheritedBox.get().visibility != visibility::visible {
return; return;
} }
@ -1047,7 +1057,7 @@ impl Box {
match self.specific { match self.specific {
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."), UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
ScannedTextBox(ref text_box) => { ScannedTextBox(ref text_box) => {
let text_color = self.style().Color.color.to_gfx_color(); let text_color = self.style().Color.get().color.to_gfx_color();
// Set the various text display item flags. // Set the various text display item flags.
let mut flow_flags = flow::base(flow).flags_info.clone(); let mut flow_flags = flow::base(flow).flags_info.clone();
@ -1472,13 +1482,13 @@ impl Box {
} }
ImageBox(ref image_box_info) => { ImageBox(ref image_box_info) => {
// TODO(ksh8281): compute border,margin,padding // TODO(ksh8281): compute border,margin,padding
let width = ImageBoxInfo::style_length(self.style().Box.width, let width = ImageBoxInfo::style_length(self.style().Box.get().width,
image_box_info.dom_width, image_box_info.dom_width,
container_width); container_width);
// FIXME(ksh8281): we shouldn't figure height this way // FIXME(ksh8281): we shouldn't figure height this way
// now, we don't know about size of parent's height // now, we don't know about size of parent's height
let height = ImageBoxInfo::style_length(self.style().Box.height, let height = ImageBoxInfo::style_length(self.style().Box.get().height,
image_box_info.dom_height, image_box_info.dom_height,
Au::new(0)); Au::new(0));
@ -1520,11 +1530,11 @@ impl Box {
let width = image_box_info.computed_width(); let width = image_box_info.computed_width();
// FIXME(ksh8281): we shouldn't assign height this way // FIXME(ksh8281): we shouldn't assign height this way
// we don't know about size of parent's height // we don't know about size of parent's height
let height = ImageBoxInfo::style_length(self.style().Box.height, let height = ImageBoxInfo::style_length(self.style().Box.get().height,
image_box_info.dom_height, image_box_info.dom_height,
Au::new(0)); Au::new(0));
let height = match (self.style().Box.width, let height = match (self.style().Box.get().width,
image_box_info.dom_width, image_box_info.dom_width,
height) { height) {
(LPA_Auto, None, Auto) => { (LPA_Auto, None, Auto) => {
@ -1575,7 +1585,7 @@ impl Box {
/// Returns true if the contents should be clipped (i.e. if `overflow` is `hidden`). /// Returns true if the contents should be clipped (i.e. if `overflow` is `hidden`).
pub fn needs_clip(&self) -> bool { pub fn needs_clip(&self) -> bool {
self.style().Box.overflow == overflow::hidden self.style().Box.get().overflow == overflow::hidden
} }
/// Returns a debugging string describing this box. /// Returns a debugging string describing this box.

View file

@ -628,7 +628,7 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
let (display, float, position) = match node.type_id() { let (display, float, position) = match node.type_id() {
ElementNodeTypeId(_) => { ElementNodeTypeId(_) => {
let style = node.style().get(); let style = node.style().get();
(style.Box.display, style.Box.float, style.Box.position) (style.Box.get().display, style.Box.get().float, style.Box.get().position)
} }
TextNodeTypeId => (display::inline, float::none, position::static_), TextNodeTypeId => (display::inline, float::none, position::static_),
CommentNodeTypeId | CommentNodeTypeId |
@ -730,7 +730,7 @@ impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
// //
// If you implement other values for this property, you will almost certainly // If you implement other values for this property, you will almost certainly
// want to update this check. // want to update this check.
match self.style().get().InheritedText.white_space { match self.style().get().InheritedText.get().white_space {
white_space::normal => true, white_space::normal => true,
_ => false, _ => false,
} }

View file

@ -21,7 +21,7 @@ use script::layout_interface::LayoutChan;
use servo_msg::constellation_msg::ConstellationChan; use servo_msg::constellation_msg::ConstellationChan;
use servo_net::local_image_cache::LocalImageCache; use servo_net::local_image_cache::LocalImageCache;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use style::Stylist; use style::{ComputedValues, Stylist};
#[thread_local] #[thread_local]
static mut FONT_CONTEXT: *mut FontContext = 0 as *mut FontContext; static mut FONT_CONTEXT: *mut FontContext = 0 as *mut FontContext;
@ -55,6 +55,9 @@ pub struct LayoutContext {
/// FIXME(pcwalton): Make this no longer an unsafe pointer once we have fast `RWArc`s. /// FIXME(pcwalton): Make this no longer an unsafe pointer once we have fast `RWArc`s.
stylist: *Stylist, stylist: *Stylist,
/// The initial set of CSS properties.
initial_css_values: Arc<ComputedValues>,
/// The root node at which we're starting the layout. /// The root node at which we're starting the layout.
reflow_root: OpaqueNode, reflow_root: OpaqueNode,
} }

View file

@ -309,7 +309,7 @@ static TEXT_ALIGN_SHIFT: u8 = 4;
impl FlowFlagsInfo { impl FlowFlagsInfo {
/// Creates a new set of flow flags from the given style. /// Creates a new set of flow flags from the given style.
pub fn new(style: &ComputedValues) -> FlowFlagsInfo { pub fn new(style: &ComputedValues) -> FlowFlagsInfo {
let text_decoration = style.Text.text_decoration; let text_decoration = style.Text.get().text_decoration;
let mut flags = FlowFlags(0); let mut flags = FlowFlags(0);
flags.set_override_underline(text_decoration.underline); flags.set_override_underline(text_decoration.underline);
flags.set_override_overline(text_decoration.overline); flags.set_override_overline(text_decoration.overline);
@ -318,9 +318,9 @@ impl FlowFlagsInfo {
// TODO(ksh8281) compute text-decoration-color,style,line // TODO(ksh8281) compute text-decoration-color,style,line
let rare_flow_flags = if flags.is_text_decoration_enabled() { let rare_flow_flags = if flags.is_text_decoration_enabled() {
Some(~RareFlowFlags { Some(~RareFlowFlags {
underline_color: style.Color.color.to_gfx_color(), underline_color: style.Color.get().color.to_gfx_color(),
overline_color: style.Color.color.to_gfx_color(), overline_color: style.Color.get().color.to_gfx_color(),
line_through_color: style.Color.color.to_gfx_color(), line_through_color: style.Color.get().color.to_gfx_color(),
}) })
} else { } else {
None None

View file

@ -107,7 +107,7 @@ impl RestyleDamage {
macro_rules! add_if_not_equal( macro_rules! add_if_not_equal(
($old:ident, $new:ident, $damage:ident, ($old:ident, $new:ident, $damage:ident,
[ $($effect:ident),* ], [ $($style_struct:ident.$name:ident),* ]) => ({ [ $($effect:ident),* ], [ $($style_struct:ident.$name:ident),* ]) => ({
if $( ($old.$style_struct.$name != $new.$style_struct.$name) )||* { if $( ($old.$style_struct.get().$name != $new.$style_struct.get().$name) )||* {
$damage.union_in_place( restyle_damage!( $($effect),* ) ); $damage.union_in_place( restyle_damage!( $($effect),* ) );
} }
}) })

View file

@ -794,7 +794,7 @@ impl Flow for InlineFlow {
// //
// The spec does not state which font to use. Previous versions of the code used // 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. // the parent's font; this code uses the current font.
let parent_text_top = cur_box.style().Font.font_size; let parent_text_top = cur_box.style().Font.get().font_size;
// We should calculate the distance from baseline to the bottom of the parent's // We should calculate the distance from baseline to the bottom of the parent's
// content area. But for now we assume it's zero. // content area. But for now we assume it's zero.

View file

@ -55,7 +55,8 @@ use std::comm::Port;
use std::ptr; use std::ptr;
use std::task; use std::task;
use std::util; use std::util;
use style::{AuthorOrigin, Stylesheet, Stylist}; use style::{AuthorOrigin, ComputedValues, Stylesheet, Stylist};
use style;
/// Information needed by the layout task. /// Information needed by the layout task.
pub struct LayoutTask { pub struct LayoutTask {
@ -97,6 +98,9 @@ pub struct LayoutTask {
stylist: ~Stylist, stylist: ~Stylist,
/// The initial set of CSS values.
initial_css_values: Arc<ComputedValues>,
/// The workers that we use for parallel operation. /// The workers that we use for parallel operation.
parallel_traversal: Option<WorkQueue<*mut LayoutContext,UnsafeFlow>>, parallel_traversal: Option<WorkQueue<*mut LayoutContext,UnsafeFlow>>,
@ -302,6 +306,7 @@ impl LayoutTask {
display_list_collection: None, display_list_collection: None,
stylist: ~new_stylist(), stylist: ~new_stylist(),
initial_css_values: Arc::new(style::initial_values()),
parallel_traversal: parallel_traversal, parallel_traversal: parallel_traversal,
profiler_chan: profiler_chan, profiler_chan: profiler_chan,
opts: opts.clone() opts: opts.clone()
@ -332,6 +337,7 @@ impl LayoutTask {
layout_chan: self.chan.clone(), layout_chan: self.chan.clone(),
font_context_info: font_context_info, font_context_info: font_context_info,
stylist: &*self.stylist, stylist: &*self.stylist,
initial_css_values: self.initial_css_values.clone(),
reflow_root: OpaqueNode::from_layout_node(reflow_root), reflow_root: OpaqueNode::from_layout_node(reflow_root),
} }
} }
@ -565,6 +571,7 @@ impl LayoutTask {
node.match_and_cascade_subtree(self.stylist, node.match_and_cascade_subtree(self.stylist,
&layout_ctx.layout_chan, &layout_ctx.layout_chan,
&mut applicable_declarations, &mut applicable_declarations,
layout_ctx.initial_css_values.get(),
None) None)
} }
Some(ref mut traversal) => { Some(ref mut traversal) => {
@ -638,6 +645,7 @@ impl LayoutTask {
.resolve_color(thread_safe_child.style() .resolve_color(thread_safe_child.style()
.get() .get()
.Background .Background
.get()
.background_color) .background_color)
.to_gfx_color() .to_gfx_color()
}; };

View file

@ -163,7 +163,9 @@ fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode,
} else { } else {
node.parent_node() node.parent_node()
}; };
node.cascade_node(parent_opt, &applicable_declarations); node.cascade_node(parent_opt,
layout_context.initial_css_values.get(),
&applicable_declarations);
// Enqueue kids. // Enqueue kids.
let mut child_count = 0; let mut child_count = 0;

View file

@ -160,33 +160,111 @@ pub mod specified {
} }
pub mod computed { pub mod computed {
use cssparser;
pub use CSSColor = cssparser::Color; pub use CSSColor = cssparser::Color;
pub use compute_CSSColor = super::super::longhands::computed_as_specified; pub use compute_CSSColor = super::super::longhands::computed_as_specified;
use super::*; use super::*;
use super::super::longhands; use super::super::{longhands, style_structs};
use servo_util::cowarc::CowArc;
pub use servo_util::geometry::Au; pub use servo_util::geometry::Au;
pub struct Context { pub struct Context {
current_color: cssparser::RGBA, color: longhands::color::computed_value::T,
parent_font_size: Au, parent_font_weight: longhands::font_weight::computed_value::T,
font_size: Au, parent_font_size: longhands::font_size::computed_value::T,
font_weight: longhands::font_weight::computed_value::T, font_size: longhands::font_size::computed_value::T,
position: longhands::position::SpecifiedValue, positioned: bool,
float: longhands::float::SpecifiedValue, floated: bool,
border_top_present: bool,
border_right_present: bool,
border_bottom_present: bool,
border_left_present: bool,
is_root_element: bool, is_root_element: bool,
border_top_style: longhands::border_top_style::computed_value::T, use_parent_font_size: bool,
border_right_style: longhands::border_top_style::computed_value::T,
border_bottom_style: longhands::border_top_style::computed_value::T,
border_left_style: longhands::border_top_style::computed_value::T,
// TODO, as needed: root font size, viewport size, etc. // TODO, as needed: root font size, viewport size, etc.
} }
fn border_is_present(border_style: longhands::border_top_style::computed_value::T) -> bool {
match border_style {
longhands::border_top_style::none | longhands::border_top_style::hidden => false,
_ => true,
}
}
impl Context {
#[inline]
pub fn new(color: &CowArc<style_structs::Color>,
font: &CowArc<style_structs::Font>,
css_box: &CowArc<style_structs::Box>,
border: &CowArc<style_structs::Border>,
is_root_element: bool)
-> Context {
let mut context = Context {
color: color.get().color,
parent_font_weight: font.get().font_weight,
parent_font_size: font.get().font_size,
font_size: font.get().font_size,
positioned: false,
floated: false,
border_top_present: false,
border_right_present: false,
border_bottom_present: false,
border_left_present: false,
is_root_element: is_root_element,
use_parent_font_size: true,
};
context.set_position(css_box.get().position);
context.set_float(css_box.get().float);
context.set_border_top_style(border.get().border_top_style);
context.set_border_right_style(border.get().border_right_style);
context.set_border_bottom_style(border.get().border_bottom_style);
context.set_border_left_style(border.get().border_left_style);
context
}
pub fn set_color(&mut self, color: longhands::color::computed_value::T) {
self.color = color
}
pub fn set_position(&mut self, position: longhands::position::computed_value::T) {
self.positioned = match position {
longhands::position::absolute | longhands::position::fixed => true,
_ => false,
}
}
pub fn set_font_size(&mut self, font_size: longhands::font_size::computed_value::T) {
self.font_size = font_size
}
pub fn set_float(&mut self, float: longhands::float::computed_value::T) {
self.floated = float != longhands::float::none
}
pub fn set_border_top_style(&mut self,
style: longhands::border_top_style::computed_value::T) {
self.border_top_present = border_is_present(style)
}
pub fn set_border_right_style(&mut self,
style: longhands::border_top_style::computed_value::T) {
self.border_right_present = border_is_present(style)
}
pub fn set_border_bottom_style(&mut self,
style: longhands::border_top_style::computed_value::T) {
self.border_bottom_present = border_is_present(style)
}
pub fn set_border_left_style(&mut self,
style: longhands::border_top_style::computed_value::T) {
self.border_left_present = border_is_present(style)
}
}
#[inline] #[inline]
pub fn compute_Au(value: specified::Length, context: &Context, em_is_parent: bool) -> Au { pub fn compute_Au(value: specified::Length, context: &Context) -> Au {
match value { match value {
specified::Au_(value) => value, specified::Au_(value) => value,
specified::Em(value) if em_is_parent => context.parent_font_size.scale_by(value),
specified::Em(value) => context.font_size.scale_by(value), specified::Em(value) => context.font_size.scale_by(value),
specified::Ex(value) => { specified::Ex(value) => {
let x_height = 0.5; // TODO: find that from the font let x_height = 0.5; // TODO: find that from the font
@ -195,6 +273,19 @@ pub mod computed {
} }
} }
/// A special version of `compute_Au` used for `font-size`.
#[inline]
pub fn compute_Au_from_parent(value: specified::Length, context: &Context) -> Au {
match value {
specified::Au_(value) => value,
specified::Em(value) => context.parent_font_size.scale_by(value),
specified::Ex(value) => {
let x_height = 0.5; // TODO: find that from the font
context.font_size.scale_by(value * x_height)
},
}
}
#[deriving(Eq, Clone)] #[deriving(Eq, Clone)]
pub enum LengthOrPercentage { pub enum LengthOrPercentage {
LP_Length(Au), LP_Length(Au),
@ -203,7 +294,7 @@ pub mod computed {
pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context) pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context)
-> LengthOrPercentage { -> LengthOrPercentage {
match value { match value {
specified::LP_Length(value) => LP_Length(compute_Au(value, context, false)), specified::LP_Length(value) => LP_Length(compute_Au(value, context)),
specified::LP_Percentage(value) => LP_Percentage(value), specified::LP_Percentage(value) => LP_Percentage(value),
} }
} }
@ -217,7 +308,7 @@ pub mod computed {
pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto, pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto,
context: &Context) -> LengthOrPercentageOrAuto { context: &Context) -> LengthOrPercentageOrAuto {
match value { match value {
specified::LPA_Length(value) => LPA_Length(compute_Au(value, context, false)), specified::LPA_Length(value) => LPA_Length(compute_Au(value, context)),
specified::LPA_Percentage(value) => LPA_Percentage(value), specified::LPA_Percentage(value) => LPA_Percentage(value),
specified::LPA_Auto => LPA_Auto, specified::LPA_Auto => LPA_Auto,
} }
@ -232,7 +323,7 @@ pub mod computed {
pub fn compute_LengthOrPercentageOrNone(value: specified::LengthOrPercentageOrNone, pub fn compute_LengthOrPercentageOrNone(value: specified::LengthOrPercentageOrNone,
context: &Context) -> LengthOrPercentageOrNone { context: &Context) -> LengthOrPercentageOrNone {
match value { match value {
specified::LPN_Length(value) => LPN_Length(compute_Au(value, context, false)), specified::LPN_Length(value) => LPN_Length(compute_Au(value, context)),
specified::LPN_Percentage(value) => LPN_Percentage(value), specified::LPN_Percentage(value) => LPN_Percentage(value),
specified::LPN_None => LPN_None, specified::LPN_None => LPN_None,
} }

View file

@ -6,6 +6,7 @@
use std::ascii::StrAsciiExt; use std::ascii::StrAsciiExt;
pub use extra::arc::Arc; pub use extra::arc::Arc;
use servo_util::cowarc::CowArc;
pub use cssparser::*; pub use cssparser::*;
pub use cssparser::ast::*; pub use cssparser::ast::*;
@ -25,18 +26,17 @@ def to_rust_ident(name):
return name return name
class Longhand(object): class Longhand(object):
def __init__(self, name, priority): def __init__(self, name, needed_for_context):
self.name = name self.name = name
self.ident = to_rust_ident(name) self.ident = to_rust_ident(name)
self.style_struct = THIS_STYLE_STRUCT self.style_struct = THIS_STYLE_STRUCT
self.priority = priority self.needed_for_context = needed_for_context
class Shorthand(object): class Shorthand(object):
def __init__(self, name, priority, sub_properties): def __init__(self, name, sub_properties):
self.name = name self.name = name
self.ident = to_rust_ident(name) self.ident = to_rust_ident(name)
self.sub_properties = [LONGHANDS_BY_NAME[s] for s in sub_properties] self.sub_properties = [LONGHANDS_BY_NAME[s] for s in sub_properties]
self.priority = priority
class StyleStruct(object): class StyleStruct(object):
def __init__(self, name, inherited): def __init__(self, name, inherited):
@ -72,13 +72,13 @@ pub mod longhands {
pub use super::*; pub use super::*;
pub use std; pub use std;
pub fn computed_as_specified<T>(value: T, _context: &mut computed::Context) -> T { pub fn computed_as_specified<T>(value: T, _context: &computed::Context) -> T {
value value
} }
<%def name="raw_longhand(name, priority='Normal', no_super=False)"> <%def name="raw_longhand(name, needed_for_context=False, no_super=False)">
<% <%
property = Longhand(name, priority) property = Longhand(name, needed_for_context)
THIS_STYLE_STRUCT.longhands.append(property) THIS_STYLE_STRUCT.longhands.append(property)
LONGHANDS.append(property) LONGHANDS.append(property)
LONGHANDS_BY_NAME[name] = property LONGHANDS_BY_NAME[name] = property
@ -101,8 +101,8 @@ pub mod longhands {
} }
</%def> </%def>
<%def name="longhand(name, priority='Normal', no_super=False)"> <%def name="longhand(name, needed_for_context=False, no_super=False)">
<%self:raw_longhand name="${name}" priority="${priority}"> <%self:raw_longhand name="${name}" needed_for_context="${needed_for_context}">
${caller.body()} ${caller.body()}
pub fn parse_specified(input: &[ComponentValue]) pub fn parse_specified(input: &[ComponentValue])
-> Option<DeclaredValue<SpecifiedValue>> { -> Option<DeclaredValue<SpecifiedValue>> {
@ -111,8 +111,8 @@ pub mod longhands {
</%self:raw_longhand> </%self:raw_longhand>
</%def> </%def>
<%def name="single_component_value(name, priority='Normal')"> <%def name="single_component_value(name, needed_for_context=False)">
<%self:longhand name="${name}" priority="${priority}"> <%self:longhand name="${name}" needed_for_context="${needed_for_context}">
${caller.body()} ${caller.body()}
pub fn parse(input: &[ComponentValue]) -> Option<SpecifiedValue> { pub fn parse(input: &[ComponentValue]) -> Option<SpecifiedValue> {
one_component_value(input).and_then(from_component_value) one_component_value(input).and_then(from_component_value)
@ -120,8 +120,8 @@ pub mod longhands {
</%self:longhand> </%self:longhand>
</%def> </%def>
<%def name="single_keyword_computed(name, values, priority='Normal')"> <%def name="single_keyword_computed(name, values, needed_for_context=False)">
<%self:single_component_value name="${name}" priority="${priority}"> <%self:single_component_value name="${name}" needed_for_context="${needed_for_context}">
${caller.body()} ${caller.body()}
pub mod computed_value { pub mod computed_value {
#[deriving(Eq, Clone, FromPrimitive)] #[deriving(Eq, Clone, FromPrimitive)]
@ -148,8 +148,10 @@ pub mod longhands {
</%self:single_component_value> </%self:single_component_value>
</%def> </%def>
<%def name="single_keyword(name, values, priority='Normal')"> <%def name="single_keyword(name, values, needed_for_context=False)">
<%self:single_keyword_computed name="${name}" values="${values}" priority="${priority}"> <%self:single_keyword_computed name="${name}"
values="${values}"
needed_for_context="${needed_for_context}">
// The computed value is the same as the specified value. // The computed value is the same as the specified value.
pub use to_computed_value = super::computed_as_specified; pub use to_computed_value = super::computed_as_specified;
</%self:single_keyword_computed> </%self:single_keyword_computed>
@ -172,14 +174,14 @@ pub mod longhands {
// CSS 2.1, Section 8 - Box model // CSS 2.1, Section 8 - Box model
${new_style_struct("Margin", False)} ${new_style_struct("Margin", is_inherited=False)}
% for side in ["top", "right", "bottom", "left"]: % for side in ["top", "right", "bottom", "left"]:
${predefined_type("margin-" + side, "LengthOrPercentageOrAuto", ${predefined_type("margin-" + side, "LengthOrPercentageOrAuto",
"computed::LPA_Length(Au(0))")} "computed::LPA_Length(Au(0))")}
% endfor % endfor
${new_style_struct("Padding", False)} ${new_style_struct("Padding", is_inherited=False)}
% for side in ["top", "right", "bottom", "left"]: % for side in ["top", "right", "bottom", "left"]:
${predefined_type("padding-" + side, "LengthOrPercentage", ${predefined_type("padding-" + side, "LengthOrPercentage",
@ -187,33 +189,19 @@ pub mod longhands {
"parse_non_negative")} "parse_non_negative")}
% endfor % endfor
${new_style_struct("Border", False)} ${new_style_struct("Border", is_inherited=False)}
% for side in ["top", "right", "bottom", "left"]: % for side in ["top", "right", "bottom", "left"]:
${predefined_type("border-%s-color" % side, "CSSColor", "CurrentColor")} ${predefined_type("border-%s-color" % side, "CSSColor", "CurrentColor")}
% endfor % endfor
// double groove ridge insed outset // double groove ridge insed outset
<%self:single_keyword_computed name="border-top-style" ${single_keyword("border-top-style", values="none solid dotted dashed hidden", \
values="none solid dotted dashed hidden" needed_for_context=True)}
priority="High">
pub fn to_computed_value(value: SpecifiedValue, context: &mut computed::Context)
-> computed_value::T {
context.border_top_style = value;
value
}
</%self:single_keyword_computed>
% for side in ["right", "bottom", "left"]: % for side in ["right", "bottom", "left"]:
<%self:longhand name="border-${side}-style", no_super="True", priority="High"> <%self:longhand name="border-${side}-style", no_super="True", needed_for_context="True">
pub use super::border_top_style::get_initial_value; pub use super::border_top_style::{get_initial_value, parse, to_computed_value};
pub use super::border_top_style::parse;
pub fn to_computed_value(value: SpecifiedValue, context: &mut computed::Context)
-> computed_value::T {
context.border_${side}_style = value;
value
}
pub type SpecifiedValue = super::border_top_style::SpecifiedValue; pub type SpecifiedValue = super::border_top_style::SpecifiedValue;
pub mod computed_value { pub mod computed_value {
pub type T = super::super::border_top_style::computed_value::T; pub type T = super::super::border_top_style::computed_value::T;
@ -238,7 +226,6 @@ pub mod longhands {
} }
% for side in ["top", "right", "bottom", "left"]: % for side in ["top", "right", "bottom", "left"]:
<%self:longhand name="border-${side}-width"> <%self:longhand name="border-${side}-width">
use super::super::border_is_present;
pub type SpecifiedValue = specified::Length; pub type SpecifiedValue = specified::Length;
pub mod computed_value { pub mod computed_value {
use super::super::Au; use super::super::Au;
@ -250,18 +237,19 @@ pub mod longhands {
pub fn parse(input: &[ComponentValue]) -> Option<SpecifiedValue> { pub fn parse(input: &[ComponentValue]) -> Option<SpecifiedValue> {
one_component_value(input).and_then(parse_border_width) one_component_value(input).and_then(parse_border_width)
} }
pub fn to_computed_value(value: SpecifiedValue, context: &mut computed::Context) #[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T { -> computed_value::T {
if !border_is_present(context.border_${side}_style) { if !context.border_${side}_present {
Au(0) Au(0)
} else { } else {
computed::compute_Au(value, context, false) computed::compute_Au(value, context)
} }
} }
</%self:longhand> </%self:longhand>
% endfor % endfor
${new_style_struct("PositionOffsets", False)} ${new_style_struct("PositionOffsets", is_inherited=False)}
% for side in ["top", "right", "bottom", "left"]: % for side in ["top", "right", "bottom", "left"]:
${predefined_type(side, "LengthOrPercentageOrAuto", ${predefined_type(side, "LengthOrPercentageOrAuto",
@ -270,7 +258,7 @@ pub mod longhands {
// CSS 2.1, Section 9 - Visual formatting model // CSS 2.1, Section 9 - Visual formatting model
${new_style_struct("Box", False)} ${new_style_struct("Box", is_inherited=False)}
// TODO: don't parse values we don't support // TODO: don't parse values we don't support
<%self:single_keyword_computed name="display" <%self:single_keyword_computed name="display"
@ -279,16 +267,13 @@ pub mod longhands {
table-row table-column-group table-column table-cell table-caption table-row table-column-group table-column table-cell table-caption
list-item list-item
none"> none">
#[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context) pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T { -> computed_value::T {
// if context.is_root_element && value == list_item { // if context.is_root_element && value == list_item {
// return block // return block
// } // }
let positioned = match context.position { if context.positioned || context.floated || context.is_root_element {
position::absolute | position::fixed => true,
_ => false
};
if positioned || context.float != float::none || context.is_root_element {
match value { match value {
// inline_table => table, // inline_table => table,
inline | inline_block inline | inline_block
@ -304,8 +289,8 @@ pub mod longhands {
} }
</%self:single_keyword_computed> </%self:single_keyword_computed>
${single_keyword("position", "static absolute relative fixed")} ${single_keyword("position", "static absolute relative fixed", needed_for_context="True")}
${single_keyword("float", "none left right")} ${single_keyword("float", "none left right", needed_for_context="True")}
${single_keyword("clear", "none left right both")} ${single_keyword("clear", "none left right both")}
// CSS 2.1, Section 10 - Visual formatting model details // CSS 2.1, Section 10 - Visual formatting model details
@ -324,7 +309,7 @@ pub mod longhands {
"computed::LPN_None", "computed::LPN_None",
"parse_non_negative")} "parse_non_negative")}
${new_style_struct("InheritedBox", True)} ${new_style_struct("InheritedBox", is_inherited=True)}
<%self:single_component_value name="line-height"> <%self:single_component_value name="line-height">
#[deriving(Clone)] #[deriving(Clone)]
@ -358,12 +343,14 @@ pub mod longhands {
Number(CSSFloat), Number(CSSFloat),
} }
} }
#[inline] pub fn get_initial_value() -> computed_value::T { Normal } #[inline]
pub fn get_initial_value() -> computed_value::T { Normal }
#[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context) pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T { -> computed_value::T {
match value { match value {
SpecifiedNormal => Normal, SpecifiedNormal => Normal,
SpecifiedLength(value) => Length(computed::compute_Au(value, context, false)), SpecifiedLength(value) => Length(computed::compute_Au(value, context)),
SpecifiedNumber(value) => Number(value), SpecifiedNumber(value) => Number(value),
} }
} }
@ -410,7 +397,9 @@ pub mod longhands {
Percentage(CSSFloat), Percentage(CSSFloat),
} }
} }
#[inline] pub fn get_initial_value() -> computed_value::T { baseline } #[inline]
pub fn get_initial_value() -> computed_value::T { baseline }
#[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context) pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T { -> computed_value::T {
match value { match value {
@ -482,15 +471,15 @@ pub mod longhands {
// CSS 2.1, Section 14 - Colors and Backgrounds // CSS 2.1, Section 14 - Colors and Backgrounds
${new_style_struct("Background", False)} ${new_style_struct("Background", is_inherited=False)}
${predefined_type("background-color", "CSSColor", ${predefined_type("background-color", "CSSColor",
"RGBA(RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */")} "RGBA(RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */")}
${new_style_struct("Color", True)} ${new_style_struct("Color", is_inherited=True)}
<%self:raw_longhand name="color"> <%self:raw_longhand name="color" needed_for_context="True">
pub use to_computed_value = super::computed_as_specified; pub use to_computed_value = super::computed_as_specified;
pub type SpecifiedValue = RGBA; pub type SpecifiedValue = RGBA;
pub mod computed_value { pub mod computed_value {
@ -510,7 +499,7 @@ pub mod longhands {
// CSS 2.1, Section 15 - Fonts // CSS 2.1, Section 15 - Fonts
${new_style_struct("Font", True)} ${new_style_struct("Font", is_inherited=True)}
<%self:longhand name="font-family"> <%self:longhand name="font-family">
pub use to_computed_value = super::computed_as_specified; pub use to_computed_value = super::computed_as_specified;
@ -593,11 +582,11 @@ pub mod longhands {
${single_keyword("font-style", "normal italic oblique")} ${single_keyword("font-style", "normal italic oblique")}
${single_keyword("font-variant", "normal")} // Add small-caps when supported ${single_keyword("font-variant", "normal")} // Add small-caps when supported
<%self:single_component_value name="font-weight" priority="High"> <%self:single_component_value name="font-weight">
#[deriving(Clone)] #[deriving(Clone)]
pub enum SpecifiedValue { pub enum SpecifiedValue {
Bolder, Bolder,
Lighther, Lighter,
% for weight in range(100, 901, 100): % for weight in range(100, 901, 100):
SpecifiedWeight${weight}, SpecifiedWeight${weight},
% endfor % endfor
@ -612,7 +601,7 @@ pub mod longhands {
"bold" => Some(SpecifiedWeight700), "bold" => Some(SpecifiedWeight700),
"normal" => Some(SpecifiedWeight400), "normal" => Some(SpecifiedWeight400),
"bolder" => Some(Bolder), "bolder" => Some(Bolder),
"lighter" => Some(Lighther), "lighter" => Some(Lighter),
_ => None, _ => None,
} }
}, },
@ -647,14 +636,16 @@ pub mod longhands {
} }
} }
} }
#[inline] pub fn get_initial_value() -> computed_value::T { Weight400 } // normal #[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &mut computed::Context) pub fn get_initial_value() -> computed_value::T { Weight400 } // normal
#[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T { -> computed_value::T {
let result = match value { match value {
% for weight in range(100, 901, 100): % for weight in range(100, 901, 100):
SpecifiedWeight${weight} => Weight${weight}, SpecifiedWeight${weight} => Weight${weight},
% endfor % endfor
Bolder => match context.font_weight { Bolder => match context.parent_font_weight {
Weight100 => Weight400, Weight100 => Weight400,
Weight200 => Weight400, Weight200 => Weight400,
Weight300 => Weight400, Weight300 => Weight400,
@ -665,7 +656,7 @@ pub mod longhands {
Weight800 => Weight900, Weight800 => Weight900,
Weight900 => Weight900, Weight900 => Weight900,
}, },
Lighther => match context.font_weight { Lighter => match context.parent_font_weight {
Weight100 => Weight100, Weight100 => Weight100,
Weight200 => Weight100, Weight200 => Weight100,
Weight300 => Weight100, Weight300 => Weight100,
@ -676,28 +667,29 @@ pub mod longhands {
Weight800 => Weight700, Weight800 => Weight700,
Weight900 => Weight700, Weight900 => Weight700,
}, },
}; }
context.font_weight = result;
result
} }
</%self:single_component_value> </%self:single_component_value>
<%self:single_component_value name="font-size" priority="High"> <%self:single_component_value name="font-size" needed_for_context="True">
pub use to_computed_value = super::super::common_types::computed::compute_Au; use super::super::common_types::computed::compute_Au_from_parent;
pub type SpecifiedValue = specified::Length; // Percentages are the same as em. pub type SpecifiedValue = specified::Length; // Percentages are the same as em.
pub mod computed_value { pub mod computed_value {
use super::super::Au; use super::super::Au;
pub type T = Au; pub type T = Au;
} }
pub fn to_computed_value(value: SpecifiedValue, context: &mut computed::Context)
-> computed_value::T {
let result = computed::compute_Au(value, context, true);
context.font_size = result;
result
}
#[inline] pub fn get_initial_value() -> computed_value::T { #[inline] pub fn get_initial_value() -> computed_value::T {
Au::from_px(16) // medium Au::from_px(16) // medium
} }
#[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T {
if !context.use_parent_font_size {
// We already computed this element's font size; no need to compute it again.
return context.font_size
}
compute_Au_from_parent(value, context)
}
/// <length> | <percentage> /// <length> | <percentage>
/// TODO: support <absolute-size> and <relative-size> /// TODO: support <absolute-size> and <relative-size>
pub fn from_component_value(input: &ComponentValue) -> Option<SpecifiedValue> { pub fn from_component_value(input: &ComponentValue) -> Option<SpecifiedValue> {
@ -712,12 +704,12 @@ pub mod longhands {
// CSS 2.1, Section 16 - Text // CSS 2.1, Section 16 - Text
${new_style_struct("InheritedText", True)} ${new_style_struct("InheritedText", is_inherited=True)}
// TODO: initial value should be 'start' (CSS Text Level 3, direction-dependent.) // TODO: initial value should be 'start' (CSS Text Level 3, direction-dependent.)
${single_keyword("text-align", "left right center justify")} ${single_keyword("text-align", "left right center justify")}
${new_style_struct("Text", False)} ${new_style_struct("Text", is_inherited=False)}
<%self:longhand name="text-decoration"> <%self:longhand name="text-decoration">
pub use to_computed_value = super::computed_as_specified; pub use to_computed_value = super::computed_as_specified;
@ -778,9 +770,9 @@ pub mod shorthands {
pub use super::*; pub use super::*;
pub use super::longhands::*; pub use super::longhands::*;
<%def name="shorthand(name, sub_properties, priority='Normal')"> <%def name="shorthand(name, sub_properties, needed_for_context=False)">
<% <%
shorthand = Shorthand(name, priority, sub_properties.split()) shorthand = Shorthand(name, sub_properties.split())
SHORTHANDS.append(shorthand) SHORTHANDS.append(shorthand)
%> %>
pub mod ${shorthand.ident} { pub mod ${shorthand.ident} {
@ -1127,7 +1119,7 @@ pub mod style_structs {
#[deriving(Eq, Clone)] #[deriving(Eq, Clone)]
pub struct ComputedValues { pub struct ComputedValues {
% for style_struct in STYLE_STRUCTS: % for style_struct in STYLE_STRUCTS:
${style_struct.name}: style_structs::${style_struct.name}, ${style_struct.name}: CowArc<style_structs::${style_struct.name}>,
% endfor % endfor
} }
@ -1142,36 +1134,21 @@ impl ComputedValues {
pub fn resolve_color(&self, color: computed::CSSColor) -> RGBA { pub fn resolve_color(&self, color: computed::CSSColor) -> RGBA {
match color { match color {
RGBA(rgba) => rgba, RGBA(rgba) => rgba,
CurrentColor => self.Color.color, CurrentColor => self.Color.get().color,
} }
} }
} }
/// Creates a new cascade context. /// Returns the initial values for all style structs as defined by the specification.
fn new_cascade_context(style_Color: &style_structs::Color, pub fn initial_values() -> ComputedValues {
style_Font: &style_structs::Font, ComputedValues {
style_Box: &style_structs::Box, % for style_struct in STYLE_STRUCTS:
is_root_element: bool) ${style_struct.name}: CowArc::new(style_structs::${style_struct.name} {
-> computed::Context { % for longhand in style_struct.longhands:
computed::Context { ${longhand.ident}: longhands::${longhand.ident}::get_initial_value(),
current_color: style_Color.color, % endfor
parent_font_size: style_Font.font_size, }),
font_size: style_Font.font_size, % endfor
font_weight: style_Font.font_weight,
position: style_Box.position,
float: style_Box.float,
is_root_element: is_root_element,
border_top_style: longhands::border_top_style::get_initial_value(),
border_right_style: longhands::border_top_style::get_initial_value(),
border_bottom_style: longhands::border_top_style::get_initial_value(),
border_left_style: longhands::border_top_style::get_initial_value(),
}
}
fn border_is_present(border_style: longhands::border_top_style::computed_value::T) -> bool {
match border_style {
longhands::border_top_style::hidden | longhands::border_top_style::none => false,
_ => true
} }
} }
@ -1182,9 +1159,12 @@ fn border_is_present(border_style: longhands::border_top_style::computed_value::
/// ///
/// * `parent_style`: The parent style, if applicable; if `None`, this is the root node. /// * `parent_style`: The parent style, if applicable; if `None`, this is the root node.
/// ///
/// * `initial_values`: The initial set of CSS values as defined by the specification.
///
/// Returns the computed values. /// Returns the computed values.
pub fn cascade(applicable_declarations: &[Arc<~[PropertyDeclaration]>], pub fn cascade(applicable_declarations: &[Arc<~[PropertyDeclaration]>],
parent_style: Option< &ComputedValues >) parent_style: Option< &ComputedValues>,
initial_values: &ComputedValues)
-> ComputedValues { -> ComputedValues {
let is_root_element; let is_root_element;
% for style_struct in STYLE_STRUCTS: % for style_struct in STYLE_STRUCTS:
@ -1197,73 +1177,90 @@ pub fn cascade(applicable_declarations: &[Arc<~[PropertyDeclaration]>],
% if style_struct.inherited: % if style_struct.inherited:
style_${style_struct.name} = parent_style.${style_struct.name}.clone(); style_${style_struct.name} = parent_style.${style_struct.name}.clone();
% else: % else:
style_${style_struct.name} = style_structs::${style_struct.name} { style_${style_struct.name} = initial_values.${style_struct.name}.clone();
% for longhand in style_struct.longhands: % endif
${longhand.ident}: longhands::${longhand.ident}::get_initial_value(),
% endfor
};
%endif
% endfor % endfor
} }
None => { None => {
is_root_element = true; is_root_element = true;
% for style_struct in STYLE_STRUCTS: % for style_struct in STYLE_STRUCTS:
style_${style_struct.name} = style_structs::${style_struct.name} { style_${style_struct.name} = initial_values.${style_struct.name}.clone();
% for longhand in style_struct.longhands:
${longhand.ident}: longhands::${longhand.ident}::get_initial_value(),
% endfor
};
% endfor % endfor
} }
} }
let mut context = new_cascade_context(&style_Color, &style_Font, &style_Box, is_root_element); let mut context = computed::Context::new(&style_Color,
&style_Font,
&style_Box,
&style_Border,
is_root_element);
<%def name="apply(priority)"> <%def name="apply(needed_for_context)">
for sub_list in applicable_declarations.iter() { for sub_list in applicable_declarations.iter() {
for declaration in sub_list.get().iter() { for declaration in sub_list.get().iter() {
match declaration { match declaration {
% for style_struct in STYLE_STRUCTS: % for style_struct in STYLE_STRUCTS:
% for property in style_struct.longhands: % for property in style_struct.longhands:
% if property.priority == priority: % if (property.needed_for_context and needed_for_context) or not \
needed_for_context:
&${property.ident}_declaration(SpecifiedValue(ref value)) => { &${property.ident}_declaration(SpecifiedValue(ref value)) => {
// Overwrite earlier declarations. let computed_value =
// TODO: can we avoid a copy?
style_${style_struct.name}.${property.ident} =
longhands::${property.ident}::to_computed_value( longhands::${property.ident}::to_computed_value(
(*value).clone(), (*value).clone(),
&mut context) &context);
% if property.needed_for_context and needed_for_context:
context.set_${property.ident}(computed_value)
% elif not needed_for_context:
// Overwrite earlier declarations.
style_${style_struct.name}.get_mut().${property.ident} =
computed_value
% endif
} }
&${property.ident}_declaration(CSSWideKeyword(Initial)) => {
let computed_value =
longhands::${property.ident}::get_initial_value();
% if property.needed_for_context and needed_for_context:
context.set_${property.ident}(computed_value)
% elif not needed_for_context:
// Overwrite earlier declarations.
style_${style_struct.name}.get_mut().${property.ident} =
computed_value
% endif
}
% endif
% if not needed_for_context:
&${property.ident}_declaration(CSSWideKeyword(Inherit)) => { &${property.ident}_declaration(CSSWideKeyword(Inherit)) => {
// This is a bit slow, but this is rare so it shouldn't matter. // This is a bit slow, but this is rare so it shouldn't matter.
match parent_style { match parent_style {
None => { None => {
style_${style_struct.name}.${property.ident} = style_${style_struct.name}.get_mut()
.${property.ident} =
longhands::${property.ident}::get_initial_value() longhands::${property.ident}::get_initial_value()
} }
Some(ref parent_style) => { Some(ref parent_style) => {
style_${style_struct.name}.${property.ident} = style_${style_struct.name}.get_mut()
.${property.ident} =
parent_style.${style_struct.name} parent_style.${style_struct.name}
.get()
.${property.ident} .${property.ident}
.clone() .clone()
} }
} }
} }
&${property.ident}_declaration(CSSWideKeyword(Initial)) => {
style_${style_struct.name}.${property.ident} =
longhands::${property.ident}::get_initial_value()
}
% endif % endif
% endfor % endfor
% endfor % endfor
_ => {} % if needed_for_context:
_ => {}
% endif
} }
} }
} }
</%def> </%def>
${apply("High")} ${apply(True)}
${apply("Normal")} context.use_parent_font_size = false;
${apply(False)}
ComputedValues { ComputedValues {
% for style_struct in STYLE_STRUCTS: % for style_struct in STYLE_STRUCTS:

View file

@ -21,6 +21,7 @@ pub use stylesheets::Stylesheet;
pub use selector_matching::{Stylist, StylesheetOrigin, UserAgentOrigin, AuthorOrigin, UserOrigin}; pub use selector_matching::{Stylist, StylesheetOrigin, UserAgentOrigin, AuthorOrigin, UserOrigin};
pub use properties::{cascade, PropertyDeclaration, ComputedValues, computed_values}; pub use properties::{cascade, PropertyDeclaration, ComputedValues, computed_values};
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
pub use properties::{initial_values};
pub use errors::with_errors_silenced; pub use errors::with_errors_silenced;
pub use node::{TElement, TNode}; pub use node::{TElement, TNode};
pub use selectors::{PseudoElement, Before, After, AttrSelector, SpecificNamespace, AnyNamespace}; pub use selectors::{PseudoElement, Before, After, AttrSelector, SpecificNamespace, AnyNamespace};

View file

@ -0,0 +1,100 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//! An atomically reference counted type that copies itself on mutation.
use std::cast;
use std::ptr;
use std::sync::atomics::{AtomicUint, SeqCst};
struct CowArcAlloc<T> {
ref_count: AtomicUint,
data: T,
}
#[unsafe_no_drop_flag]
pub struct CowArc<T> {
priv ptr: *mut CowArcAlloc<T>,
}
#[unsafe_destructor]
impl<T> Drop for CowArc<T> {
#[inline]
fn drop(&mut self) {
unsafe {
if self.ptr != ptr::mut_null() && (*self.ptr).ref_count.fetch_sub(1, SeqCst) == 1 {
let _kill_it: ~CowArcAlloc<T> = cast::transmute(self.ptr);
self.ptr = ptr::mut_null()
}
}
}
}
impl<T:Eq + Freeze + Clone> Eq for CowArc<T> {
fn eq(&self, other: &CowArc<T>) -> bool {
self.get() == other.get()
}
}
impl<T:Freeze + Clone> Clone for CowArc<T> {
#[inline]
fn clone(&self) -> CowArc<T> {
unsafe {
drop((*self.ptr).ref_count.fetch_add(1, SeqCst));
}
CowArc {
ptr: self.ptr
}
}
}
impl<T:Freeze + Clone> CowArc<T> {
#[inline]
pub fn new(value: T) -> CowArc<T> {
let alloc = ~CowArcAlloc {
ref_count: AtomicUint::new(1),
data: value,
};
unsafe {
CowArc {
ptr: cast::transmute(alloc),
}
}
}
#[inline]
pub fn shared(&self) -> bool {
unsafe {
(*self.ptr).ref_count.load(SeqCst) != 1
}
}
#[inline]
pub fn get<'a>(&'a self) -> &'a T {
unsafe {
cast::transmute(&(*self.ptr).data)
}
}
#[inline(always)]
pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
unsafe {
if (*self.ptr).ref_count.load(SeqCst) == 1 {
return cast::transmute(&mut (*self.ptr).data)
}
let copy = ~CowArcAlloc {
ref_count: AtomicUint::new(1),
data: (*self.ptr).data.clone(),
};
*self = CowArc {
ptr: cast::transmute(copy),
};
cast::transmute(&mut (*self.ptr).data)
}
}
}

View file

@ -13,6 +13,7 @@ extern mod native;
pub mod cache; pub mod cache;
pub mod concurrentmap; pub mod concurrentmap;
pub mod cowarc;
pub mod debug; pub mod debug;
pub mod geometry; pub mod geometry;
pub mod io; pub mod io;