mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Implement the beginnings of the box model for render boxes
This commit is contained in:
parent
c14a137233
commit
233a2040da
4 changed files with 155 additions and 73 deletions
|
@ -6,7 +6,7 @@ use geom::point::Point2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
|
||||||
use core::num::NumCast;
|
use core::num::{NumCast, One, Zero};
|
||||||
|
|
||||||
pub struct Au(i32);
|
pub struct Au(i32);
|
||||||
|
|
||||||
|
@ -46,6 +46,17 @@ impl cmp::Eq for Au {
|
||||||
fn ne(&self, other: &Au) -> bool { **self != **other }
|
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 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 } }
|
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::context::LayoutContext;
|
||||||
use layout::display_list_builder::{DisplayListBuilder, ToGfxColor};
|
use layout::display_list_builder::{DisplayListBuilder, ToGfxColor};
|
||||||
use layout::flow::FlowContext;
|
use layout::flow::FlowContext;
|
||||||
|
use layout::model::BoxModel;
|
||||||
use layout::text;
|
use layout::text;
|
||||||
|
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use core::cmp::ApproxEq;
|
use core::cmp::ApproxEq;
|
||||||
use core::managed;
|
use core::managed;
|
||||||
|
use core::num::Zero;
|
||||||
use geom::{Point2D, Rect, Size2D};
|
use geom::{Point2D, Rect, Size2D};
|
||||||
use gfx::display_list::{BaseDisplayItem, BorderDisplayItem, BorderDisplayItemClass};
|
use gfx::display_list::{BaseDisplayItem, BorderDisplayItem, BorderDisplayItemClass};
|
||||||
use gfx::display_list::{DisplayList, ImageDisplayItem, ImageDisplayItemClass};
|
use gfx::display_list::{DisplayList, ImageDisplayItem, ImageDisplayItemClass};
|
||||||
|
@ -24,7 +26,6 @@ use gfx::text::text_run::TextRun;
|
||||||
use newcss::color::rgb;
|
use newcss::color::rgb;
|
||||||
use newcss::complete::CompleteStyle;
|
use newcss::complete::CompleteStyle;
|
||||||
use newcss::units::{Cursive, Em, Fantasy, Monospace, Pt, Px, SansSerif, Serif};
|
use newcss::units::{Cursive, Em, Fantasy, Monospace, Pt, Px, SansSerif, Serif};
|
||||||
use newcss::values::{CSSBorderWidthLength, CSSBorderWidthMedium};
|
|
||||||
use newcss::values::{CSSFontFamilyFamilyName, CSSFontFamilyGenericFamily};
|
use newcss::values::{CSSFontFamilyFamilyName, CSSFontFamilyGenericFamily};
|
||||||
use newcss::values::{CSSFontSizeLength, CSSFontStyleItalic, CSSFontStyleNormal};
|
use newcss::values::{CSSFontSizeLength, CSSFontStyleItalic, CSSFontStyleNormal};
|
||||||
use newcss::values::{CSSFontStyleOblique, CSSTextAlign, CSSTextDecoration};
|
use newcss::values::{CSSFontStyleOblique, CSSTextAlign, CSSTextDecoration};
|
||||||
|
@ -154,6 +155,9 @@ pub struct RenderBoxBase {
|
||||||
/// The position of this box relative to its owning flow.
|
/// The position of this box relative to its owning flow.
|
||||||
position: Rect<Au>,
|
position: Rect<Au>,
|
||||||
|
|
||||||
|
/// The core parameters (border, padding, margin) used by the box model.
|
||||||
|
model: BoxModel,
|
||||||
|
|
||||||
/// A debug ID.
|
/// A debug ID.
|
||||||
///
|
///
|
||||||
/// TODO(#87) Make this only present in debug builds.
|
/// TODO(#87) Make this only present in debug builds.
|
||||||
|
@ -168,6 +172,7 @@ impl RenderBoxBase {
|
||||||
node: node,
|
node: node,
|
||||||
ctx: flow_context,
|
ctx: flow_context,
|
||||||
position: Au::zero_rect(),
|
position: Au::zero_rect(),
|
||||||
|
model: Zero::zero(),
|
||||||
id: id,
|
id: id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,6 +372,16 @@ pub impl RenderBox {
|
||||||
|
|
||||||
/// Returns the *minimum width* of this render box as defined by the CSS specification.
|
/// Returns the *minimum width* of this render box as defined by the CSS specification.
|
||||||
fn get_min_width(&self, _: &LayoutContext) -> Au {
|
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 {
|
match *self {
|
||||||
// TODO: This should account for the minimum width of the box element in isolation.
|
// 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
|
// That includes borders, margins, and padding, but not child widths. The block
|
||||||
|
@ -489,13 +504,6 @@ pub impl RenderBox {
|
||||||
self.content_box()
|
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
|
/// A convenience function to access the computed style of the DOM node that this render box
|
||||||
/// represents.
|
/// represents.
|
||||||
fn style(&self) -> CompleteStyle {
|
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.
|
/// Converts this node's computed style to a font style used for rendering.
|
||||||
fn font_style(&self) -> FontStyle {
|
fn font_style(&self) -> FontStyle {
|
||||||
let my_style = self.nearest_ancestor_element().style();
|
let my_style = self.nearest_ancestor_element().style();
|
||||||
|
@ -870,3 +814,4 @@ pub impl RenderBox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
125
src/components/main/layout/model.rs
Normal file
125
src/components/main/layout/model.rs
Normal file
|
@ -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 flow;
|
||||||
pub mod layout_task;
|
pub mod layout_task;
|
||||||
pub mod inline;
|
pub mod inline;
|
||||||
|
pub mod model;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
mod aux;
|
mod aux;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue