mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Redo representation of CSS values, and many other related things.
This commit is contained in:
parent
cdd85d8d65
commit
fd3ade2a3c
11 changed files with 413 additions and 236 deletions
|
@ -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<StyleDeclaration> = 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
|
||||
|
|
|
@ -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<Unit> {
|
||||
|
||||
fn parse_length(str : ~str) -> Option<Length> {
|
||||
// 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<Unit> {
|
||||
// The default pixel size, not sure if this is accurate.
|
||||
let default = 16.0;
|
||||
|
||||
fn parse_absolute_size(str : ~str) -> ParseResult<AbsoluteSize> {
|
||||
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<RelativeSize> {
|
||||
match str {
|
||||
~"smaller" => Value(Smaller),
|
||||
~"larger" => Value(Larger),
|
||||
_ => Fail
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_font_size(str: ~str) -> ParseResult<CSSFontSize> {
|
||||
// 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<Unit> {
|
||||
fn parse_box_sizing(str : ~str) -> ParseResult<BoxSizing> {
|
||||
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<DisplayType> {
|
||||
fn parse_display_type(str : ~str) -> ParseResult<CSSDisplay> {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<T> {
|
||||
pure fn initial() -> T;
|
||||
}
|
||||
|
||||
impl CSSValue<CSSBackgroundColor> : ResolveMethods<CSSBackgroundColor> {
|
||||
pure fn initial() -> CSSBackgroundColor { return BgTransparent; }
|
||||
}
|
||||
|
||||
impl CSSValue<CSSDisplay> : ResolveMethods<CSSDisplay> {
|
||||
pure fn initial() -> CSSDisplay { return DisplayInline; }
|
||||
}
|
||||
|
||||
impl CSSValue<BoxSizing> : ResolveMethods<BoxSizing> {
|
||||
pure fn initial() -> BoxSizing { return BoxAuto; }
|
||||
}
|
||||
|
||||
impl CSSValue<CSSFontSize> : ResolveMethods<CSSFontSize> {
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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<Color>,
|
||||
mut display_type : Option<DisplayType>,
|
||||
mut font_size : Option<Unit>,
|
||||
mut height : Option<Unit>,
|
||||
mut text_color : Option<Color>,
|
||||
mut width : Option<Unit>
|
||||
type SpecifiedStyle = {mut background_color : CSSValue<CSSBackgroundColor>,
|
||||
mut display_type : CSSValue<CSSDisplay>,
|
||||
mut font_size : CSSValue<CSSFontSize>,
|
||||
mut height : CSSValue<BoxSizing>,
|
||||
mut text_color : CSSValue<CSSColor>,
|
||||
mut width : CSSValue<BoxSizing>
|
||||
};
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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<T> {
|
||||
Value(T),
|
||||
CSSInitial,
|
||||
CSSInherit,
|
||||
Fail
|
||||
}
|
||||
|
||||
enum CSSValue<T : copy> {
|
||||
Specified(T),
|
||||
Initial,
|
||||
Inherit
|
||||
}
|
||||
|
||||
impl<T : copy> ParseResult<T> {
|
||||
pure fn extract<U>(f: fn(CSSValue<T>) -> U) -> Option<U> { extract(self, f) }
|
||||
}
|
||||
|
||||
pure fn extract<T : copy, U>(res: ParseResult<T>, f: fn(CSSValue<T>) -> U) -> Option<U> {
|
||||
match res {
|
||||
Fail => None,
|
||||
CSSInitial => Some(f(Initial)),
|
||||
CSSInherit => Some(f(Inherit)),
|
||||
Value(x) => Some(f(Specified(x)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq copy> CSSValue<T> : Eq {
|
||||
pure fn eq(&&other: CSSValue<T>) -> 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<CSSBackgroundColor>),
|
||||
Display(CSSValue<CSSDisplay>),
|
||||
FontSize(CSSValue<CSSFontSize>),
|
||||
Height(CSSValue<BoxSizing>),
|
||||
Color(CSSValue<CSSColor>),
|
||||
Width(CSSValue<BoxSizing>)
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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<ImageHolder>;
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
};
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<au>)
|
|||
#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<au>)
|
|||
});
|
||||
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
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue