Properly account for relative CSS units in borders, margins, padding, and widths.

This commit is contained in:
Jack Moffitt 2013-07-18 19:31:52 -06:00
parent 09acdcc4ec
commit 9a1d4d593b
5 changed files with 103 additions and 67 deletions

View file

@ -202,14 +202,16 @@ impl BlockFlowData {
// Top and bottom margins for blocks are 0 if auto. // Top and bottom margins for blocks are 0 if auto.
let margin_top = MaybeAuto::from_margin(style.margin_top(), let margin_top = MaybeAuto::from_margin(style.margin_top(),
remaining_width).spec_or_default(Au(0)); remaining_width,
style.font_size()).spec_or_default(Au(0));
let margin_bottom = MaybeAuto::from_margin(style.margin_bottom(), let margin_bottom = MaybeAuto::from_margin(style.margin_bottom(),
remaining_width).spec_or_default(Au(0)); remaining_width,
style.font_size()).spec_or_default(Au(0));
let (width, margin_left, margin_right) = let (width, margin_left, margin_right) =
(MaybeAuto::from_width(style.width(), remaining_width), (MaybeAuto::from_width(style.width(), remaining_width, style.font_size()),
MaybeAuto::from_margin(style.margin_left(), remaining_width), MaybeAuto::from_margin(style.margin_left(), remaining_width, style.font_size()),
MaybeAuto::from_margin(style.margin_right(), remaining_width)); MaybeAuto::from_margin(style.margin_right(), remaining_width, style.font_size()));
let (width, margin_left, margin_right) = self.compute_horiz(width, let (width, margin_left, margin_right) = self.compute_horiz(width,
margin_left, margin_left,
@ -297,7 +299,7 @@ impl BlockFlowData {
for self.box.iter().advance |&box| { for self.box.iter().advance |&box| {
let style = box.style(); let style = box.style();
let maybe_height = MaybeAuto::from_height(style.height(), Au(0)); let maybe_height = MaybeAuto::from_height(style.height(), Au(0), style.font_size());
let maybe_height = maybe_height.spec_or_default(Au(0)); let maybe_height = maybe_height.spec_or_default(Au(0));
height = geometry::max(height, maybe_height); height = geometry::max(height, maybe_height);
} }

View file

@ -388,14 +388,25 @@ impl RenderBox {
if(!base.node.is_element()) { if(!base.node.is_element()) {
Au(0) Au(0)
} else { } else {
let style = self.style();
let w = MaybeAuto::from_width(self.style().width(), Au(0)).spec_or_default(Au(0)); let font_size = style.font_size();
let ml = MaybeAuto::from_margin(self.style().margin_left(), Au(0)).spec_or_default(Au(0)); let w = MaybeAuto::from_width(style.width(),
let mr = MaybeAuto::from_margin(self.style().margin_right(), Au(0)).spec_or_default(Au(0)); Au(0),
let pl = base.model.compute_padding_length(self.style().padding_left(), Au(0)); font_size).spec_or_default(Au(0));
let pr = base.model.compute_padding_length(self.style().padding_right(), Au(0)); let ml = MaybeAuto::from_margin(style.margin_left(),
let bl = base.model.compute_border_width(self.style().border_left_width()); Au(0),
let br = base.model.compute_border_width(self.style().border_right_width()); font_size).spec_or_default(Au(0));
let mr = MaybeAuto::from_margin(style.margin_right(),
Au(0),
font_size).spec_or_default(Au(0));
let pl = base.model.compute_padding_length(style.padding_left(),
Au(0),
font_size);
let pr = base.model.compute_padding_length(style.padding_right(),
Au(0),
font_size);
let bl = base.model.compute_border_width(style.border_left_width(), font_size);
let br = base.model.compute_border_width(style.border_right_width(), font_size);
w + ml + mr + pl + pr + bl + br w + ml + mr + pl + pr + bl + br
} }

View file

@ -106,13 +106,17 @@ impl FloatFlowData {
// Margins for floats are 0 if auto. // Margins for floats are 0 if auto.
let margin_top = MaybeAuto::from_margin(style.margin_top(), let margin_top = MaybeAuto::from_margin(style.margin_top(),
remaining_width).spec_or_default(Au(0)); remaining_width,
style.font_size()).spec_or_default(Au(0));
let margin_bottom = MaybeAuto::from_margin(style.margin_bottom(), let margin_bottom = MaybeAuto::from_margin(style.margin_bottom(),
remaining_width).spec_or_default(Au(0)); remaining_width,
style.font_size()).spec_or_default(Au(0));
let margin_left = MaybeAuto::from_margin(style.margin_left(), let margin_left = MaybeAuto::from_margin(style.margin_left(),
remaining_width).spec_or_default(Au(0)); remaining_width,
style.font_size()).spec_or_default(Au(0));
let margin_right = MaybeAuto::from_margin(style.margin_right(), let margin_right = MaybeAuto::from_margin(style.margin_right(),
remaining_width).spec_or_default(Au(0)); remaining_width,
style.font_size()).spec_or_default(Au(0));
@ -122,7 +126,8 @@ impl FloatFlowData {
let width = MaybeAuto::from_width(style.width(), let width = MaybeAuto::from_width(style.width(),
remaining_width).spec_or_default(shrink_to_fit); remaining_width,
style.font_size()).spec_or_default(shrink_to_fit);
debug!("assign_widths_float -- width: %?", width); debug!("assign_widths_float -- width: %?", width);
model.margin.top = margin_top; model.margin.top = margin_top;
@ -197,9 +202,10 @@ impl FloatFlowData {
//TODO(eatkinson): compute heights properly using the 'height' property. //TODO(eatkinson): compute heights properly using the 'height' property.
for self.box.iter().advance |&box| { for self.box.iter().advance |&box| {
let height_prop = let height_prop =
MaybeAuto::from_height(box.style().height(), Au(0)).spec_or_default(Au(0)); MaybeAuto::from_height(box.style().height(),
Au(0),
box.style().font_size()).spec_or_default(Au(0));
height = geometry::max(height, height_prop) + noncontent_height; height = geometry::max(height, height_prop) + noncontent_height;
debug!("assign_height_float -- height: %?", height); debug!("assign_height_float -- height: %?", height);

View file

@ -10,7 +10,7 @@ use gfx::geometry::Au;
use newcss::complete::CompleteStyle; use newcss::complete::CompleteStyle;
use newcss::units::{Em, Pt, Px}; use newcss::units::{Em, Pt, Px};
use newcss::values::{CSSBorderWidth, CSSBorderWidthLength, CSSBorderWidthMedium}; use newcss::values::{CSSBorderWidth, CSSBorderWidthLength, CSSBorderWidthMedium};
use newcss::values::{CSSBorderWidthThick, CSSBorderWidthThin}; use newcss::values::{CSSBorderWidthThick, CSSBorderWidthThin, CSSFontSize, CSSFontSizeLength};
use newcss::values::{CSSWidth, CSSWidthLength, CSSWidthPercentage, CSSWidthAuto}; use newcss::values::{CSSWidth, CSSWidthLength, CSSWidthPercentage, CSSWidthAuto};
use newcss::values::{CSSHeight, CSSHeightLength, CSSHeightPercentage, CSSHeightAuto}; use newcss::values::{CSSHeight, CSSHeightLength, CSSHeightPercentage, CSSHeightAuto};
use newcss::values::{CSSMargin, CSSMarginLength, CSSMarginPercentage, CSSMarginAuto}; use newcss::values::{CSSMargin, CSSMarginLength, CSSMarginPercentage, CSSMarginAuto};
@ -30,45 +30,60 @@ pub enum MaybeAuto {
Specified(Au), Specified(Au),
} }
impl MaybeAuto{ impl MaybeAuto {
pub fn from_margin(margin: CSSMargin, cb_width: Au) -> MaybeAuto{ pub fn from_margin(margin: CSSMargin, cb_width: Au, font_size: CSSFontSize) -> MaybeAuto {
match margin { match margin {
CSSMarginAuto => Auto, CSSMarginAuto => Auto,
//FIXME(eatkinson): Compute percents properly
CSSMarginPercentage(percent) => Specified(cb_width.scale_by(percent/100.0)), CSSMarginPercentage(percent) => Specified(cb_width.scale_by(percent/100.0)),
//FIXME(eatkinson): Compute pt and em values properly CSSMarginLength(Px(v)) => Specified(Au::from_frac_px(v)),
CSSMarginLength(Px(v)) | CSSMarginLength(Pt(v)) => Specified(Au::from_pt(v)),
CSSMarginLength(Pt(v)) | CSSMarginLength(Em(em)) => match font_size {
CSSMarginLength(Em(v)) => Specified(Au::from_frac_px(v)), CSSFontSizeLength(Px(v)) =>
Specified(Au::from_frac_px(em * v)),
CSSFontSizeLength(Pt(v)) =>
Specified(Au::from_pt(em * v)),
_ => fail!(~"expected non-relative font size"),
}
} }
} }
pub fn from_width(width: CSSWidth, cb_width: Au) -> MaybeAuto{ pub fn from_width(width: CSSWidth, cb_width: Au, font_size: CSSFontSize) -> MaybeAuto {
match width{ match width {
CSSWidthAuto => Auto, CSSWidthAuto => Auto,
CSSWidthPercentage(percent) => Specified(cb_width.scale_by(percent/100.0)), CSSWidthPercentage(percent) => Specified(cb_width.scale_by(percent/100.0)),
//FIXME(eatkinson): Compute pt and em values properly CSSWidthLength(Px(v)) => Specified(Au::from_frac_px(v)),
CSSWidthLength(Px(v)) | CSSWidthLength(Pt(v)) => Specified(Au::from_pt(v)),
CSSWidthLength(Pt(v)) | CSSWidthLength(Em(em)) => match font_size {
CSSWidthLength(Em(v)) => Specified(Au::from_frac_px(v)), CSSFontSizeLength(Px(v)) =>
Specified(Au::from_frac_px(em * v)),
CSSFontSizeLength(Pt(v)) =>
Specified(Au::from_pt(em * v)),
_ => fail!(~"expected non-relative font size"),
}
} }
} }
pub fn from_height(height: CSSHeight, cb_height: Au) -> MaybeAuto{ pub fn from_height(height: CSSHeight, cb_height: Au, font_size: CSSFontSize) -> MaybeAuto {
match height { match height {
CSSHeightAuto => Auto, CSSHeightAuto => Auto,
CSSHeightPercentage(percent) => Specified(cb_height.scale_by(percent/100.0)), CSSHeightPercentage(percent) => Specified(cb_height.scale_by(percent/100.0)),
//FIXME(eatkinson): Compute pt and em values properly CSSHeightLength(Px(v)) => Specified(Au::from_frac_px(v)),
CSSHeightLength(Px(v)) | CSSHeightLength(Pt(v)) => Specified(Au::from_pt(v)),
CSSHeightLength(Pt(v)) | CSSHeightLength(Em(em)) => match font_size {
CSSHeightLength(Em(v)) => Specified(Au::from_frac_px(v)), CSSFontSizeLength(Px(v)) =>
Specified(Au::from_frac_px(em * v)),
CSSFontSizeLength(Pt(v)) =>
Specified(Au::from_pt(em * v)),
_ => fail!(~"expected non-relative font size"),
}
} }
} }
pub fn spec_or_default(&self, default: Au) -> Au{ pub fn spec_or_default(&self, default: Au) -> Au {
match *self{ match *self {
Auto => default, Auto => default,
Specified(value) => value Specified(value) => value,
} }
} }
} }
@ -92,17 +107,17 @@ impl BoxModel {
/// Populates the box model parameters from the given computed style. /// Populates the box model parameters from the given computed style.
pub fn compute_borders(&mut self, style: CompleteStyle) { pub fn compute_borders(&mut self, style: CompleteStyle) {
// Compute the borders. // Compute the borders.
self.border.top = self.compute_border_width(style.border_top_width()); self.border.top = self.compute_border_width(style.border_top_width(), style.font_size());
self.border.right = self.compute_border_width(style.border_right_width()); self.border.right = self.compute_border_width(style.border_right_width(), style.font_size());
self.border.bottom = self.compute_border_width(style.border_bottom_width()); self.border.bottom = self.compute_border_width(style.border_bottom_width(), style.font_size());
self.border.left = self.compute_border_width(style.border_left_width()); self.border.left = self.compute_border_width(style.border_left_width(), style.font_size());
} }
pub fn compute_padding(&mut self, style: CompleteStyle, cb_width: Au){ pub fn compute_padding(&mut self, style: CompleteStyle, cb_width: Au) {
self.padding.top = self.compute_padding_length(style.padding_top(), cb_width); self.padding.top = self.compute_padding_length(style.padding_top(), cb_width, style.font_size());
self.padding.right = self.compute_padding_length(style.padding_right(), cb_width); self.padding.right = self.compute_padding_length(style.padding_right(), cb_width, style.font_size());
self.padding.bottom = self.compute_padding_length(style.padding_bottom(), cb_width); self.padding.bottom = self.compute_padding_length(style.padding_bottom(), cb_width, style.font_size());
self.padding.left = self.compute_padding_length(style.padding_left(), cb_width); self.padding.left = self.compute_padding_length(style.padding_left(), cb_width, style.font_size());
} }
pub fn noncontent_width(&self) -> Au { pub fn noncontent_width(&self) -> Au {
@ -116,28 +131,30 @@ impl BoxModel {
} }
/// Helper function to compute the border width in app units from the CSS border width. /// Helper function to compute the border width in app units from the CSS border width.
pub fn compute_border_width(&self, width: CSSBorderWidth) -> Au { pub fn compute_border_width(&self, width: CSSBorderWidth, font_size: CSSFontSize) -> Au {
match width { match width {
CSSBorderWidthLength(Px(v)) | CSSBorderWidthLength(Px(v)) => Au::from_frac_px(v),
CSSBorderWidthLength(Em(v)) | CSSBorderWidthLength(Pt(v)) => Au::from_pt(v),
CSSBorderWidthLength(Pt(v)) => { CSSBorderWidthLength(Em(em)) => match font_size {
// FIXME(pcwalton): Handle `em` and `pt` correctly. CSSFontSizeLength(Px(v)) => Au::from_frac_px(em * v),
Au::from_frac_px(v) CSSFontSizeLength(Pt(v)) => Au::from_pt(em * v),
} _ => fail!(~"expected non-relative font size"),
},
CSSBorderWidthThin => Au::from_px(1), CSSBorderWidthThin => Au::from_px(1),
CSSBorderWidthMedium => Au::from_px(5), CSSBorderWidthMedium => Au::from_px(5),
CSSBorderWidthThick => Au::from_px(10), CSSBorderWidthThick => Au::from_px(10),
} }
} }
pub fn compute_padding_length(&self, padding: CSSPadding, content_box_width: Au) -> Au { pub fn compute_padding_length(&self, padding: CSSPadding, content_box_width: Au, font_size: CSSFontSize) -> Au {
match padding { match padding {
CSSPaddingLength(Px(v)) | CSSPaddingLength(Px(v)) => Au::from_frac_px(v),
CSSPaddingLength(Pt(v)) | CSSPaddingLength(Pt(v)) => Au::from_pt(v),
CSSPaddingLength(Em(v)) => { CSSPaddingLength(Em(em)) => match font_size {
// FIXME(eatkinson): Handle 'em' and 'pt' correctly CSSFontSizeLength(Px(v)) => Au::from_frac_px(em * v),
Au::from_frac_px(v) CSSFontSizeLength(Pt(v)) => Au::from_pt(em * v),
} _ => fail!(~"expected non-relative font size"),
},
CSSPaddingPercentage(p) => content_box_width.scale_by(p/100.0) CSSPaddingPercentage(p) => content_box_width.scale_by(p/100.0)
} }
} }

@ -1 +1 @@
Subproject commit 7a584804a98b5731fb53d216c3f059e5a0c7ea5c Subproject commit 8b9cf93fb03027d0f125afbd84cf758bd8d2d676