mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Added the ability to compute heights from parent heights and to layout specified heights
This commit is contained in:
parent
470a88f459
commit
95d0998149
14 changed files with 232 additions and 72 deletions
|
@ -3,7 +3,7 @@ import util::color::Color;
|
|||
#[doc = "
|
||||
Defines how css rules, both selectors and style specifications, are
|
||||
stored. CSS selector-matching rules, as presented by
|
||||
http://www.w3.org/TR/CSS2/selector.html are represented by nested, structural types,
|
||||
http://www.w3.org/TR/CSS2/selector.html are represented by nested types.
|
||||
"]
|
||||
|
||||
enum DisplayType {
|
||||
|
@ -15,13 +15,8 @@ enum DisplayType {
|
|||
enum Unit {
|
||||
Auto,
|
||||
Percent(float),
|
||||
In(float),
|
||||
Mm(float),
|
||||
Cm(float),
|
||||
Em(float),
|
||||
Ex(float),
|
||||
Pt(float),
|
||||
Pc(float),
|
||||
Px(float)
|
||||
}
|
||||
|
||||
|
@ -51,3 +46,19 @@ enum Selector{
|
|||
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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@ import geom::rect::Rect;
|
|||
import geom::size::Size2D;
|
||||
import image::base::{image, load};
|
||||
import util::tree;
|
||||
import util::color::{Color, css_colors};
|
||||
import style::style::SpecifiedStyle;
|
||||
import util::color::Color;
|
||||
import text::TextBox;
|
||||
import traverse::extended_full_traversal;
|
||||
import style::style::{SpecifiedStyle};
|
||||
import vec::{push, push_all};
|
||||
|
||||
import arc::{arc, clone};
|
||||
|
@ -155,8 +156,17 @@ impl BTree : tree::WriteMethods<@Box> {
|
|||
}
|
||||
}
|
||||
|
||||
// Private methods
|
||||
impl @Box {
|
||||
#[doc="The main reflow routine."]
|
||||
fn reflow() {
|
||||
match self.kind {
|
||||
BlockBox => self.reflow_block(),
|
||||
InlineBox => self.reflow_inline(),
|
||||
IntrinsicBox(size) => self.reflow_intrinsic(*size),
|
||||
TextBoxKind(subbox) => self.reflow_text(subbox)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Dumps the box tree, for debugging, with indentation."]
|
||||
fn dump_indent(indent: uint) {
|
||||
let mut s = ~"";
|
||||
|
@ -173,16 +183,37 @@ impl @Box {
|
|||
}
|
||||
}
|
||||
|
||||
// Public methods
|
||||
#[doc = "
|
||||
Set your width to the maximum available width and return the
|
||||
maximum available width any children can use. Currently children
|
||||
are just given the same available width.
|
||||
"]
|
||||
fn give_kids_width(+available_width : au, box : @Box) -> au {
|
||||
// TODO: give smaller available widths if the width of the
|
||||
// containing box is constrained
|
||||
match box.kind {
|
||||
BlockBox | InlineBox => box.bounds.size.width = available_width,
|
||||
IntrinsicBox(*) | TextBoxKind(*) => { }
|
||||
}
|
||||
|
||||
available_width
|
||||
}
|
||||
|
||||
#[doc="Wrapper around reflow so it can be passed to traverse"]
|
||||
fn reflow_wrapper(b : @Box) {
|
||||
b.reflow();
|
||||
}
|
||||
|
||||
impl @Box {
|
||||
#[doc="The main reflow routine."]
|
||||
fn reflow(available_width: au) {
|
||||
match self.kind {
|
||||
BlockBox => self.reflow_block(available_width),
|
||||
InlineBox => self.reflow_inline(available_width),
|
||||
IntrinsicBox(size) => self.reflow_intrinsic(*size),
|
||||
TextBoxKind(subbox) => self.reflow_text(available_width, subbox)
|
||||
}
|
||||
#[doc="
|
||||
Run a parallel traversal over the layout tree rooted at
|
||||
this box. On the top-down traversal give each box the
|
||||
available width determined by their parent and on the
|
||||
bottom-up traversal reflow each box based on their
|
||||
attributes and their children's sizes.
|
||||
"]
|
||||
fn reflow_subtree(available_width : au) {
|
||||
extended_full_traversal(self, available_width, give_kids_width, reflow_wrapper);
|
||||
}
|
||||
|
||||
#[doc="The trivial reflow routine for instrinsically-sized frames."]
|
||||
|
@ -200,7 +231,7 @@ impl @Box {
|
|||
|
||||
// Debugging
|
||||
|
||||
trait PrivateNodeMethods {
|
||||
trait PrivateNodeMethods{
|
||||
fn dump_indent(ident: uint);
|
||||
}
|
||||
|
||||
|
@ -292,7 +323,7 @@ mod test {
|
|||
tree::add_child(BTree, b3, b1);
|
||||
tree::add_child(BTree, b3, b2);
|
||||
|
||||
b3.reflow_block(au(100));
|
||||
b3.reflow_subtree(au(100));
|
||||
let fb = flat_bounds(b3);
|
||||
#debug["fb=%?", fb];
|
||||
assert fb == ~[geometry::box(au(0), au(0), au(10), au(10)), // n0
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
#[doc="Block layout."]
|
||||
|
||||
import dom::style::{Px, Mm, Pt, Auto, Percent, Unit};
|
||||
import geom::point::Point2D;
|
||||
import geom::size::Size2D;
|
||||
import gfx::geometry::au;
|
||||
import gfx::geometry::{px_to_au, au};
|
||||
import util::tree;
|
||||
import base::{Box, BlockBox, BTree};
|
||||
|
||||
trait BlockLayoutMethods {
|
||||
fn reflow_block(available_widh: au);
|
||||
fn reflow_block();
|
||||
}
|
||||
|
||||
#[doc="The public block layout methods."]
|
||||
impl @Box : BlockLayoutMethods {
|
||||
#[doc="The main reflow routine for block layout."]
|
||||
fn reflow_block(available_width: au) {
|
||||
fn reflow_block() {
|
||||
assert self.kind == BlockBox;
|
||||
|
||||
#debug["starting reflow block"];
|
||||
|
@ -24,19 +25,31 @@ impl @Box : BlockLayoutMethods {
|
|||
// This routine:
|
||||
// - generates root.bounds.size
|
||||
// - generates root.bounds.origin for each child
|
||||
// - and recursively computes the bounds for each child
|
||||
|
||||
let mut current_height = 0;
|
||||
|
||||
// Find the combined height of all the children and mark the
|
||||
// relative heights of the children in the box
|
||||
for tree::each_child(BTree, self) |c| {
|
||||
let mut blk_available_width = available_width;
|
||||
// FIXME subtract borders, margins, etc
|
||||
c.bounds.origin = Point2D(au(0), au(current_height));
|
||||
c.reflow(blk_available_width);
|
||||
current_height += *c.bounds.size.height;
|
||||
}
|
||||
|
||||
let height = match self.appearance.height {
|
||||
Px(p) => px_to_au(p.to_int()),
|
||||
Auto => au(current_height),
|
||||
_ => fail ~"inhereit_height failed, height is neither a Px or auto"
|
||||
};
|
||||
|
||||
// FIXME: Width is wrong in the calculation below.
|
||||
self.bounds.size = Size2D(available_width, au(current_height));
|
||||
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
|
||||
_ => fail ~"inhereit_height failed, width is neither a Px or auto"
|
||||
};
|
||||
|
||||
self.bounds.size = Size2D(width, height);
|
||||
|
||||
#debug["reflow_block size=%?", copy self.bounds];
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ fn should_convert_text_boxes_to_solid_color_background_items() {
|
|||
|
||||
let subbox = match check b.kind { TextBoxKind(subbox) => subbox };
|
||||
|
||||
b.reflow_text(px_to_au(800), subbox);
|
||||
b.reflow_text(subbox);
|
||||
let list = dvec();
|
||||
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
||||
|
||||
|
@ -139,7 +139,7 @@ fn should_convert_text_boxes_to_text_items() {
|
|||
|
||||
let subbox = match check b.kind { TextBoxKind(subbox) => { subbox } };
|
||||
|
||||
b.reflow_text(px_to_au(800), subbox);
|
||||
b.reflow_text(subbox);
|
||||
let list = dvec();
|
||||
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
||||
|
||||
|
@ -159,7 +159,7 @@ fn should_calculate_the_bounds_of_the_text_box_background_color() {
|
|||
|
||||
let subbox = match check b.kind { TextBoxKind(subbox) => { subbox } };
|
||||
|
||||
b.reflow_text(px_to_au(800), subbox);
|
||||
b.reflow_text(subbox);
|
||||
let list = dvec();
|
||||
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
||||
|
||||
|
@ -181,7 +181,7 @@ fn should_calculate_the_bounds_of_the_text_items() {
|
|||
|
||||
let subbox = match check b.kind { TextBoxKind(subbox) => { subbox } };
|
||||
|
||||
b.reflow_text(px_to_au(800), subbox);
|
||||
b.reflow_text(subbox);
|
||||
let list = dvec();
|
||||
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@ import util::tree;
|
|||
import base::{Box, InlineBox, BTree};
|
||||
|
||||
trait InlineLayout {
|
||||
fn reflow_inline(available_width: au);
|
||||
fn reflow_inline();
|
||||
}
|
||||
|
||||
#[doc="The main reflow routine for inline layout."]
|
||||
impl @Box : InlineLayout {
|
||||
fn reflow_inline(available_width: au) {
|
||||
fn reflow_inline() {
|
||||
assert self.kind == InlineBox;
|
||||
|
||||
#debug["starting reflow inline"];
|
||||
|
@ -21,17 +21,19 @@ impl @Box : InlineLayout {
|
|||
// FIXME: This is clownshoes inline layout and is not even close to
|
||||
// correct.
|
||||
let y = 0;
|
||||
let mut x = 0, inline_available_width = *available_width;
|
||||
let mut x = 0;
|
||||
let mut current_height = 0;
|
||||
|
||||
// loop over children and set them at the proper horizontal offset
|
||||
for tree::each_child(BTree, self) |kid| {
|
||||
kid.bounds.origin = Point2D(au(x), au(y));
|
||||
kid.reflow(au(inline_available_width));
|
||||
inline_available_width -= *kid.bounds.size.width;
|
||||
x += *kid.bounds.size.width;
|
||||
current_height = int::max(current_height, *kid.bounds.size.height);
|
||||
}
|
||||
|
||||
self.bounds.size = Size2D(available_width, au(current_height));
|
||||
// The maximum available width should have been set in the top-down pass
|
||||
self.bounds.size = Size2D(au(int::max(x, *self.bounds.size.width)),
|
||||
au(current_height));
|
||||
|
||||
#debug["reflow_inline size=%?", copy self.bounds];
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ fn Layout(renderer: Renderer) -> Layout {
|
|||
this_box.dump();
|
||||
|
||||
this_box.apply_css_style();
|
||||
this_box.reflow(px_to_au(800));
|
||||
this_box.reflow_subtree(px_to_au(800));
|
||||
|
||||
let dlist = build_display_list(this_box);
|
||||
renderer.send(renderer::RenderMsg(dlist));
|
||||
|
|
|
@ -1,24 +1,58 @@
|
|||
#[doc="Applies the appropriate CSS style to boxes."]
|
||||
|
||||
import dom::base::{Element, HTMLImageElement, Node};
|
||||
import either::right;
|
||||
import dom::style::{Percent, Mm, Pt, Px, Auto, PtToPx, MmToPx};
|
||||
import gfx::geometry::au_to_px;
|
||||
import image::base::load;
|
||||
import base::{Box, BTree, ImageHolder, LayoutData, NTree, SpecifiedStyle};
|
||||
import traverse::top_down_traversal;
|
||||
import base::{Box, BTree, NTree, LayoutData, SpecifiedStyle, ImageHolder,
|
||||
BlockBox, InlineBox, IntrinsicBox, TextBox};
|
||||
import traverse::{top_down_traversal};
|
||||
|
||||
trait ApplyStyleBoxMethods {
|
||||
fn apply_css_style();
|
||||
fn apply_style();
|
||||
}
|
||||
|
||||
#[doc="A wrapper so the function can be passed around by name."]
|
||||
fn apply_style_wrapper(box : @Box) {
|
||||
#[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) {
|
||||
box.apply_style();
|
||||
inhereit_height(box);
|
||||
}
|
||||
|
||||
#[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) {
|
||||
let style = box.node.get_specified_style();
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl @Box : ApplyStyleBoxMethods {
|
||||
fn apply_css_style() {
|
||||
top_down_traversal(self, apply_style_wrapper);
|
||||
top_down_traversal(self, inheritance_wrapper);
|
||||
}
|
||||
|
||||
#[doc="Applies CSS style to a layout box.
|
||||
|
@ -58,3 +92,54 @@ impl @Box : ApplyStyleBoxMethods {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
import dom::base::{Attr, HTMLDivElement, HTMLHeadElement, HTMLImageElement, ElementData};
|
||||
import dom::base::{NodeScope, UnknownElement};
|
||||
import dvec::dvec;
|
||||
|
||||
#[allow(non_implicitly_copyable_typarams)]
|
||||
fn new_node(scope: NodeScope, -name: ~str) -> Node {
|
||||
let elmt = ElementData(name, ~HTMLDivElement);
|
||||
return scope.new_node(base::Element(elmt));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore(reason = "leaks memory")]
|
||||
fn test_percent_height() {
|
||||
let scope = NodeScope();
|
||||
|
||||
let parent = new_node(scope, ~"parent");
|
||||
let child = new_node(scope, ~"child");
|
||||
let child2 = new_node(scope, ~"child");
|
||||
let g1 = new_node(scope, ~"gchild");
|
||||
let g2 = new_node(scope, ~"gchild");
|
||||
|
||||
scope.add_child(parent, child);
|
||||
scope.add_child(parent, child2);
|
||||
scope.add_child(child, g1);
|
||||
scope.add_child(child, g2);
|
||||
parent.initialize_style_for_subtree();
|
||||
|
||||
do parent.aux |aux| { aux.specified_style.height = some(Px(100.0)); }
|
||||
do child.aux |aux| { aux.specified_style.height = some(Auto); }
|
||||
do child2.aux |aux| { aux.specified_style.height = some(Percent(50.0)); }
|
||||
do g1.aux |aux| { aux.specified_style.height = some(Percent(50.0)); }
|
||||
do g2.aux |aux| { aux.specified_style.height = some(Px(10.0)); }
|
||||
|
||||
let parent_box = parent.construct_boxes();
|
||||
let child_box = parent_box.tree.first_child.get();
|
||||
let child2_box = parent_box.tree.last_child.get();
|
||||
let g1_box = child_box.tree.first_child.get();
|
||||
let g2_box = child_box.tree.last_child.get();
|
||||
|
||||
top_down_traversal(parent_box, inhereit_height);
|
||||
|
||||
assert parent_box.appearance.height == Px(100.0);
|
||||
assert child_box.appearance.height == Auto;
|
||||
assert child2_box.appearance.height == Px(50.0);
|
||||
assert g1_box.appearance.height == Auto;
|
||||
assert g2_box.appearance.height == Px(10.0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -212,7 +212,6 @@ mod test {
|
|||
import dom::base::{Attr, HTMLDivElement, HTMLHeadElement, HTMLImageElement};
|
||||
import dom::base::{NodeScope, UnknownElement};
|
||||
import dvec::dvec;
|
||||
import io::println;
|
||||
|
||||
#[allow(non_implicitly_copyable_typarams)]
|
||||
fn new_node_from_attr(scope: NodeScope, -name: ~str, -val: ~str) -> Node {
|
||||
|
|
|
@ -127,7 +127,7 @@ impl Node : StyleMethods {
|
|||
"]
|
||||
fn get_specified_style() -> SpecifiedStyle {
|
||||
if !self.has_aux() {
|
||||
fail ~"get_computed_style() called on a node without a style!";
|
||||
fail ~"get_specified_style() called on a node without a style!";
|
||||
}
|
||||
return copy *self.aux(|x| copy x).specified_style;
|
||||
}
|
||||
|
|
|
@ -17,12 +17,12 @@ struct TextBox {
|
|||
}
|
||||
|
||||
trait TextLayout {
|
||||
fn reflow_text(_available_width: au, subbox: @TextBox);
|
||||
fn reflow_text(subbox: @TextBox);
|
||||
}
|
||||
|
||||
#[doc="The main reflow routine for text layout."]
|
||||
impl @Box : TextLayout {
|
||||
fn reflow_text(_available_width: au, subbox: @TextBox) {
|
||||
fn reflow_text(subbox: @TextBox) {
|
||||
match self.kind {
|
||||
TextBoxKind(*) => { /* ok */ }
|
||||
_ => { fail ~"expected text box in reflow_text!" }
|
||||
|
@ -51,7 +51,7 @@ fn should_calculate_the_size_of_the_text_box() {
|
|||
let b = n.construct_boxes();
|
||||
|
||||
let subbox = match check b.kind { TextBoxKind(subbox) => { subbox } };
|
||||
b.reflow_text(px_to_au(800), subbox);
|
||||
b.reflow_text(subbox);
|
||||
let expected = Size2D(px_to_au(84), px_to_au(20));
|
||||
assert b.bounds.size == expected;
|
||||
}
|
||||
|
|
|
@ -67,15 +67,15 @@ fn link_up_attribute(scope: NodeScope, node: Node, -key: ~str, -value: ~str) {
|
|||
|
||||
fn build_element_kind(tag_name: ~str) -> ~ElementKind {
|
||||
match tag_name {
|
||||
~"div" => ~HTMLDivElement,
|
||||
~"img" => {
|
||||
~HTMLImageElement({ mut size: Size2D(geometry::px_to_au(100),
|
||||
geometry::px_to_au(100))
|
||||
})
|
||||
}
|
||||
~"script" => ~HTMLScriptElement,
|
||||
~"head" => ~HTMLHeadElement,
|
||||
_ => ~UnknownElement
|
||||
~"div" => ~HTMLDivElement,
|
||||
~"img" => {
|
||||
~HTMLImageElement({ mut size: Size2D(geometry::px_to_au(100),
|
||||
geometry::px_to_au(100))
|
||||
})
|
||||
}
|
||||
~"script" => ~HTMLScriptElement,
|
||||
~"head" => ~HTMLHeadElement,
|
||||
_ => ~UnknownElement
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,14 +12,13 @@ export parse_display_type;
|
|||
fn parse_unit(str : ~str) -> option<Unit> {
|
||||
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| In(f)),
|
||||
s if s.ends_with(~"cm") => from_str(str.substr(0, str.len() - 2)).map(|f| Cm(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| Pc(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(~"px") => from_str(str.substr(0, str.len() - 2)).map(|f| Px(f)),
|
||||
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| Ex(f)),
|
||||
s if s.ends_with(~"ex") | s.ends_with(~"em") => fail ~"Em and Ex sizes not yet supported",
|
||||
_ => none,
|
||||
}
|
||||
}
|
||||
|
@ -36,9 +35,9 @@ fn parse_font_size(str : ~str) -> option<Unit> {
|
|||
~"large" => some(Px(1.2*default)),
|
||||
~"x-large" => some(Px(1.5*default)),
|
||||
~"xx-large" => some(Px(2.0*default)),
|
||||
~"smaller" => some(Em(0.8)),
|
||||
~"larger" => some(Em(1.25)),
|
||||
~"inherit" => some(Em(1.0)),
|
||||
~"smaller" => some(Percent(80.0)),
|
||||
~"larger" => some(Percent(125.0)),
|
||||
~"inherit" => some(Percent(100.0)),
|
||||
_ => parse_unit(str),
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +46,7 @@ fn parse_font_size(str : ~str) -> option<Unit> {
|
|||
fn parse_size(str : ~str) -> option<Unit> {
|
||||
match str {
|
||||
~"auto" => some(Auto),
|
||||
~"inherit" => some(Em(1.0)),
|
||||
~"inherit" => some(Percent(100.0)),
|
||||
_ => parse_unit(str),
|
||||
}
|
||||
}
|
||||
|
@ -68,13 +67,13 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn should_match_font_sizes() {
|
||||
let input = ~"* {font-size:12pt; font-size:inherit; font-size:2em; font-size:x-small}";
|
||||
let input = ~"* {font-size:12pt; font-size:inherit; font-size:200%; font-size:x-small}";
|
||||
let token_port = spawn_css_lexer_from_string(input);
|
||||
let actual_rule = build_stylesheet(token_port);
|
||||
let expected_rule : Stylesheet = ~[~(~[~Element(~"*", ~[])],
|
||||
~[FontSize(Pt(12.0)),
|
||||
FontSize(Em(1.0)),
|
||||
FontSize(Em(2.0)),
|
||||
FontSize(Percent(100.0)),
|
||||
FontSize(Percent(200.0)),
|
||||
FontSize(Px(12.0))])];
|
||||
|
||||
assert actual_rule == expected_rule;
|
||||
|
@ -89,9 +88,9 @@ mod test {
|
|||
~[Width(Percent(20.0)),
|
||||
Height(Auto),
|
||||
Width(Px(20.0)),
|
||||
Width(In(3.0)),
|
||||
Width(Pt(216.0)),
|
||||
Height(Mm(70.0)),
|
||||
Height(Cm(3.0))])];
|
||||
Height(Mm(30.0))])];
|
||||
|
||||
assert actual_rule == expected_rule;
|
||||
}
|
||||
|
|
7
src/test/height.css
Normal file
7
src/test/height.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
.start {background-color : gray; height : 600px}
|
||||
.half {background-color : red; height : 50%}
|
||||
.quarter {background-color : rgb(250, 125, 0); height : 25%}
|
||||
.eighth {background-color : yellow; height : 12.5%}
|
||||
.sixteenth {background-color : green; height : 6.25%}
|
||||
.thirtysecond {background-color : blue; height : 3.125%}
|
||||
.sixtyfourth {background-color : purple; height : 1.5625%}
|
13
src/test/height_compute.html
Normal file
13
src/test/height_compute.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<head>
|
||||
<link rel="stylesheet" href="height.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="start">
|
||||
<div class="half"></div>
|
||||
<div class="quarter"></div>
|
||||
<div class="eighth"></div>
|
||||
<div class="sixteenth"></div>
|
||||
<div class="thirtysecond"></div>
|
||||
<div class="sixtyfourth"></div>
|
||||
</div>
|
||||
</body>
|
Loading…
Add table
Add a link
Reference in a new issue