Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NSS/NSPR, scroll fixes, texture upload fixes, and hit testing #495

Closed
wants to merge 16 commits into from
Closed
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Add horizontal borders, margins and padding. Broken until rust-css su…

…pports padding
  • Loading branch information
Eric Atkinson Tim Kuehn
Eric Atkinson authored and Tim Kuehn committed May 31, 2013
commit ef1785d0c05f00b3f160b767095b16934e7e2c51
@@ -10,6 +10,7 @@ use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::display_list_builder::{FlowDisplayListBuilderMethods};
use layout::flow::{BlockFlow, FlowContext, FlowData, InlineBlockFlow};
use layout::inline::InlineLayout;
use layout::model::{MaybeAuto, Specified, Auto};

use core::cell::Cell;
use geom::point::Point2D;
@@ -104,6 +105,8 @@ impl BlockFlowData {
/* if not an anonymous block context, add in block box's widths.
these widths will not include child elements, just padding etc. */
self.box.map(|&box| {
//Can compute border width here since it doesn't depend on anything
box.compute_borders();
min_width = min_width.add(&box.get_min_width(ctx));
pref_width = pref_width.add(&box.get_pref_width(ctx));
});
@@ -112,6 +115,57 @@ impl BlockFlowData {
self.common.pref_width = pref_width;
}

/// Computes left and right margins and width based on CSS 2.1 secion 10.3.3.
/// Requires borders and padding to already be computed
priv fn compute_horiz( &self,
width: MaybeAuto,
left_margin: MaybeAuto,
right_margin: MaybeAuto,
available_width: Au) -> (Au, Au, Au) {

//If width is not 'auto', and width + margins > available_width, all 'auto' margins are treated as '0'
let (left_margin, right_margin) = match width{
Auto => (left_margin, right_margin),
Specified(width) => {
let left = left_margin.spec_or_default(Au(0));
let right = right_margin.spec_or_default(Au(0));

if((left + right + width) > available_width) {
(Specified(left), Specified(right))
} else {
(left_margin, right_margin)
}
}
};

//Invariant: left_margin_Au + width_Au + right_margin_Au == available_width
let (left_margin_Au, width_Au, right_margin_Au) = match (left_margin, width, right_margin) {
//If all have a computed value other than 'auto', the system is over-constrained and we need to discard a margin.
//if direction is ltr, ignore the specified right margin and solve for it. If it is rtl, ignore the specified
//left margin. FIXME(eatkinson): this assumes the direction is ltr
(Specified(margin_l), Specified(width), Specified(margin_r)) => (margin_l, width, available_width - (margin_l + width )),

//If exactly one value is 'auto', solve for it
(Auto, Specified(width), Specified(margin_r)) => (available_width - (width + margin_r), width, margin_r),
(Specified(margin_l), Auto, Specified(margin_r)) => (margin_l, available_width - (margin_l + margin_r), margin_r),
(Specified(margin_l), Specified(width), Auto) => (margin_l, width, available_width - (margin_l + width)),

//If width is set to 'auto', any other 'auto' value becomes '0', and width is solved for
(Auto, Auto, Specified(margin_r)) => (Au(0), available_width - margin_r, margin_r),
(Specified(margin_l), Auto, Auto) => (margin_l, available_width - margin_l, Au(0)),
(Auto, Auto, Auto) => (Au(0), available_width, Au(0)),

//If left and right margins are auto, they become equal
(Auto, Specified(width), Auto) => {
let margin = (available_width - width).scale_by(0.5);
(margin, width, margin)
}

};
//return values in same order as params
(width_Au, left_margin_Au, right_margin_Au)
}

/// Recursively (top-down) determines the actual width of child contexts and boxes. When called
/// on this context, the context has had its width set by the parent context.
///
@@ -123,24 +177,28 @@ impl BlockFlowData {
self.common.position.size.width = ctx.screen_size.size.width;
}

//position was set to the containing block by the flow's parent
let mut remaining_width = self.common.position.size.width;
let left_used = Au(0);
let mut x_offset = Au(0);

// Let the box consume some width. It will return the amount remaining for its children.
self.box.map(|&box| {
do box.with_mut_base |base| {
base.position.size.width = remaining_width;
box.compute_padding(remaining_width);
let available_width = remaining_width - box.get_noncontent_width();

let (left_used, right_used) = box.get_used_width();
remaining_width -= left_used.add(&right_used);
do box.compute_width(remaining_width) |width, left_margin, right_margin| {
self.compute_horiz(width, left_margin, right_margin, available_width)
}

let content_box = box.content_box();
x_offset = content_box.origin.x;
remaining_width = content_box.size.width;
});

for BlockFlow(self).each_child |kid| {
assert!(kid.starts_block_flow() || kid.starts_inline_flow());

do kid.with_mut_base |child_node| {
child_node.position.origin.x = left_used;
child_node.position.origin.x = x_offset;
child_node.position.size.width = remaining_width;
}
}
@@ -8,7 +8,7 @@ use css::node_style::StyledNode;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToGfxColor};
use layout::flow::FlowContext;
use layout::model::BoxModel;
use layout::model::{BoxModel,MaybeAuto};
use layout::text;

use core::cell::Cell;
@@ -374,14 +374,6 @@ pub impl RenderBox {
fn get_min_width(&self, _: &LayoutContext) -> Au {
// FIXME(pcwalton): I think we only need to calculate this if the damage says that CSS
// needs to be restyled.
do self.with_mut_base |base| {
// TODO(pcwalton): Hmm, it seems wasteful to have the box model stuff inside every
// render box if they can only be nonzero if the box is an element.
if base.node.is_element() {
base.model.populate(base.node.style())
}
}

match *self {
// TODO: This should account for the minimum width of the box element in isolation.
// That includes borders, margins, and padding, but not child widths. The block
@@ -456,37 +448,51 @@ pub impl RenderBox {
(Au(0), Au(0))
}

/// The box formed by the content edge as defined in CSS 2.1 § 8.1. Coordinates are relative to
/// the owning flow.
fn content_box(&self) -> Rect<Au> {
let origin = self.position().origin;
match *self {
ImageRenderBoxClass(image_box) => {
Rect {
origin: origin,
size: image_box.base.position.size,
}
},
GenericRenderBoxClass(*) => {
self.position()
fn compute_padding(&self, cb_width: Au) {
do self.with_imm_base |base| {
base.model.compute_padding(self.style(), cb_width);
}
}

// FIXME: The following hits an ICE for whatever reason.
fn compute_borders(&self){
do self.with_imm_base |base| {
base.model.compute_borders(self.style());
}
}

/*
let origin = self.d().position.origin;
let size = self.d().position.size;
let (offset_left, offset_right) = self.get_used_width();
let (offset_top, offset_bottom) = self.get_used_height();
fn get_noncontent_width(&self) -> Au {
do self.with_imm_base |base| {
base.model.border.left + base.model.padding.left + base.model.border.right +
base.model.padding.right
}
}

Rect {
origin: Point2D(origin.x + offset_left, origin.y + offset_top),
size: Size2D(size.width - (offset_left + offset_right),
size.height - (offset_top + offset_bottom))
}
*/
},
TextRenderBoxClass(*) => self.position(),
UnscannedTextRenderBoxClass(*) => fail!(~"Shouldn't see unscanned boxes here.")
fn compute_width (&self, cb_width: Au,
callback: &fn(MaybeAuto, MaybeAuto, MaybeAuto) -> (Au, Au, Au)) {
let computed_width = MaybeAuto::from_width(self.style().width());
let computed_margin_left = MaybeAuto::from_margin(self.style().margin_left());
let computed_margin_right = MaybeAuto::from_margin(self.style().margin_right());

let (used_width, used_margin_left, used_margin_right) =
callback(computed_width, computed_margin_left, computed_margin_right);

do self.with_mut_base |base| {
base.model.margin.left = used_margin_left;
base.model.margin.right = used_margin_right;
base.position.size.width = used_width + self.get_noncontent_width();
base.position.origin.x = used_margin_left;
}
}

/// The box formed by the content edge as defined in CSS 2.1 § 8.1. Coordinates are relative to
/// the owning flow.
fn content_box(&self) -> Rect<Au> {
do self.with_imm_base |base| {
let origin = Point2D(base.position.origin.x + base.model.border.left + base.model.padding.left,
base.position.origin.y);
let size = Size2D(base.position.size.width - self.get_noncontent_width(),
base.position.size.height);
Rect(origin, size)
}
}

@@ -19,12 +19,54 @@ use newcss::complete::CompleteStyle;
use newcss::units::{Em, Pt, Px};
use newcss::values::{CSSBorderWidth, CSSBorderWidthLength, CSSBorderWidthMedium};
use newcss::values::{CSSBorderWidthThick, CSSBorderWidthThin};

use newcss::values::{CSSWidth, CSSWidthLength, CSSWidthPercentage, CSSWidthAuto};
use newcss::values::{CSSMargin, CSSMarginLength, CSSMarginPercentage, CSSMarginAuto};
use newcss::values::{CSSPadding, CSSPaddingLength, CSSPaddingPercentage};
/// Encapsulates the borders, padding, and margins, which we collectively call the "box model".
pub struct BoxModel {
border: SideOffsets2D<Au>,
padding: SideOffsets2D<Au>,
margin: SideOffsets2D<Au>,
content_width: Au,
}

/// Useful helper data type when computing values for blocks and positioned elements.
pub enum MaybeAuto{
Auto,
Specified(Au),
}

impl MaybeAuto{
pub fn from_margin(margin: CSSMargin) -> MaybeAuto{
match margin {
CSSMarginAuto => Auto,
//FIXME(eatkinson): Compute percents properly
CSSMarginPercentage(_) => Specified(Au(0)),
//FIXME(eatkinson): Compute pt and em values properly
CSSMarginLength(Px(v)) |
CSSMarginLength(Pt(v)) |
CSSMarginLength(Em(v)) => Specified(Au::from_frac_px(v)),
}
}

pub fn from_width(width: CSSWidth) -> MaybeAuto{
match width{
CSSWidthAuto => Auto,
//FIXME(eatkinson): Compute percents properly
CSSWidthPercentage(_) => Specified(Au(0)),
//FIXME(eatkinson): Compute pt and em values properly
CSSWidthLength(Px(v)) |
CSSWidthLength(Pt(v)) |
CSSWidthLength(Em(v)) => Specified(Au::from_frac_px(v)),
}
}

pub fn spec_or_default(&self, default: Au) -> Au{
match *self{
Auto => default,
Specified(value) => value
}
}
}

impl Zero for BoxModel {
@@ -33,24 +75,31 @@ impl Zero for BoxModel {
border: Zero::zero(),
padding: Zero::zero(),
margin: Zero::zero(),
content_width: Zero::zero(),
}
}

fn is_zero(&self) -> bool {
self.padding.is_zero() && self.border.is_zero() && self.margin.is_zero()
self.padding.is_zero() && self.border.is_zero() && self.margin.is_zero() &&
self.content_width.is_zero()
}
}

impl BoxModel {
/// Populates the box model parameters from the given computed style.
pub fn populate(&mut self, style: CompleteStyle) {
// Populate the borders.
pub fn compute_borders(&mut self, style: CompleteStyle) {
// Compute the borders.
self.border.top = self.compute_border_width(style.border_top_width());
self.border.right = self.compute_border_width(style.border_right_width());
self.border.bottom = self.compute_border_width(style.border_bottom_width());
self.border.left = self.compute_border_width(style.border_left_width());
}

// TODO(pcwalton): Padding, margins.
pub fn compute_padding(&mut self, style: CompleteStyle, cb_width: Au){
self.padding.top = self.compute_padding(style.padding_top(), cb_width);
self.padding.right = self.compute_padding(style.padding_right(), cb_width);
self.padding.bottom = self.compute_padding(style.padding_bottom(), cb_width);
self.padding.left = self.compute_padding(style.padding_left(), cb_width);
}

/// Helper function to compute the border width in app units from the CSS border width.
@@ -67,6 +116,18 @@ impl BoxModel {
CSSBorderWidthThick => Au::from_px(10),
}
}

fn compute_padding(&self, padding: CSSPadding, cb_width: Au) -> Au{
match padding {
CSSPaddingLength(Px(v)) |
CSSPaddingLength(Pt(v)) |
CSSPaddingLength(Em(v)) => {
// FIXME(eatkinson): Handle 'em' and 'pt' correctly
Au::from_frac_px(v)
}
CSSPaddingPercentage(p) => cb_width.scale_by(p)
}
}
}

//
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.