servo: Inherit CSS styles
authorBrian Anderson <banderson@mozilla.com>
Tue, 06 Nov 2012 15:11:50 -0800
changeset 333212 f6dd36b6465cc5df618cacb0bc2303566b99c12a
parent 333211 d22e6c4d9f1aa818733b2ab216916cef00c8fc2b
child 333213 bbbd3d61d6e1e692becbfa52c9f84c947a61b391
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
servo: Inherit CSS styles Source-Repo: https://github.com/servo/servo Source-Revision: 25ad3849743cb3c033379e384436afb259060aa2
servo/src/servo/css/matching.rs
servo/src/servo/css/node_style.rs
servo/src/servo/css/node_util.rs
servo/src/servo/dom/node.rs
servo/src/servo/layout/box.rs
--- a/servo/src/servo/css/matching.rs
+++ b/servo/src/servo/css/matching.rs
@@ -1,39 +1,68 @@
 /**
  * High-level interface to CSS selector matching.
  */
 use std::arc::{ARC, get, clone};
 use dom::node::{Node, NodeTree};
 use newcss::select::{SelectCtx, SelectResults};
+use newcss::complete::CompleteSelectResults;
 use layout::context::LayoutContext;
 use select_handler::NodeSelectHandler;
 
 trait MatchMethods {
     fn restyle_subtree(select_ctx: &SelectCtx);
 }
 
 impl Node : MatchMethods {
     /**
      * Performs CSS selector matching on a subtree.
 
      * This is, importantly, the function that updates the layout data for
      * the node (the reader-auxiliary box in the COW model) with the
      * computed style.
      */
     fn restyle_subtree(select_ctx: &SelectCtx) {
+
+        // Only elements have styles
+        if self.is_element() {
+            let select_handler = NodeSelectHandler {
+                node: self
+            };
+            let incomplete_results = select_ctx.select_style(&self, &select_handler);
+            // Combine this node's results with its parent's to resolve all inherited values
+            let complete_results = compose_results(&self, move incomplete_results);
+            self.set_css_select_results(move complete_results);
+        }
+
         let mut i = 0u;
         
         for NodeTree.each_child(&self) |kid| {
             i = i + 1u;
             kid.restyle_subtree(select_ctx); 
         }
-
-        // Only elements have styles
-        if self.is_element() {
-            let select_handler = NodeSelectHandler {
-                node: self
-            };
-            let style = select_ctx.select_style(&self, &select_handler);
-            self.set_css_select_results(move style);
-        }
     }
 }
+
+fn compose_results(node: &Node, results: SelectResults) -> CompleteSelectResults {
+    match find_parent_element_node(node) {
+        None => CompleteSelectResults::new_root(move results),
+        Some(parent_node) => {
+            let parent_results = parent_node.get_css_select_results();
+            CompleteSelectResults::new_from_parent(parent_results, move results)
+        }
+    }    
+}
+
+fn find_parent_element_node(node: &Node) -> Option<Node> {
+    use util::tree::parent;
+
+    match parent(&NodeTree, node) {
+        Some(ref parent) => {
+            if parent.is_element() {
+                Some(*parent)
+            } else {
+                find_parent_element_node(parent)
+            }
+        }
+        None => None
+    }
+}
\ No newline at end of file
--- a/servo/src/servo/css/node_style.rs
+++ b/servo/src/servo/css/node_style.rs
@@ -1,152 +1,15 @@
-/*!
-Calculates computed Node styles, based on CSS SelectResults.
-
-These methods mostly defer to the Node's ComputedStyle object.
-The only exception is that this is where inheritance is resolved.
-*/
-
 use dom::node::Node;
