From fd3ade2a3c822fcc1568f9c3e31981d202d38be7 Mon Sep 17 00:00:00 2001 From: "Brian J. Burg" Date: Fri, 7 Sep 2012 17:00:09 -0700 Subject: [PATCH] Redo representation of CSS values, and many other related things. --- src/servo/css/parser.rs | 24 +- src/servo/css/parser_util.rs | 81 ++++--- src/servo/css/resolve/apply.rs | 118 +++++----- src/servo/css/resolve/matching.rs | 16 +- src/servo/css/styles.rs | 50 ++-- src/servo/css/values.rs | 279 ++++++++++++++++++----- src/servo/layout/base.rs | 13 +- src/servo/layout/block.rs | 10 +- src/servo/layout/box_builder.rs | 34 +-- src/servo/layout/display_list_builder.rs | 14 +- src/servo/layout/inline.rs | 10 +- 11 files changed, 413 insertions(+), 236 deletions(-) diff --git a/src/servo/css/parser.rs b/src/servo/css/parser.rs index 2e02d154306..a0fa5021692 100644 --- a/src/servo/css/parser.rs +++ b/src/servo/css/parser.rs @@ -3,8 +3,7 @@ // TODO: fail according to the css spec instead of failing when things // are not as expected -use css::values::{TextColor, BackgroundColor, FontSize, Height, Width, - Display, StyleDeclaration}; +use css::values::*; // Disambiguate parsed Selector, Rule values from tokens use css = css::values; use tok = lexer; @@ -156,17 +155,20 @@ impl TokenReader : ParserMethods { match tok { tok::EndDescription => { break; } tok::Description(prop, val) => { - let desc = match prop { - // TODO: have color parsing return an option instead of a real value - ~"background-color" => parse_color(val).map(|res| BackgroundColor(res)), - ~"color" => parse_color(val).map(|res| TextColor(res)), - ~"display" => parse_display_type(val).map(|res| Display(res)), - ~"font-size" => parse_font_size(val).map(|res| FontSize(res)), - ~"height" => parse_size(val).map(|res| Height(res)), - ~"width" => parse_size(val).map(|res| Width(res)), + let desc : Option = match prop { + // TODO: have color parsing return a ParseResult instead of a real value + ~"background-color" => parse_color(val).map(|res| BackgroundColor(Specified(BgColor(res)))), + ~"color" => parse_color(val).map(|res| Color(Specified(TextColor(res)))), + ~"display" => parse_display_type(val).extract(|res| Display(res)), + ~"font-size" => parse_font_size(val).extract(|res| FontSize(res)), + ~"height" => parse_box_sizing(val).extract(|res| Height(res)), + ~"width" => parse_box_sizing(val).extract(|res| Width(res)), _ => { #debug["Recieved unknown style property '%s'", val]; None } }; - desc.map(|res| push(desc_list, res)); + match desc { + Some(d) => push(desc_list, d), + None => { #debug["Couldn't parse value '%s' for property '%s'", val, prop] } + } } tok::Eof => { return None; } tok::StartDescription | tok::Descendant | tok::Child | tok::Sibling diff --git a/src/servo/css/parser_util.rs b/src/servo/css/parser_util.rs index 0d45f001e23..14a38d5cf8e 100644 --- a/src/servo/css/parser_util.rs +++ b/src/servo/css/parser_util.rs @@ -1,63 +1,76 @@ #[doc = "Helper functions to parse values of specific attributes."] -use css::values::{DisplayType, Inline, Block, DisplayNone}; -use css::values::{Unit, Pt, Mm, Px, Percent, Auto}; +use css::values::*; use str::{pop_char, from_chars}; use float::from_str; use option::map; export parse_font_size; export parse_size; +export parse_box_sizing; export parse_display_type; -fn parse_unit(str : ~str) -> Option { + +fn parse_length(str : ~str) -> Option { + // TODO: use these once we stop lexing below + const PTS_PER_INCH: float = 72.0; + const CM_PER_INCH: float = 2.54; + const PX_PER_PT: float = 1.0 / 0.75; + match str { - s if s.ends_with(~"%") => from_str(str.substr(0, str.len() - 1)).map(|f| Percent(f)), - s if s.ends_with(~"in") => from_str(str.substr(0, str.len() - 2)).map(|f| Pt(72.0*f)), - s if s.ends_with(~"cm") => from_str(str.substr(0, str.len() - 2)).map(|f| Mm(10.0*f)), - s if s.ends_with(~"mm") => from_str(str.substr(0, str.len() - 2)).map(|f| Mm(f)), - s if s.ends_with(~"pt") => from_str(str.substr(0, str.len() - 2)).map(|f| Pt(f)), - s if s.ends_with(~"pc") => from_str(str.substr(0, str.len() - 2)).map(|f| Pt(12.0*f)), + s if s.ends_with(~"in") => from_str(str.substr(0, str.len() - 2)).map(|f| Px(1.0/0.75 * 72.0 * f)), + s if s.ends_with(~"cm") => from_str(str.substr(0, str.len() - 2)).map(|f| Px(f / 2.54 * 72.0 * 1.0/0.75)), + s if s.ends_with(~"mm") => from_str(str.substr(0, str.len() - 2)).map(|f| Px(f * 0.1 / 2.54 * 72.0 * 1.0/0.75)), + s if s.ends_with(~"pt") => from_str(str.substr(0, str.len() - 2)).map(|f| Px(1.0/0.75 * f)), + s if s.ends_with(~"pc") => from_str(str.substr(0, str.len() - 2)).map(|f| Px(1.0/0.75 * 12.0 * f)), s if s.ends_with(~"px") => from_str(str.substr(0, str.len() - 2)).map(|f| Px(f)), - s if s.ends_with(~"ex") | s.ends_with(~"em") => fail ~"Em and Ex sizes not yet supported", + s if s.ends_with(~"em") => from_str(str.substr(0, str.len() - 2)).map(|f| Em(f)), + s if s.ends_with(~"ex") => from_str(str.substr(0, str.len() - 2)).map(|f| Em(0.5*f)), _ => None, } } -fn parse_font_size(str : ~str) -> Option { - // The default pixel size, not sure if this is accurate. - let default = 16.0; - +fn parse_absolute_size(str : ~str) -> ParseResult { match str { - ~"xx-small" => Some(Px(0.6*default)), - ~"x-small" => Some(Px(0.75*default)), - ~"small" => Some(Px(8.0/9.0*default)), - ~"medium" => Some(Px(default)), - ~"large" => Some(Px(1.2*default)), - ~"x-large" => Some(Px(1.5*default)), - ~"xx-large" => Some(Px(2.0*default)), - ~"smaller" => Some(Percent(80.0)), - ~"larger" => Some(Percent(125.0)), - ~"inherit" => Some(Percent(100.0)), - _ => parse_unit(str), + ~"xx-small" => Value(XXSmall), + ~"x-small" => Value(XSmall), + ~"small" => Value(Small), + ~"medium" => Value(Medium), + ~"large" => Value(Large), + ~"x-large" => Value(XLarge), + ~"xx-large" => Value(XXLarge), + _ => Fail } } +fn parse_relative_size(str: ~str) -> ParseResult { + match str { + ~"smaller" => Value(Smaller), + ~"larger" => Value(Larger), + _ => Fail + } +} + +fn parse_font_size(str: ~str) -> ParseResult { + // TODO: complete me + Value(LengthSize(Px(14.0))) +} + // For width / height, and anything else with the same attribute values -fn parse_size(str : ~str) -> Option { +fn parse_box_sizing(str : ~str) -> ParseResult { match str { - ~"auto" => Some(Auto), - ~"inherit" => Some(Percent(100.0)), - _ => parse_unit(str), + ~"auto" => Value(BoxAuto), + ~"inherit" => CSSInherit, + _ => Fail, } } -fn parse_display_type(str : ~str) -> Option { +fn parse_display_type(str : ~str) -> ParseResult { match str { - ~"inline" => Some(Inline), - ~"block" => Some(Block), - ~"none" => Some(DisplayNone), - _ => { #debug["Recieved unknown display value '%s'", str]; None } + ~"inline" => Value(DisplayInline), + ~"block" => Value(DisplayBlock), + ~"none" => Value(DisplayNone), + _ => { #debug["Recieved unknown display value '%s'", str]; Fail } } } diff --git a/src/servo/css/resolve/apply.rs b/src/servo/css/resolve/apply.rs index 91090125040..1b35b35251c 100644 --- a/src/servo/css/resolve/apply.rs +++ b/src/servo/css/resolve/apply.rs @@ -1,6 +1,6 @@ #[doc="Applies the appropriate CSS style to boxes."] -import dom::base::{Element, HTMLImageElement, Node}; +import dom = dom::base; import gfx::geometry::au_to_px; import layout::base::{Box, BTree, NTree, LayoutData, SpecifiedStyle, ImageHolder, BlockBox, InlineBox, IntrinsicBox, TextBox}; @@ -8,7 +8,28 @@ import layout::traverse::{top_down_traversal}; import std::net::url::Url; import resource::image_cache_task::ImageCacheTask; -import css::values::{Percent, Mm, Pt, Px, Auto, PtToPx, MmToPx}; +import css::values::*; + +trait ResolveMethods { + pure fn initial() -> T; +} + +impl CSSValue : ResolveMethods { + pure fn initial() -> CSSBackgroundColor { return BgTransparent; } +} + +impl CSSValue : ResolveMethods { + pure fn initial() -> CSSDisplay { return DisplayInline; } +} + +impl CSSValue : ResolveMethods { + pure fn initial() -> BoxSizing { return BoxAuto; } +} + +impl CSSValue : ResolveMethods { + pure fn initial() -> CSSFontSize { return AbsoluteSize(Medium); } +} + struct StyleApplicator { box: @Box; @@ -17,6 +38,7 @@ struct StyleApplicator { reflow: fn~(); } + fn apply_style(box: @Box, doc_url: &Url, image_cache_task: ImageCacheTask, reflow: fn~()) { let applicator = StyleApplicator { box: box, @@ -28,6 +50,8 @@ fn apply_style(box: @Box, doc_url: &Url, image_cache_task: ImageCacheTask, reflo applicator.apply_css_style(); } +// TODO: this is misleadingly-named. It is actually trying to resolve CSS 'inherit' values. + #[doc="A wrapper around a set of functions that can be applied as a top-down traversal of layout boxes."] fn inheritance_wrapper(box : @Box, doc_url: &Url, image_cache_task: ImageCacheTask, reflow: fn~()) { @@ -38,66 +62,51 @@ fn inheritance_wrapper(box : @Box, doc_url: &Url, image_cache_task: ImageCacheTa reflow: reflow }; applicator.apply_style(); - inhereit_height(box); - inhereit_width(box); + inherit_fontsize(box); + inherit_height(box); + inherit_width(box); } +/* Turns symbolic (abs, rel) and relative font sizes into absolute lengths */ + fn inherit_fontsize(box : @Box) { + // TODO: complete this + return + } + #[doc="Compute the specified height of a layout box based on it's css specification and its parent's height."] -fn inhereit_height(box : @Box) { +fn inherit_height(box : @Box) { let style = box.node.get_specified_style(); - + let inherit_val = match box.tree.parent { + None => style.height.initial(), + Some(node) => node.appearance.height + }; + box.appearance.height = match style.height { - None => Auto, - Some(h) => match h { - Auto | Px(*) => h, - Pt(*) => PtToPx(h), - Mm(*) => MmToPx(h), - Percent(em) => { - match box.tree.parent { - None => Auto, - Some(parent) => { - match parent.appearance.height { - //This is a poorly constrained case, so we ignore the percentage - Auto => Auto, - Px(f) => Px(em*f/100.0), - Percent(*) | Mm(*) | Pt(*) => { - fail ~"failed inheriting heights, parent should only be Px or Auto" - } - } - } - } - } + Initial => style.height.initial(), + Inherit => inherit_val, + Specified(val) => match val { // BoxSizing + BoxPercent(*) | BoxAuto | BoxLength(Px(_)) => val, + BoxLength(Em(n)) => BoxLength(Px(n * box.appearance.font_size.abs())) } } } #[doc="Compute the specified width of a layout box based on it's css specification and its parent's width."] -fn inhereit_width(box : @Box) { +fn inherit_width(box : @Box) { let style = box.node.get_specified_style(); - + let inherit_val = match box.tree.parent { + None => style.height.initial(), + Some(node) => node.appearance.width + }; + box.appearance.width = match style.width { - None => Auto, - Some(h) => match h { - Auto | Px(*) => h, - Pt(*) => PtToPx(h), - Mm(*) => MmToPx(h), - Percent(em) => { - match box.tree.parent { - None => Auto, - Some(parent) => { - match parent.appearance.width { - //This is a poorly constrained case, so we ignore the percentage - Auto => Auto, - Px(f) => Px(em*f/100.0), - Percent(*) | Mm(*) | Pt(*) => { - fail ~"failed inheriting widths, parent should only be Px or Auto" - } - } - } - } - } + Initial => style.width.initial(), + Inherit => inherit_val, + Specified(val) => match val { // BoxSizing + BoxPercent(*) | BoxAuto | BoxLength(Px(_)) => val, + BoxLength(Em(n)) => BoxLength(Px(n * box.appearance.font_size.abs())) } } } @@ -124,16 +133,9 @@ impl StyleApplicator { // Right now, we only handle images. do self.box.node.read |node| { match node.kind { - ~Element(element) => { - let style = self.box.node.get_specified_style(); - - self.box.appearance.background_color = match style.background_color { - Some(col) => col, - None => node.kind.default_color() - }; - + ~dom::Element(element) => { match element.kind { - ~HTMLImageElement(*) => { + ~dom::HTMLImageElement(*) => { let url = element.get_attr(~"src"); if url.is_some() { @@ -192,7 +194,7 @@ mod test { let g1_box = child_box.tree.first_child.get(); let g2_box = child_box.tree.last_child.get(); - top_down_traversal(parent_box.get(), inhereit_height); + top_down_traversal(parent_box.get(), inherit_height); assert parent_box.get().appearance.height == Px(100.0); assert child_box.appearance.height == Auto; diff --git a/src/servo/css/resolve/matching.rs b/src/servo/css/resolve/matching.rs index 48b23c225e2..04f35f67524 100644 --- a/src/servo/css/resolve/matching.rs +++ b/src/servo/css/resolve/matching.rs @@ -4,9 +4,7 @@ import dom::base::{LayoutData}; import dom::base; import base::{ElementData, Node, Text}; -import values::{Selector, StyleDeclaration, FontSize, Display, TextColor, BackgroundColor, - Stylesheet, Element, Child, Descendant, Sibling, Attr, Exact, Exists, Includes, - StartsWith, Width, Height}; +import values::*; import styles::{SpecifiedStyle}; #[doc="Check if a CSS attribute matches the attribute of an HTML element."] @@ -169,12 +167,12 @@ impl Node : PrivStyleMethods { fn update_style(decl : StyleDeclaration) { self.aux(|layout| { match decl { - BackgroundColor(col) => layout.specified_style.background_color = Some(col), - Display(dis) => layout.specified_style.display_type = Some(dis), - FontSize(size) => layout.specified_style.font_size = Some(size), - Height(size) => layout.specified_style.height = Some(size), - TextColor(col) => layout.specified_style.text_color = Some(col), - Width(size) => layout.specified_style.width = Some(size) + BackgroundColor(col) => layout.specified_style.background_color = col, + Display(dis) => layout.specified_style.display_type = dis, + FontSize(size) => layout.specified_style.font_size = size, + Height(size) => layout.specified_style.height = size, + Color(col) => layout.specified_style.text_color = col, + Width(size) => layout.specified_style.width = size }; }) } diff --git a/src/servo/css/styles.rs b/src/servo/css/styles.rs index 63368e3d522..90c16edbd5c 100644 --- a/src/servo/css/styles.rs +++ b/src/servo/css/styles.rs @@ -2,7 +2,7 @@ import std::arc::{ARC, get, clone}; -import css::values::{DisplayType, DisplayNone, Inline, Block, Unit, Auto}; +import css::values::*; import css::values::Stylesheet; import dom::base::{HTMLDivElement, HTMLHeadElement, HTMLImageElement, UnknownElement, HTMLScriptElement}; import dom::base::{Comment, Doctype, Element, Node, NodeKind, Text}; @@ -10,19 +10,19 @@ import util::color::{Color, rgb}; import util::color::css_colors::{white, black}; import layout::base::{LayoutData, NTree}; -type SpecifiedStyle = {mut background_color : Option, - mut display_type : Option, - mut font_size : Option, - mut height : Option, - mut text_color : Option, - mut width : Option +type SpecifiedStyle = {mut background_color : CSSValue, + mut display_type : CSSValue, + mut font_size : CSSValue, + mut height : CSSValue, + mut text_color : CSSValue, + mut width : CSSValue }; trait DefaultStyleMethods { fn default_color() -> Color; - fn default_display_type() -> DisplayType; - fn default_width() -> Unit; - fn default_height() -> Unit; + fn default_display_type() -> CSSDisplay; + fn default_width() -> BoxSizing; + fn default_height() -> BoxSizing; } /// Default styles for various attributes in case they don't get initialized from CSS selectors. @@ -35,28 +35,28 @@ impl NodeKind : DefaultStyleMethods { } } - fn default_display_type() -> DisplayType { + fn default_display_type() -> CSSDisplay { match self { - Text(*) => { Inline } + Text(*) => { DisplayInline } Element(element) => { match *element.kind { - HTMLDivElement => Block, + HTMLDivElement => DisplayBlock, HTMLHeadElement => DisplayNone, - HTMLImageElement(*) => Inline, + HTMLImageElement(*) => DisplayInline, HTMLScriptElement => DisplayNone, - UnknownElement => Inline, + UnknownElement => DisplayInline, } }, Comment(*) | Doctype(*) => DisplayNone } } - fn default_width() -> Unit { - Auto + fn default_width() -> BoxSizing { + BoxAuto } - fn default_height() -> Unit { - Auto + fn default_height() -> BoxSizing { + BoxAuto } } @@ -70,12 +70,12 @@ impl NodeKind : DefaultStyleMethods { fn empty_style_for_node_kind(kind: NodeKind) -> SpecifiedStyle { let display_type = kind.default_display_type(); - {mut background_color : None, - mut display_type : Some(display_type), - mut font_size : None, - mut height : None, - mut text_color : None, - mut width : None} + {mut background_color : Initial, + mut display_type : Specified(display_type), + mut font_size : Initial, + mut height : Initial, + mut text_color : Initial, + mut width : Initial} } trait StylePriv { diff --git a/src/servo/css/values.rs b/src/servo/css/values.rs index 98d79a84864..b1ae87d4bee 100644 --- a/src/servo/css/values.rs +++ b/src/servo/css/values.rs @@ -1,4 +1,5 @@ -import util::color::Color; +use SharedColor = util::color::Color; +use cmp::Eq; #[doc = " Defines how css rules, both selectors and style specifications, are @@ -6,39 +7,156 @@ import util::color::Color; http://www.w3.org/TR/CSS2/selector.html are represented by nested types. "] -enum DisplayType { - Inline, - Block, - ListItem, - InlineBlock, - Table, - InlineTable, - TableRowGroup, - TableHeaderGroup, - TableFooterGroup, - TableRow, - TableColumnGroup, - TableColumn, - TableCell, - TableCaption, +// CSS Units + +enum ParseResult { + Value(T), + CSSInitial, + CSSInherit, + Fail +} + +enum CSSValue { + Specified(T), + Initial, + Inherit +} + +impl ParseResult { + pure fn extract(f: fn(CSSValue) -> U) -> Option { extract(self, f) } +} + +pure fn extract(res: ParseResult, f: fn(CSSValue) -> U) -> Option { + match res { + Fail => None, + CSSInitial => Some(f(Initial)), + CSSInherit => Some(f(Inherit)), + Value(x) => Some(f(Specified(x))) + } +} + +impl CSSValue : Eq { + pure fn eq(&&other: CSSValue) -> bool { + match (self, other) { + (Initial, Initial) => true, + (Inherit, Inherit) => true, + (Specified(a), Specified(b)) => a == b, + _ => false + } + } +} + +enum Auto = (); + +enum Length { + Em(float), // normalized to 'em' + Px(float) // normalized to 'px' +} + +impl Length { + pure fn rel() -> float { + match self { + Em(x) => x, + _ => fail ~"attempted to access relative unit of an absolute length" + } + } + pure fn abs() -> float { + match self { + Em(x) => x, + _ => fail ~"attempted to access relative unit of an absolute length" + } + } +} + +enum BoxSizing { // used by width, height, top, left, etc + BoxLength(Length), + BoxPercent(float), + BoxAuto +} + +enum AbsoluteSize { + XXSmall, + XSmall, + Small, + Medium, + Large, + XLarge, + XXLarge +} + +enum RelativeSize { + Larger, + Smaller +} + +// CSS property values + +enum CSSBackgroundAttachment { + BgAttachScroll, + BgAttachFixed +} + +enum CSSBackgroundColor { + BgColor(SharedColor), + BgTransparent +} + +enum CSSBackgroundRepeat { + BgRepeat, + BgRepeatX, + BgRepeatY, + BgNoRepeat +} + +enum CSSColor { + TextColor(SharedColor) +} + +enum CSSDirection { + DirectionLtr, + DirectionRtl +} + +enum CSSDisplay { + DisplayInline, + DisplayBlock, + DisplayListItem, + DisplayInlineBlock, + DisplayTable, + DisplayInlineTable, + DisplayTableRowGroup, + DisplayTableHeaderGroup, + DisplayTableFooterGroup, + DisplayTableRow, + DisplayTableColumnGroup, + DisplayTableColumn, + DisplayTableCell, + DisplayTableCaption, DisplayNone } -enum Unit { - Auto, - Percent(float), - Mm(float), - Pt(float), - Px(float) +enum CSSFloat { + FloatLeft, + FloatRight, + FloatNone } +enum CSSFontSize { + AbsoluteSize(AbsoluteSize), + RelativeSize(RelativeSize), + LengthSize(Length), + PercentSize(float) +} + +// Stylesheet parts + enum StyleDeclaration { - BackgroundColor(Color), - Display(DisplayType), - FontSize(Unit), - Height(Unit), - TextColor(Color), - Width(Unit) + BackgroundColor(CSSValue), + Display(CSSValue), + FontSize(CSSValue), + Height(CSSValue), + Color(CSSValue), + Width(CSSValue) } enum Attr{ @@ -59,45 +177,80 @@ type Rule = (~[~Selector], ~[StyleDeclaration]); type Stylesheet = ~[~Rule]; -#[doc="Convert between units measured in millimeteres and pixels"] -pure fn MmToPx(u : Unit) -> Unit { - match u { - Mm(m) => Px(m * 3.7795), - _ => fail ~"Calling MmToPx on a unit that is not a Mm" - } -} -#[doc="Convert between units measured in points and pixels"] -pure fn PtToPx(u : Unit) -> Unit { - match u { - Pt(m) => Px(m * 1.3333), - _ => fail ~"Calling PtToPx on a unit that is not a Pt" - } -} - -impl DisplayType: cmp::Eq { - pure fn eq(&&other: DisplayType) -> bool { - self as uint == other as uint - } -} - -impl Unit: cmp::Eq { - pure fn eq(&&other: Unit) -> bool { +impl Length: cmp::Eq { + pure fn eq(&&other: Length) -> bool { match (self, other) { - (Auto, Auto) => true, - (Auto, _) => false, - (Percent(a), Percent(b)) => a == b, - (Percent(*), _) => false, - (Mm(a), Mm(b)) => a == b, - (Mm(*), _) => false, - (Pt(a), Pt(b)) => a == b, - (Pt(*), _) => false, + (Em(a), Em(b)) => a == b, (Px(a), Px(b)) => a == b, - (Px(*), _) => false + (_, _) => false } } } +impl BoxSizing: cmp::Eq { + pure fn eq(&&other: BoxSizing) -> bool { + match (self, other) { + (BoxLength(a), BoxLength(b)) => a == b, + (BoxPercent(a), BoxPercent(b)) => a == b, + (BoxAuto, BoxAuto) => true, + (_, _) => false + } + } +} + +impl AbsoluteSize: cmp::Eq { + pure fn eq(&&other: AbsoluteSize) -> bool { + self as uint == other as uint + } +} + +impl RelativeSize: cmp::Eq { + pure fn eq(&&other: RelativeSize) -> bool { + self as uint == other as uint + } +} + + + +impl CSSBackgroundColor: cmp::Eq { + pure fn eq(&&other: CSSBackgroundColor) -> bool { + match (self, other) { + (BgColor(a), BgColor(b)) => a == b, + (BgTransparent, BgTransparent) => true, + (_, _) => false + } + } +} + + +impl CSSColor: cmp::Eq { + pure fn eq(&&other: CSSColor) -> bool { + match (self, other) { + (TextColor(a), TextColor(b)) => a == b + } + } +} + +impl CSSDisplay: cmp::Eq { + pure fn eq(&&other: CSSDisplay) -> bool { + self as uint == other as uint + } +} + + +impl CSSFontSize: cmp::Eq { + pure fn eq(&&other: CSSFontSize) -> bool { + match (self, other) { + (AbsoluteSize(a), AbsoluteSize(b)) => a == b, + (RelativeSize(a), RelativeSize(b)) => a == b, + (LengthSize(a), LengthSize(b)) => a == b, + (PercentSize(a), PercentSize(b)) => a == b, + (_, _) => false + } + } +} +/* impl StyleDeclaration: cmp::Eq { pure fn eq(&&other: StyleDeclaration) -> bool { match (self, other) { @@ -105,18 +258,18 @@ impl StyleDeclaration: cmp::Eq { (Display(a), Display(b)) => a == b, (FontSize(a), FontSize(b)) => a == b, (Height(a), Height(b)) => a == b, - (TextColor(a), TextColor(b)) => a == b, + (Color(a), Color(b)) => a == b, (Width(a), Width(b)) => a == b, (BackgroundColor(*), _) | (Display(*), _) | (FontSize(*), _) | (Height(*), _) - | (TextColor(*), _) + | (Color(*), _) | (Width(*), _) => false } } -} +}*/ impl Attr: cmp::Eq { pure fn eq(&&other: Attr) -> bool { diff --git a/src/servo/layout/base.rs b/src/servo/layout/base.rs index 11f826ee353..6fa99694455 100644 --- a/src/servo/layout/base.rs +++ b/src/servo/layout/base.rs @@ -1,7 +1,7 @@ #[doc="Fundamental layout structures and algorithms."] -import css::values::Unit; import css::styles::SpecifiedStyle; +import css::values::{BoxSizing, Length, Px}; import dom::base::{Element, ElementKind, HTMLDivElement, HTMLImageElement, Node, NodeData}; import dom::base::{NodeKind}; import dom::rcu; @@ -42,13 +42,16 @@ impl BoxKind : cmp::Eq { struct Appearance { let mut background_image: Option; - let mut background_color: Color; - let mut width: Unit; - let mut height: Unit; + // TODO: create some sort of layout-specific enum to differentiate between + // relative and resolved values. + let mut width: BoxSizing; + let mut height: BoxSizing; + let mut font_size: Length; new(kind: NodeKind) { + // TODO: these should come from initial() or elsewhere + self.font_size = Px(14.0); self.background_image = None; - self.background_color = kind.default_color(); self.width = kind.default_width(); self.height = kind.default_height(); } diff --git a/src/servo/layout/block.rs b/src/servo/layout/block.rs index 7ceb7650add..bc964458fc3 100644 --- a/src/servo/layout/block.rs +++ b/src/servo/layout/block.rs @@ -1,6 +1,6 @@ #[doc="Block layout."] -import css::values::{Px, Mm, Pt, Auto, Percent, Unit}; +import css::values::*; import geom::point::Point2D; import geom::size::Size2D; import gfx::geometry::{px_to_au, au}; @@ -37,15 +37,15 @@ impl @Box : BlockLayoutMethods { } let height = match self.appearance.height { - Px(p) => px_to_au(p.to_int()), - Auto => au(current_height), + BoxLength(Px(p)) => px_to_au(p.to_int()), + BoxAuto => au(current_height), _ => fail ~"inhereit_height failed, height is neither a Px or auto" }; // FIXME: Width is wrong in the calculation below. let width = match self.appearance.width { - Px(p) => px_to_au(p.to_int()), - Auto => self.bounds.size.width, // Do nothing here, width was set by top-down pass + BoxLength(Px(p)) => px_to_au(p.to_int()), + BoxAuto => self.bounds.size.width, // Do nothing here, width was set by top-down pass _ => fail ~"inhereit_width failed, width is neither a Px or auto" }; diff --git a/src/servo/layout/box_builder.rs b/src/servo/layout/box_builder.rs index 34f55b107a1..14bc1501cc7 100644 --- a/src/servo/layout/box_builder.rs +++ b/src/servo/layout/box_builder.rs @@ -1,6 +1,6 @@ #[doc="Creates CSS boxes from a DOM."] -import css::values::{DisplayType, Block, Inline, DisplayNone}; +import css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayNone, Specified}; import dom::base::{ElementData, HTMLDivElement, HTMLImageElement, Element, Text, Node, Doctype, Comment}; import gfx::geometry::zero_size_au; import layout::base::{Appearance, BTree, BlockBox, Box, BoxKind, InlineBox, IntrinsicBox, NTree}; @@ -49,14 +49,14 @@ impl ctxt { // Determine the child's display. let disp = kid.get_specified_style().display_type; - if disp != Some(Inline) { + if disp != Specified(DisplayInline) { self.finish_anonymous_box_if_necessary(); } // Add the child's box to the current enclosing box or the current anonymous box. match kid.get_specified_style().display_type { - Some(Block) => BTree.add_child(self.parent_box, kid_box.get()), - Some(Inline) => { + Specified(DisplayBlock) => BTree.add_child(self.parent_box, kid_box.get()), + Specified(DisplayInline) => { let anon_box = match self.anon_box { None => { // @@ -75,7 +75,7 @@ impl ctxt { }; BTree.add_child(anon_box, kid_box.get()); } - Some(DisplayNone) => { + Specified(DisplayNone) => { // Nothing to do. } _ => { //hack for now @@ -96,21 +96,21 @@ impl ctxt { // Determine the child's display. let disp = kid.get_specified_style().display_type; - if disp != Some(Inline) { + if disp != Specified(DisplayInline) { // TODO } // Add the child's box to the current enclosing box. match kid.get_specified_style().display_type { - Some(Block) => { + Specified(DisplayBlock) => { // TODO #warn("TODO: non-inline display found inside inline box"); BTree.add_child(self.parent_box, kid_box.get()); } - Some(Inline) => { + Specified(DisplayInline) => { BTree.add_child(self.parent_box, kid_box.get()); } - Some(DisplayNone) => { + Specified(DisplayNone) => { // Nothing to do. } _ => { //hack for now @@ -125,9 +125,9 @@ impl ctxt { self.parent_node.dump(); match self.parent_node.get_specified_style().display_type { - Some(Block) => self.construct_boxes_for_block_children(), - Some(Inline) => self.construct_boxes_for_inline_children(), - Some(DisplayNone) => { /* Nothing to do. */ } + Specified(DisplayBlock) => self.construct_boxes_for_block_children(), + Specified(DisplayInline) => self.construct_boxes_for_inline_children(), + Specified(DisplayNone) => { /* Nothing to do. */ } _ => { //hack for now } } @@ -164,11 +164,11 @@ impl Node : PrivBoxBuilder { ~Element(element) => { match (copy *element.kind, self.get_specified_style().display_type) { (HTMLImageElement({size}), _) => Some(IntrinsicBox(@size)), - (_, Some(Block)) => Some(BlockBox), - (_, Some(Inline)) => Some(InlineBox), - (_, Some(DisplayNone)) => None, - (_, Some(_)) => Some(InlineBox), - (_, None) => { + (_, Specified(DisplayBlock)) => Some(BlockBox), + (_, Specified(DisplayInline)) => Some(InlineBox), + (_, Specified(DisplayNone)) => None, + (_, Specified(_)) => Some(InlineBox), + (_, _) => { fail ~"The specified display style should be a default instead of none" } } diff --git a/src/servo/layout/display_list_builder.rs b/src/servo/layout/display_list_builder.rs index 3d168099dfe..d0a2aa36c25 100644 --- a/src/servo/layout/display_list_builder.rs +++ b/src/servo/layout/display_list_builder.rs @@ -1,5 +1,6 @@ export build_display_list; +import css::values::{BgColor, BgTransparent, Specified}; import base::{Box, BTree, ImageHolder, TextBoxKind}; import dl = display_list; import dom::base::{Text, NodeScope}; @@ -65,7 +66,6 @@ fn box_to_display_items(list: dl::display_list, box: @Box, origin: Point2D) #debug("request to display a box from origin %?", origin); let bounds = Rect(origin, copy box.bounds.size); - let col = box.appearance.background_color; match box.kind { TextBoxKind(subbox) => { @@ -96,10 +96,16 @@ fn box_to_display_items(list: dl::display_list, box: @Box, origin: Point2D) }); list.push(display_item); } else { - #debug("Assigning color %? to box with bounds %?", col, bounds); - let col = box.appearance.background_color; + // DAC + // TODO: shouldn't need to unbox CSSValue by now + let boxed_color = box.node.get_specified_style().background_color; + let color = match boxed_color { + Specified(BgColor(c)) => c, + Specified(BgTransparent) | _ => util::color::rgba(0,0,0,0.0) + }; + #debug("Assigning color %? to box with bounds %?", color, bounds); list.push(dl::display_item({ - item_type: dl::display_item_solid_color(col.red, col.green, col.blue), + item_type: dl::display_item_solid_color(color.red, color.green, color.blue), bounds: bounds })); } diff --git a/src/servo/layout/inline.rs b/src/servo/layout/inline.rs index d9d6d4c2ab0..9050b8fac6e 100644 --- a/src/servo/layout/inline.rs +++ b/src/servo/layout/inline.rs @@ -1,7 +1,7 @@ #[doc="Inline layout."] import base::{Box, InlineBox, BTree}; -import css::values::{Auto, Px}; +import css::values::{BoxAuto, BoxLength, Px}; import dom::rcu; import geom::point::Point2D; import geom::size::Size2D; @@ -34,14 +34,14 @@ impl @Box : InlineLayout { } let height = match self.appearance.height { - Px(p) => px_to_au(p.to_int()), - Auto => au(current_height), + BoxLength(Px(p)) => px_to_au(p.to_int()), + BoxAuto => au(current_height), _ => fail ~"inhereit_height failed, height is neither a Px or auto" }; let width = match self.appearance.width { - Px(p) => px_to_au(p.to_int()), - Auto => au(i32::max(x, *self.bounds.size.width)), + BoxLength(Px(p)) => px_to_au(p.to_int()), + BoxAuto => au(i32::max(x, *self.bounds.size.width)), _ => fail ~"inhereit_width failed, width is neither a Px or auto" };