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

Scrolling improvements #491

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

Implement the beginnings of the box model for render boxes

  • Loading branch information
pcwalton committed May 29, 2013
commit 11efed672895a4a0c5eab2f35ad7dd0486c1ff97
@@ -6,7 +6,7 @@ use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;

use core::num::NumCast;
use core::num::{NumCast, One, Zero};

pub struct Au(i32);

@@ -46,6 +46,17 @@ impl cmp::Eq for Au {
fn ne(&self, other: &Au) -> bool { **self != **other }
}

impl One for Au {
fn one() -> Au { Au(1) }
}

impl Zero for Au {
fn zero() -> Au { Au(0) }
fn is_zero(&self) -> bool { **self == 0 }
}

impl Num for Au {}

pub fn min(x: Au, y: Au) -> Au { if x < y { x } else { y } }
pub fn max(x: Au, y: Au) -> Au { if x > y { x } else { y } }

@@ -8,11 +8,13 @@ use css::node_style::StyledNode;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ToGfxColor};
use layout::flow::FlowContext;
use layout::model::BoxModel;
use layout::text;

use core::cell::Cell;
use core::cmp::ApproxEq;
use core::managed;
use core::num::Zero;
use geom::{Point2D, Rect, Size2D};
use gfx::display_list::{BaseDisplayItem, BorderDisplayItem, BorderDisplayItemClass};
use gfx::display_list::{DisplayList, ImageDisplayItem, ImageDisplayItemClass};
@@ -24,7 +26,6 @@ use gfx::text::text_run::TextRun;
use newcss::color::rgb;
use newcss::complete::CompleteStyle;
use newcss::units::{Cursive, Em, Fantasy, Monospace, Pt, Px, SansSerif, Serif};
use newcss::values::{CSSBorderWidthLength, CSSBorderWidthMedium};
use newcss::values::{CSSFontFamilyFamilyName, CSSFontFamilyGenericFamily};
use newcss::values::{CSSFontSizeLength, CSSFontStyleItalic, CSSFontStyleNormal};
use newcss::values::{CSSFontStyleOblique, CSSTextAlign, CSSTextDecoration};
@@ -154,6 +155,9 @@ pub struct RenderBoxBase {
/// The position of this box relative to its owning flow.
position: Rect<Au>,

/// The core parameters (border, padding, margin) used by the box model.
model: BoxModel,

/// A debug ID.
///
/// TODO(#87) Make this only present in debug builds.
@@ -168,6 +172,7 @@ impl RenderBoxBase {
node: node,
ctx: flow_context,
position: Au::zero_rect(),
model: Zero::zero(),
id: id,
}
}
@@ -367,6 +372,16 @@ pub impl RenderBox {

/// Returns the *minimum width* of this render box as defined by the CSS specification.
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
@@ -489,13 +504,6 @@ pub impl RenderBox {
self.content_box()
}

/// A convenience function to determine whether this render box represents a DOM element.
fn is_element(&self) -> bool {
do self.with_imm_base |base| {
base.node.is_element()
}
}

/// A convenience function to access the computed style of the DOM node that this render box
/// represents.
fn style(&self) -> CompleteStyle {
@@ -684,70 +692,6 @@ pub impl RenderBox {
}
}

/// Adds the display items necessary to paint the borders of this render box to the display
/// list if necessary.
fn paint_borders_if_applicable(&self, list: &Cell<DisplayList>, abs_bounds: &Rect<Au>) {
if !self.is_element() {
return
}

let style = self.style();
let (top_width, right_width) = (style.border_top_width(), style.border_right_width());
let (bottom_width, left_width) = (style.border_bottom_width(), style.border_left_width());
match (top_width, right_width, bottom_width, left_width) {
(CSSBorderWidthLength(Px(top)),
CSSBorderWidthLength(Px(right)),
CSSBorderWidthLength(Px(bottom)),
CSSBorderWidthLength(Px(left))) => {
let top_au = Au::from_frac_px(top);
let right_au = Au::from_frac_px(right);
let bottom_au = Au::from_frac_px(bottom);
let left_au = Au::from_frac_px(left);

// Are all the widths equal?
if [ top_au, right_au, bottom_au ].all(|a| *a == left_au) {
let border_width = top_au;
let bounds = Rect {
origin: Point2D {
x: abs_bounds.origin.x - border_width / Au(2),
y: abs_bounds.origin.y - border_width / Au(2),
},
size: Size2D {
width: abs_bounds.size.width + border_width,
height: abs_bounds.size.height + border_width
}
};

let top_color = self.style().border_top_color();
let color = top_color.to_gfx_color(); // FIXME

// Append the border to the display list.
do list.with_mut_ref |list| {
let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem {
bounds: bounds,
},
width: border_width,
color: color,
};

list.append_item(BorderDisplayItemClass(border_display_item))
}
} else {
warn!("ignoring unimplemented border widths");
}
}
(CSSBorderWidthMedium,
CSSBorderWidthMedium,
CSSBorderWidthMedium,
CSSBorderWidthMedium) => {
// FIXME: This seems to be the default for non-root nodes. For now we'll ignore it.
warn!("ignoring medium border widths");
}
_ => warn!("ignoring unimplemented border widths")
}
}