-use newcss::color::{Color, rgba};
-use newcss::units::{Length, Px};
-use newcss::values::{CSSValue, Specified, Inherit};
-use newcss::values::{CSSMargin, CSSMarginLength};
-use newcss::values::{CSSBorderWidth, CSSBorderWidthLength};
-use newcss::values::{CSSDisplay, CSSDisplayBlock};
-use newcss::values::{CSSPosition, CSSPositionRelative};
-use newcss::values::{CSSFloat, CSSFloatNone};
-use newcss::values::{CSSWidth, CSSWidthLength};
-use newcss::values::{CSSHeight, CSSHeightLength};
-use newcss::computed::ComputedStyle;
+use newcss::complete::CompleteStyle;
 
 /// Node mixin providing `style` method that returns a `NodeStyle`
 trait StyledNode {
-    fn style(&self) -> NodeStyle/&self;
+    fn style(&self) -> CompleteStyle/&self;
 }
 
 impl Node: StyledNode {
-    fn style(&self) -> NodeStyle/&self {
+    fn style(&self) -> CompleteStyle/&self {
         assert self.is_element(); // Only elements can have styles
-        NodeStyle::new(self)
+        let results = self.get_css_select_results();
+        results.computed_style()
     }
 }
-
-/// Provides getters for calculated node styles
-pub struct NodeStyle {
-    priv node: &Node
-}
-
-impl NodeStyle {
-
-    static fn new(node: &r/Node) -> NodeStyle/&r {
-        NodeStyle {
-            node: node
-        }
-    }
-
-    // CSS 2.1, Section 8 - Box model
-
-    fn margin_top(&self) -> CSSMargin {
-        resolve(self, CSSMarginLength(Px(0.0)), |cs| cs.margin_top() )
-    }
-
-    fn margin_right(&self) -> CSSMargin {
-        resolve(self, CSSMarginLength(Px(0.0)), |cs| cs.margin_right() )
-    }
-
-    fn margin_bottom(&self) -> CSSMargin {
-        resolve(self, CSSMarginLength(Px(0.0)), |cs| cs.margin_bottom() )
-    }
-
-    fn margin_left(&self) -> CSSMargin {
-        resolve(self, CSSMarginLength(Px(0.0)), |cs| cs.margin_left() )
-    }
-
-    fn border_top_width(&self) -> CSSBorderWidth {
-        resolve(self, CSSBorderWidthLength(Px(0.0)), |cs| cs.border_top_width() )
-    }
-
-    fn border_right_width(&self) -> CSSBorderWidth {
-        resolve(self, CSSBorderWidthLength(Px(0.0)), |cs| cs.border_right_width() )
-    }
-
-    fn border_bottom_width(&self) -> CSSBorderWidth {
-        resolve(self, CSSBorderWidthLength(Px(0.0)), |cs| cs.border_bottom_width() )
-    }
-
-    fn border_left_width(&self) -> CSSBorderWidth {
-        resolve(self, CSSBorderWidthLength(Px(0.0)), |cs| cs.border_left_width() )
-    }
-
-    fn border_top_color(&self) -> Color {
-        resolve(self, rgba(255, 255, 255, 0.0), |cs| cs.border_top_color() )
-    }
-
-    fn border_right_color(&self) -> Color {
-        resolve(self, rgba(255, 255, 255, 0.0), |cs| cs.border_right_color() )
-    }
-
-    fn border_bottom_color(&self) -> Color {
-        resolve(self, rgba(255, 255, 255, 0.0), |cs| cs.border_bottom_color() )
-    }
-
-    fn border_left_color(&self) -> Color {
-        resolve(self, rgba(255, 255, 255, 0.0), |cs| cs.border_left_color() )
-    }
-
-    // CSS 2.1, Section 9 - Visual formatting model
-
-    fn display(&self) -> CSSDisplay {
-        // FIXME: Shouldn't be passing false here
-        resolve(self, CSSDisplayBlock, |cs| cs.display(false) )
-    }
-
-    fn position(&self) -> CSSPosition {
-        resolve(self, CSSPositionRelative, |cs| cs.position() )
-    }
-
-    fn float(&self) -> CSSFloat {
-        resolve(self, CSSFloatNone, |cs| cs.float() )
-    }
-
-    // CSS 2.1, Section 10 - Visual formatting model details
-
-    fn width(&self) -> CSSWidth {
-        resolve(self, CSSWidthLength(Px(0.0)), |cs| cs.width() )
-    }
-
-    fn height(&self) -> CSSHeight {
-        resolve(self, CSSHeightLength(Px(0.0)), |cs| cs.height() )
-    }
-
-    // CSS 2.1, Section 11 - Visual effects
-
-    // CSS 2.1, Section 12 - Generated content, automatic numbering, and lists
-
-    // CSS 2.1, Section 13 - Paged media
-
-    // CSS 2.1, Section 14 - Colors and Backgrounds
-
-    fn background_color(&self) -> Color {
-        resolve(self, rgba(0, 0, 0, 0.0), |cs| cs.background_color() )
-    }
-
-    // CSS 2.1, Section 15 - Fonts
-
-    // CSS 2.1, Section 16 - Text
-
-    // CSS 2.1, Section 17 - Tables
-
-    // CSS 2.1, Section 18 - User interface
-
-}
-
-fn resolve<T>(node_style: &NodeStyle, default: T, get: &fn(cs: ComputedStyle) -> CSSValue<T>) -> T {
-    let node = node_style.node;
-    let select_res = node.get_css_select_results();
-    let computed = select_res.computed_style();
-    let value = get(computed);
-    match move value {
-        Inherit => /* FIXME: need inheritance */ move default,
-        Specified(move value) => move value,
-    }
-}
\ No newline at end of file
--- a/servo/src/servo/css/node_util.rs
+++ b/servo/src/servo/css/node_util.rs
@@ -1,39 +1,39 @@
 use dom::node::Node;
-use newcss::select::SelectResults;
+use newcss::complete::CompleteSelectResults;
 use std::cell::Cell;
 
 trait NodeUtil {
-    fn get_css_select_results() -> &self/SelectResults;
-    fn set_css_select_results(decl : SelectResults);
+    fn get_css_select_results() -> &self/CompleteSelectResults;
+    fn set_css_select_results(decl : CompleteSelectResults);
 }
 
 impl Node: NodeUtil {
     /** 
      * Provides the computed style for the given node. If CSS selector
      * Returns the style results for the given node. If CSS selector
      * matching has not yet been performed, fails.
      * FIXME: This isn't completely memory safe since the style is
      * stored in a box that can be overwritten
      */
-    fn get_css_select_results() -> &self/SelectResults {
+    fn get_css_select_results() -> &self/CompleteSelectResults {
         if !self.has_aux() {
             fail ~"style() called on a node without aux data!";
         }
         unsafe { &*self.aux( |x| {
             match x.style {
                 Some(ref style) => ptr::to_unsafe_ptr(style),
                 None => fail ~"style() called on node without a style!"
             }
         })}
     }
 
     /**
     Update the computed style of an HTML element with a style specified by CSS.
     */
-    fn set_css_select_results(decl : SelectResults) {
+    fn set_css_select_results(decl : CompleteSelectResults) {
         let decl = Cell(move decl);
         do self.aux |data| {
             data.style = Some(decl.take())
         }
     }
 }
--- a/servo/src/servo/dom/node.rs
+++ b/servo/src/servo/dom/node.rs
@@ -1,10 +1,10 @@
 /* The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. */
-use newcss::select::SelectResults;
+use newcss::complete::CompleteSelectResults;
 use dom::bindings;
 use dom::document::Document;
 use dom::element::{Attr, ElementData};
 use dom::window::Window;
 use geom::size::Size2D;
 use js::crust::*;
 use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
 use js::jsapi::{JSClass, JSObject, JSPropertySpec, JSContext, jsid, JSVal, JSBool};
@@ -113,17 +113,17 @@ fn define_bindings(compartment: &bare_co
 
 
 /** The COW rd_aux data is a (weak) pointer to the layout data,
    defined by this `LayoutData` enum. It contains the CSS style object
    as well as the primary `RenderBox`.
 
    Note that there may be multiple boxes per DOM node. */
 enum LayoutData = {
-    mut style: Option<SelectResults>,
+    mut style: Option<CompleteSelectResults>,
     mut flow:  Option<@FlowContext>
 };
 
 type Node = cow::Handle<NodeData, LayoutData>;
 
 type NodeScope = cow::Scope<NodeData, LayoutData>;
 
 fn NodeScope() -> NodeScope {
--- a/servo/src/servo/layout/box.rs
+++ b/servo/src/servo/layout/box.rs
@@ -3,17 +3,18 @@
 use newcss::color::rgb;
 use arc = std::arc;
 use arc::ARC;
 use au = gfx::geometry;
 use au::Au;
 use core::dvec::DVec;
 use core::to_str::ToStr;
 use core::rand;
-use css::node_style::{NodeStyle, StyledNode};
+use css::node_style::StyledNode;
+use newcss::complete::CompleteStyle;
 use newcss::units::{BoxSizing, Length, Px};
 use newcss::values::{CSSDisplay, Specified, CSSBackgroundColorColor, CSSBackgroundColorTransparent};
 use newcss::values::{CSSBorderColor, CSSPositionAbsolute};
 use newcss::values::{CSSBorderWidthLength, CSSBorderWidthMedium};
 use newcss::color::{Color, rgba};
 use dom::element::{ElementKind, HTMLDivElement, HTMLImageElement};
 use dom::node::{Element, Node, NodeData, NodeKind, NodeTree};
 use geom::rect::Rect;
@@ -359,17 +360,17 @@ impl RenderBox : RenderBoxMethods {
 
     /* The box fromed by the margin edge, as defined in CSS 2.1 Section 8.1.
        Coordinates are relative to the owning flow. */
     pure fn margin_box() -> Rect<Au> {
         // TODO: actually compute content_box + padding + border + margin
         self.content_box()
     }
 
-    fn style(&self) -> NodeStyle/&self {
+    fn style(&self) -> CompleteStyle/&self {
         let d: &self/RenderBoxData = self.d();
         d.node.style()
     }
 
     // TODO: to implement stacking contexts correctly, we need to
     // create a set of display lists, one per each layer of a stacking
     // context. (CSS 2.1, Section 9.9.1). Each box is passed the list
     // set representing the box's stacking context. When asked to