diff --git a/src/components/main/css/matching.rs b/src/components/main/css/matching.rs index 43deb7ffd92..b637bf9a5cb 100644 --- a/src/components/main/css/matching.rs +++ b/src/components/main/css/matching.rs @@ -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>, @@ -43,12 +43,14 @@ pub trait MatchMethods { stylist: &Stylist, layout_chan: &LayoutChan, applicable_declarations: &mut ApplicableDeclarations, + initial_values: &ComputedValues, parent: Option); fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations); unsafe fn cascade_node(&self, parent: Option, + 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) { 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, + 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) + } } }} ); diff --git a/src/components/main/css/user-agent.css b/src/components/main/css/user-agent.css index cc23479b21f..b8bf8442995 100644 --- a/src/components/main/css/user-agent.css +++ b/src/components/main/css/user-agent.css @@ -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 } \ No newline at end of file +style { display: none } diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs index fcbfba3b497..cac4cee4c37 100644 --- a/src/components/main/layout/block.rs +++ b/src/components/main/layout/block.rs @@ -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() { diff --git a/src/components/main/layout/box_.rs b/src/components/main/layout/box_.rs index f904e6a1d00..bcbb0ccebd1 100644 --- a/src/components/main/layout/box_.rs +++ b/src/components/main/layout/box_.rs @@ -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) -> Point2D { - 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 { 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. diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs index 55a1cd92db4..398a0479042 100644 --- a/src/components/main/layout/construct.rs +++ b/src/components/main/layout/construct.rs @@ -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, } diff --git a/src/components/main/layout/context.rs b/src/components/main/layout/context.rs index 5385e2bcb99..f3a1ac59bd9 100644 --- a/src/components/main/layout/context.rs +++ b/src/components/main/layout/context.rs @@ -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, + /// The root node at which we're starting the layout. reflow_root: OpaqueNode, } diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs index db38b3327ce..e1daba18667 100644 --- a/src/components/main/layout/flow.rs +++ b/src/components/main/layout/flow.rs @@ -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 diff --git a/src/components/main/layout/incremental.rs b/src/components/main/layout/incremental.rs index 0b611f896d6..707367952f4 100644 --- a/src/components/main/layout/incremental.rs +++ b/src/components/main/layout/incremental.rs @@ -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),* ) ); } }) diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs index b14c3dc6be6..ee718001f43 100644 --- a/src/components/main/layout/inline.rs +++ b/src/components/main/layout/inline.rs @@ -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. diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index 7868f57c68c..d85d0612716 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -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, + /// The workers that we use for parallel operation. parallel_traversal: Option>, @@ -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() }; diff --git a/src/components/main/layout/parallel.rs b/src/components/main/layout/parallel.rs index 8a08416b8c6..8d6dd029413 100644 --- a/src/components/main/layout/parallel.rs +++ b/src/components/main/layout/parallel.rs @@ -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; diff --git a/src/components/style/common_types.rs b/src/components/style/common_types.rs index fad92568352..13545416cab 100644 --- a/src/components/style/common_types.rs +++ b/src/components/style/common_types.rs @@ -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, + font: &CowArc, + css_box: &CowArc, + border: &CowArc, + 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, } diff --git a/src/components/style/properties.rs.mako b/src/components/style/properties.rs.mako index 7c3da2b980b..10dc44ad2af 100644 --- a/src/components/style/properties.rs.mako +++ b/src/components/style/properties.rs.mako @@ -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(value: T, _context: &mut computed::Context) -> T { + pub fn computed_as_specified(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 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> { @@ -111,8 +111,8 @@ pub mod longhands { - <%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 { one_component_value(input).and_then(from_component_value) @@ -120,8 +120,8 @@ pub mod longhands { - <%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 { - <%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; @@ -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 - } - + ${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 { 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) } } % 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 { } - ${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 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) + } /// | /// TODO: support and pub fn from_component_value(input: &ComponentValue) -> Option { @@ -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, % 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 } } } - ${apply("High")} - ${apply("Normal")} + ${apply(True)} + context.use_parent_font_size = false; + ${apply(False)} ComputedValues { % for style_struct in STYLE_STRUCTS: diff --git a/src/components/style/style.rs b/src/components/style/style.rs index afd3787436d..843c06b73ab 100644 --- a/src/components/style/style.rs +++ b/src/components/style/style.rs @@ -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}; diff --git a/src/components/util/cowarc.rs b/src/components/util/cowarc.rs new file mode 100644 index 00000000000..c09a059ec22 --- /dev/null +++ b/src/components/util/cowarc.rs @@ -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 { + ref_count: AtomicUint, + data: T, +} + +#[unsafe_no_drop_flag] +pub struct CowArc { + priv ptr: *mut CowArcAlloc, +} + +#[unsafe_destructor] +impl Drop for CowArc { + #[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 = cast::transmute(self.ptr); + self.ptr = ptr::mut_null() + } + } + } +} + +impl Eq for CowArc { + fn eq(&self, other: &CowArc) -> bool { + self.get() == other.get() + } +} + +impl Clone for CowArc { + #[inline] + fn clone(&self) -> CowArc { + unsafe { + drop((*self.ptr).ref_count.fetch_add(1, SeqCst)); + } + CowArc { + ptr: self.ptr + } + } +} + +impl CowArc { + #[inline] + pub fn new(value: T) -> CowArc { + 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) + } + } +} + diff --git a/src/components/util/util.rs b/src/components/util/util.rs index 05870d12678..ab66e8f855c 100644 --- a/src/components/util/util.rs +++ b/src/components/util/util.rs @@ -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;