/// Converts this node's computed style to a font style used for rendering.
fn font_style(&self) -> FontStyle {
let my_style = self.nearest_ancestor_element().style();
@@ -870,3 +814,4 @@ pub impl RenderBox {
}
}


@@ -0,0 +1,125 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Borders, padding, and margins.

use layout::display_list_builder::ToGfxColor;
use layout::box::RenderBox;

use core::cell::Cell;
use core::num::Zero;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use geom::side_offsets::SideOffsets2D;
use gfx::display_list::{BaseDisplayItem, BorderDisplayItem, BorderDisplayItemClass, DisplayList};
use gfx::geometry::Au;
use newcss::complete::CompleteStyle;
use newcss::units::{Em, Pt, Px};
use newcss::values::{CSSBorderWidth, CSSBorderWidthLength, CSSBorderWidthMedium};
use newcss::values::{CSSBorderWidthThick, CSSBorderWidthThin};

/// 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>,
}

impl Zero for BoxModel {
fn zero() -> BoxModel {
BoxModel {
border: Zero::zero(),
padding: Zero::zero(),
margin: Zero::zero(),
}
}

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

impl BoxModel {
/// Populates the box model parameters from the given computed style.
pub fn populate(&mut self, style: CompleteStyle) {
// Populate 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.
}

/// Helper function to compute the border width in app units from the CSS border width.
fn compute_border_width(&self, width: CSSBorderWidth) -> Au {
match width {
CSSBorderWidthLength(Px(v)) |
CSSBorderWidthLength(Em(v)) |
CSSBorderWidthLength(Pt(v)) => {
// FIXME(pcwalton): Handle `em` and `pt` correctly.
Au::from_frac_px(v)
}
CSSBorderWidthThin => Au::from_px(1),
CSSBorderWidthMedium => Au::from_px(5),
CSSBorderWidthThick => Au::from_px(10),
}
}
}

//
// Painting
//

impl RenderBox {
/// Adds the display items necessary to paint the borders of this render box to a display list
/// if necessary.
pub fn paint_borders_if_applicable(&self, list: &Cell<DisplayList>, abs_bounds: &Rect<Au>) {
// Fast path.
let border = do self.with_imm_base |base| {
base.model.border
};
if border.is_zero() {
return
}

// Are all the widths equal?
//
// FIXME(pcwalton): Obviously this is wrong.
if [ border.top, border.right, border.bottom ].all(|a| *a == border.left) {
let border_width = border.top;
let bounds = Rect {
origin: Point2D {
x: abs_bounds.origin.x - border_width / Au(2),
y: abs_bounds.origin.y - border_width / Au(2),
},
size: Size2D {
width: abs_bounds.size.width + border_width,
height: abs_bounds.size.height + border_width
}
};

let top_color = self.style().border_top_color();
let color = top_color.to_gfx_color(); // FIXME

// Append the border to the display list.
do list.with_mut_ref |list| {
let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem {
bounds: bounds,
},
width: border_width,
color: color,
};

list.append_item(BorderDisplayItemClass(border_display_item))
}
} else {
warn!("ignoring unimplemented border widths");
}
}

}

@@ -68,6 +68,7 @@ pub mod layout {
pub mod flow;
pub mod layout_task;
pub mod inline;
pub mod model;
pub mod text;
mod aux;
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.