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 script::layout_interface::LayoutChan;
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 {
normal: SmallVec16<Arc<~[PropertyDeclaration]>>,
@ -43,12 +43,14 @@ pub trait MatchMethods {
stylist: &Stylist,
layout_chan: &LayoutChan,
applicable_declarations: &mut ApplicableDeclarations,
initial_values: &ComputedValues,
parent: Option<LayoutNode>);
fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations);
unsafe fn cascade_node(&self,
parent: Option<LayoutNode>,
initial_values: &ComputedValues,
applicable_declarations: &ApplicableDeclarations);
}
@ -79,6 +81,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
stylist: &Stylist,
layout_chan: &LayoutChan,
applicable_declarations: &mut ApplicableDeclarations,
initial_values: &ComputedValues,
parent: Option<LayoutNode>) {
self.initialize_layout_data((*layout_chan).clone());
@ -87,7 +90,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
}
unsafe {
self.cascade_node(parent, applicable_declarations)
self.cascade_node(parent, initial_values, applicable_declarations)
}
applicable_declarations.clear();
@ -96,12 +99,14 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
kid.match_and_cascade_subtree(stylist,
layout_chan,
applicable_declarations,
initial_values,
Some(*self))
}
}
unsafe fn cascade_node(&self,
parent: Option<LayoutNode>,
initial_values: &ComputedValues,
applicable_declarations: &ApplicableDeclarations) {
macro_rules! cascade_node(
($applicable_declarations: expr, $style: ident) => {{
@ -124,30 +129,33 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
}
}
}
};
};
let computed_values = match parent_style {
Some(ref style) => {
Arc::new(cascade($applicable_declarations.as_slice(),
Some(style.get())))
}
None => Arc::new(cascade($applicable_declarations.as_slice(), None)),
};
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref.get() {
None => fail!("no layout data"),
Some(ref mut layout_data) => {
let style = &mut layout_data.data.$style;
match *style {
None => (),
Some(ref previous_style) => {
layout_data.data.restyle_damage = Some(incremental::compute_damage(
previous_style.get(), computed_values.get()).to_int())
}
}
*style = Some(computed_values)
}
let computed_values = match parent_style {
Some(ref style) => {
Arc::new(cascade($applicable_declarations.as_slice(),
Some(style.get()),
initial_values))
}
None => Arc::new(cascade($applicable_declarations.as_slice(),
None,
initial_values)),
};
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref.get() {
None => fail!("no layout data"),
Some(ref mut layout_data) => {
let style = &mut layout_data.data.$style;
match *style {
None => (),
Some(ref previous_style) => {
layout_data.data.restyle_damage = Some(incremental::compute_damage(
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 }
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 }
/* Begin bidirectionality settings (do not change) */
@ -106,6 +111,8 @@ ul, ol, dl { page-break-before: avoid }
}
/* Servo additions */
:link { color: blue }
a:link,
area:link,
link:link { color: blue }
script { display: none }
style { display: none }
style { display: none }

View file

@ -193,9 +193,9 @@ impl BlockFlow {
let style = box_.style();
let (width, maybe_margin_left, maybe_margin_right) =
(MaybeAuto::from_style(style.Box.width, remaining_width),
MaybeAuto::from_style(style.Margin.margin_left, remaining_width),
MaybeAuto::from_style(style.Margin.margin_right, remaining_width));
(MaybeAuto::from_style(style.Box.get().width, remaining_width),
MaybeAuto::from_style(style.Margin.get().margin_left, remaining_width),
MaybeAuto::from_style(style.Margin.get().margin_right, remaining_width));
let (width, margin_left, margin_right) = self.compute_horiz(width,
maybe_margin_left,
@ -206,7 +206,7 @@ impl BlockFlow {
// 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'.
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),
maybe_margin_left,
maybe_margin_right,
@ -218,7 +218,7 @@ impl BlockFlow {
// 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'.
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 {
self.compute_horiz(Specified(computed_min_width),
maybe_margin_left,
@ -235,13 +235,13 @@ impl BlockFlow {
// CSS Section 10.3.5
fn compute_float_margins(&self, box_: &Box, remaining_width: Au) -> (Au, Au, Au) {
let style = box_.style();
let margin_left = MaybeAuto::from_style(style.Margin.margin_left,
let margin_left = MaybeAuto::from_style(style.Margin.get().margin_left,
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();
let shrink_to_fit = geometry::min(self.base.pref_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);
debug!("assign_widths_float -- width: {}", width);
return (width, margin_left, margin_right);
@ -376,7 +376,7 @@ impl BlockFlow {
// block per CSS 2.1 § 10.5.
// TODO: We need to pass in the correct containing block height
// 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,
Specified(value) => value
};
@ -516,7 +516,7 @@ impl BlockFlow {
box_.border.get().top + box_.border.get().bottom;
//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();
height = geometry::max(height, height_prop) + noncontent_height;
@ -719,7 +719,7 @@ impl Flow for BlockFlow {
let style = box_.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);
// 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();
// 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();
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();
let (width, margin_left, margin_right) = if self.is_float() {

View file

@ -373,7 +373,7 @@ impl Box {
}
(_, _) => {
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 => {
height = screen_height - position_offsets.top - position_offsets.bottom;
}
@ -408,7 +408,7 @@ impl Box {
}
(_, _) => {
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 => {
width = screen_width - position_offsets.left - position_offsets.right;
}
@ -446,14 +446,14 @@ impl Box {
}
let style = self.style();
let width = MaybeAuto::from_style(style.Box.width, Au::new(0)).specified_or_zero();
let margin_left = MaybeAuto::from_style(style.Margin.margin_left,
let width = MaybeAuto::from_style(style.Box.get().width, Au::new(0)).specified_or_zero();
let margin_left = MaybeAuto::from_style(style.Margin.get().margin_left,
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();
let padding_left = self.compute_padding_length(style.Padding.padding_left, Au::new(0));
let padding_right = self.compute_padding_length(style.Padding.padding_right, 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.get().padding_right, Au(0));
width + margin_left + margin_right + padding_left + padding_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,
style.Border.border_top_style),
width(style.Border.border_right_width,
style.Border.border_right_style),
width(style.Border.border_bottom_width,
style.Border.border_bottom_style),
width(style.Border.border_left_width,
style.Border.border_left_style)))
self.border.set(SideOffsets2D::new(width(style.Border.get().border_top_width,
style.Border.get().border_top_style),
width(style.Border.get().border_right_width,
style.Border.get().border_right_style),
width(style.Border.get().border_bottom_width,
style.Border.get().border_bottom_style),
width(style.Border.get().border_left_width,
style.Border.get().border_left_style)))
}
pub fn compute_positioned_offsets(&self, style: &ComputedValues, containing_width: Au, containing_height: Au) {
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(),
MaybeAuto::from_style(style.PositionOffsets.right, containing_width)
MaybeAuto::from_style(style.PositionOffsets.get().right, containing_width)
.specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.bottom, containing_height)
MaybeAuto::from_style(style.PositionOffsets.get().bottom, containing_height)
.specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.left, containing_width)
MaybeAuto::from_style(style.PositionOffsets.get().left, containing_width)
.specified_or_zero()));
}
/// Populates the box model padding parameters from the given computed style.
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),
self.compute_padding_length(style.Padding.padding_right,
self.compute_padding_length(style.Padding
.get()
.padding_right,
containing_block_width),
self.compute_padding_length(style.Padding.padding_bottom,
self.compute_padding_length(style.Padding
.get()
.padding_bottom,
containing_block_width),
self.compute_padding_length(style.Padding.padding_left,
self.compute_padding_length(style.Padding
.get()
.padding_left,
containing_block_width));
self.padding.set(padding)
}
@ -679,28 +687,28 @@ impl Box {
}
}
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
match (style.PositionOffsets.left, style.PositionOffsets.right) {
match (style.PositionOffsets.get().left, style.PositionOffsets.get().right) {
(LPA_Auto, _) => {
-MaybeAuto::from_style(style.PositionOffsets.right, block_width)
-MaybeAuto::from_style(style.PositionOffsets.get().right, block_width)
.specified_or_zero()
}
(_, _) => {
MaybeAuto::from_style(style.PositionOffsets.left, block_width)
MaybeAuto::from_style(style.PositionOffsets.get().left, block_width)
.specified_or_zero()
}
}
}
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, _) => {
-MaybeAuto::from_style(style.PositionOffsets.bottom, block_height)
-MaybeAuto::from_style(style.PositionOffsets.get().bottom, block_height)
.specified_or_zero()
}
(_, _) => {
MaybeAuto::from_style(style.PositionOffsets.top, block_height)
MaybeAuto::from_style(style.PositionOffsets.get().top, block_height)
.specified_or_zero()
}
}
@ -711,7 +719,7 @@ impl Box {
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.y = rel_pos.y + top_bottom(self.style(), container_block_size.height);
}
@ -720,9 +728,11 @@ impl Box {
match info.get() {
&Some(ref info) => {
for info in info.parent_info.iter() {
if info.style.get().Box.position == position::relative {
rel_pos.x = rel_pos.x + left_right(info.style.get(), container_block_size.width);
rel_pos.y = rel_pos.y + top_bottom(info.style.get(), container_block_size.height);
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.y = rel_pos.y + top_bottom(info.style.get(),
container_block_size.height);
}
}
},
@ -737,7 +747,7 @@ impl Box {
#[inline(always)]
pub fn clear(&self) -> Option<ClearType> {
let style = self.style();
match style.Box.clear {
match style.Box.get().clear {
clear::none => None,
clear::left => Some(ClearLeft),
clear::right => Some(ClearRight),
@ -755,20 +765,20 @@ impl Box {
debug!("(font style) start");
// 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 {
font_family::FamilyName(ref name) => (*name).clone(),
}
});
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);
FontStyle {
pt_size: font_size,
weight: my_style.Font.font_weight,
style: my_style.Font.font_style,
weight: my_style.Font.get().font_weight,
style: my_style.Font.get().font_style,
families: font_families,
}
}
@ -781,19 +791,19 @@ impl Box {
/// Returns the text alignment of the computed style of the nearest ancestor-or-self `Element`
/// node.
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 {
self.style().InheritedBox.line_height
self.style().InheritedBox.get().line_height
}
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 {
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
@ -804,7 +814,7 @@ impl Box {
/// model. Therefore, this is a best lower bound approximation, but the end result may actually
/// have the various decoration flags turned on afterward.
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.
@ -862,7 +872,7 @@ impl Box {
bg_rect.origin.y = box_info.baseline + offset.y - info.font_ascent;
bg_rect.size.height = info.font_ascent + info.font_descent;
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) {
lists.with_mut(|lists| {
@ -886,14 +896,14 @@ impl Box {
bg_rect.size.height = bg_rect.size.height + border.top + border.bottom;
let style = info.style.get();
let top_color = style.resolve_color(style.Border.border_top_color);
let right_color = style.resolve_color(style.Border.border_right_color);
let bottom_color = style.resolve_color(style.Border.border_bottom_color);
let left_color = style.resolve_color(style.Border.border_left_color);
let top_style = style.Border.border_top_style;
let right_style = style.Border.border_right_style;
let bottom_style = style.Border.border_bottom_style;
let left_style = style.Border.border_left_style;
let top_color = style.resolve_color(style.Border.get().border_top_color);
let right_color = style.resolve_color(style.Border.get().border_right_color);
let bottom_color = style.resolve_color(style.Border.get().border_bottom_color);
let left_color = style.resolve_color(style.Border.get().border_left_color);
let top_style = style.Border.get().border_top_style;
let right_style = style.Border.get().border_right_style;
let bottom_style = style.Border.get().border_bottom_style;
let left_style = style.Border.get().border_left_style;
lists.with_mut(|lists| {
@ -935,7 +945,7 @@ impl Box {
// inefficient. What we really want is something like "nearest ancestor element that
// doesn't have a box".
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) {
lists.with_mut(|lists| {
let solid_color_display_item = ~SolidColorDisplayItem {
@ -965,14 +975,14 @@ impl Box {
}
let style = self.style();
let top_color = style.resolve_color(style.Border.border_top_color);
let right_color = style.resolve_color(style.Border.border_right_color);
let bottom_color = style.resolve_color(style.Border.border_bottom_color);
let left_color = style.resolve_color(style.Border.border_left_color);
let top_style = style.Border.border_top_style;
let right_style = style.Border.border_right_style;
let bottom_style = style.Border.border_bottom_style;
let left_style = style.Border.border_left_style;
let top_color = style.resolve_color(style.Border.get().border_top_color);
let right_color = style.resolve_color(style.Border.get().border_right_color);
let bottom_color = style.resolve_color(style.Border.get().border_bottom_color);
let left_color = style.resolve_color(style.Border.get().border_left_color);
let top_style = style.Border.get().border_top_style;
let right_style = style.Border.get().border_right_style;
let bottom_style = style.Border.get().border_bottom_style;
let left_style = style.Border.get().border_left_style;
let mut abs_bounds = abs_bounds.clone();
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());
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;
}
@ -1047,7 +1057,7 @@ impl Box {
match self.specific {
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
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.
let mut flow_flags = flow::base(flow).flags_info.clone();
@ -1472,13 +1482,13 @@ impl Box {
}
ImageBox(ref image_box_info) => {
// 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,
container_width);
// FIXME(ksh8281): we shouldn't figure height this way
// 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,
Au::new(0));
@ -1520,11 +1530,11 @@ impl Box {
let width = image_box_info.computed_width();
// FIXME(ksh8281): we shouldn't assign height this way
// 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,
Au::new(0));
let height = match (self.style().Box.width,
let height = match (self.style().Box.get().width,
image_box_info.dom_width,
height) {
(LPA_Auto, None, Auto) => {
@ -1575,7 +1585,7 @@ impl Box {
/// Returns true if the contents should be clipped (i.e. if `overflow` is `hidden`).
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.

View file

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

View file

@ -21,7 +21,7 @@ use script::layout_interface::LayoutChan;
use servo_msg::constellation_msg::ConstellationChan;
use servo_net::local_image_cache::LocalImageCache;
use servo_util::geometry::Au;
use style::Stylist;
use style::{ComputedValues, Stylist};
#[thread_local]
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.
stylist: *Stylist,
/// The initial set of CSS properties.
initial_css_values: Arc<ComputedValues>,
/// The root node at which we're starting the layout.
reflow_root: OpaqueNode,
}

View file

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

View file

@ -107,7 +107,7 @@ impl RestyleDamage {
macro_rules! add_if_not_equal(
($old:ident, $new:ident, $damage: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),* ) );
}
})

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

View file

@ -163,7 +163,9 @@ fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode,
} else {
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.
let mut child_count = 0;

View file

@ -160,33 +160,111 @@ pub mod specified {
}
pub mod computed {
use cssparser;
pub use CSSColor = cssparser::Color;
pub use compute_CSSColor = super::super::longhands::computed_as_specified;
use super::*;
use super::super::longhands;
use super::super::{longhands, style_structs};
use servo_util::cowarc::CowArc;
pub use servo_util::geometry::Au;
pub struct Context {
current_color: cssparser::RGBA,
parent_font_size: Au,
font_size: Au,
font_weight: longhands::font_weight::computed_value::T,
position: longhands::position::SpecifiedValue,
float: longhands::float::SpecifiedValue,
color: longhands::color::computed_value::T,
parent_font_weight: longhands::font_weight::computed_value::T,
parent_font_size: longhands::font_size::computed_value::T,
font_size: longhands::font_size::computed_value::T,
positioned: bool,
floated: bool,
border_top_present: bool,
border_right_present: bool,
border_bottom_present: bool,
border_left_present: bool,
is_root_element: bool,
border_top_style: longhands::border_top_style::computed_value::T,
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,
use_parent_font_size: bool,
// 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]
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 {
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::Ex(value) => {
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)]
pub enum LengthOrPercentage {
LP_Length(Au),
@ -203,7 +294,7 @@ pub mod computed {
pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context)
-> LengthOrPercentage {
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),
}
}
@ -217,7 +308,7 @@ pub mod computed {
pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto,
context: &Context) -> LengthOrPercentageOrAuto {
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_Auto => LPA_Auto,
}
@ -232,7 +323,7 @@ pub mod computed {
pub fn compute_LengthOrPercentageOrNone(value: specified::LengthOrPercentageOrNone,
context: &Context) -> LengthOrPercentageOrNone {
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_None => LPN_None,
}

View file

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