implement position:relative

This commit is contained in:
patrick kim 2014-01-27 11:43:42 +09:00
parent 35a869d3d6
commit a90c2e3a26
10 changed files with 147 additions and 13 deletions

View file

@ -13,7 +13,7 @@ use layout::model::{MaybeAuto, Specified, Auto, specified_or_none, specified};
use layout::float_context::{FloatContext, PlacementInfo, Invalid, FloatType};
use std::cell::RefCell;
use geom::{Point2D, Rect, SideOffsets2D};
use geom::{Point2D, Rect, SideOffsets2D, Size2D};
use gfx::display_list::{DisplayList, DisplayListCollection};
use servo_util::geometry::Au;
use servo_util::geometry;
@ -533,12 +533,13 @@ impl BlockFlow {
pub fn build_display_list_block<E:ExtraDisplayListData>(
&mut self,
builder: &DisplayListBuilder,
container_block_size: &Size2D<Au>,
dirty: &Rect<Au>,
mut index: uint,
lists: &RefCell<DisplayListCollection<E>>)
-> uint {
if self.is_float() {
self.build_display_list_float(builder, dirty, index, lists);
self.build_display_list_float(builder, container_block_size, dirty, index, lists);
return index;
}
@ -556,16 +557,28 @@ impl BlockFlow {
debug!("build_display_list_block: adding display element");
let rel_offset = match self.box_ {
Some(ref box_) => {
box_.relative_position(container_block_size)
},
None => {
Point2D {
x: Au::new(0),
y: Au::new(0),
}
}
};
// add box that starts block context
for box_ in self.box_.iter() {
box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, index, lists);
box_.build_display_list(builder, dirty, self.base.abs_position + rel_offset, (&*self) as &Flow, index, lists);
}
// TODO: handle any out-of-flow elements
let this_position = self.base.abs_position;
for child in self.base.child_iter() {
let child_base = flow::mut_base(*child);
child_base.abs_position = this_position + child_base.position.origin;
child_base.abs_position = this_position + child_base.position.origin + rel_offset;
}
index
@ -574,6 +587,7 @@ impl BlockFlow {
pub fn build_display_list_float<E:ExtraDisplayListData>(
&mut self,
builder: &DisplayListBuilder,
container_block_size: &Size2D<Au>,
dirty: &Rect<Au>,
index: uint,
lists: &RefCell<DisplayListCollection<E>>)
@ -583,8 +597,21 @@ impl BlockFlow {
return true;
}
// position:relative
let rel_offset = match self.box_ {
Some(ref box_) => {
box_.relative_position(container_block_size)
},
None => {
Point2D {
x: Au::new(0),
y: Au::new(0),
}
}
};
let offset = self.base.abs_position + self.float.get_ref().rel_pos;
let offset = self.base.abs_position + self.float.get_ref().rel_pos + rel_offset;
// add box that starts block context
for box_ in self.box_.iter() {
box_.build_display_list(builder, dirty, offset, (&*self) as &Flow, index, lists);
@ -596,7 +623,7 @@ impl BlockFlow {
// go deeper into the flow tree
for child in self.base.child_iter() {
let child_base = flow::mut_base(*child);
child_base.abs_position = offset + child_base.position.origin;
child_base.abs_position = offset + child_base.position.origin + rel_offset;
}
false

View file

@ -29,7 +29,7 @@ use std::cmp::ApproxEq;
use std::num::Zero;
use style::{ComputedValues, TElement, TNode};
use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto, overflow, LPA_Auto};
use style::computed_values::{border_style, clear, font_family, line_height};
use style::computed_values::{border_style, clear, font_family, line_height, position};
use style::computed_values::{text_align, text_decoration, vertical_align, visibility, white_space};
use css::node_style::StyledNode;
@ -651,6 +651,59 @@ impl Box {
&None => {}
}
}
pub fn relative_position(&self, container_block_size: &Size2D<Au>) -> Point2D<Au> {
fn left_right(style: &ComputedValues,block_width: Au) -> Au {
// TODO(ksh8281) : consider RTL(right-to-left) culture
match (style.PositionOffsets.left, style.PositionOffsets.right) {
(LPA_Auto, _) => {
-MaybeAuto::from_style(style.PositionOffsets.right, block_width)
.specified_or_zero()
}
(_, _) => {
MaybeAuto::from_style(style.PositionOffsets.left, block_width)
.specified_or_zero()
}
}
}
fn top_bottom(style: &ComputedValues,block_height: Au) -> Au {
match (style.PositionOffsets.top, style.PositionOffsets.bottom) {
(LPA_Auto, _) => {
-MaybeAuto::from_style(style.PositionOffsets.bottom, block_height)
.specified_or_zero()
}
(_, _) => {
MaybeAuto::from_style(style.PositionOffsets.top, block_height)
.specified_or_zero()
}
}
}
let mut rel_pos: Point2D<Au> = Point2D {
x: Au::new(0),
y: Au::new(0),
};
if self.style().Box.position == position::relative {
rel_pos.x = rel_pos.x + left_right(self.style(), container_block_size.width);
rel_pos.y = rel_pos.y + top_bottom(self.style(), container_block_size.height);
}
let info = self.inline_info.borrow();
match info.get() {
&Some(ref info) => {
for info in info.parent_info.iter() {
if info.style.get().Box.position == position::relative {
rel_pos.x = rel_pos.x + left_right(info.style.get(), container_block_size.width);
rel_pos.y = rel_pos.y + top_bottom(info.style.get(), container_block_size.height);
}
}
},
&None => {}
}
rel_pos
}
/// Always inline for SCCP.
///
/// FIXME(pcwalton): Just replace with the clear type from the style module for speed?

View file

@ -40,6 +40,7 @@ use layout::wrapper::ThreadSafeLayoutNode;
use extra::dlist::{DList, DListIterator, MutDListIterator};
use extra::container::Deque;
use geom::point::Point2D;
use geom::Size2D;
use geom::rect::Rect;
use gfx::display_list::{ClipDisplayItemClass, DisplayListCollection, DisplayList};
use layout::display_list_builder::ToGfxColor;
@ -207,6 +208,7 @@ pub trait MutableFlowUtils {
fn build_display_lists<E:ExtraDisplayListData>(
self,
builder: &DisplayListBuilder,
container_block_size: &Size2D<Au>,
dirty: &Rect<Au>,
index: uint,
mut list: &RefCell<DisplayListCollection<E>>)
@ -726,14 +728,15 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
fn build_display_lists<E:ExtraDisplayListData>(
self,
builder: &DisplayListBuilder,
container_block_size: &Size2D<Au>,
dirty: &Rect<Au>,
mut index: uint,
lists: &RefCell<DisplayListCollection<E>>)
-> bool {
debug!("Flow: building display list for f{}", base(self).id);
index = match self.class() {
BlockFlowClass => self.as_block().build_display_list_block(builder, dirty, index, lists),
InlineFlowClass => self.as_inline().build_display_list_inline(builder, dirty, index, lists),
BlockFlowClass => self.as_block().build_display_list_block(builder, container_block_size, dirty, index, lists),
InlineFlowClass => self.as_inline().build_display_list_inline(builder, container_block_size, dirty, index, lists),
};
if lists.with_mut(|lists| lists.lists[index].list.len() == 0) {
@ -744,8 +747,21 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
let mut child_lists = DisplayListCollection::new();
child_lists.add_list(DisplayList::new());
let child_lists = RefCell::new(child_lists);
let container_block_size = match self.class() {
BlockFlowClass => {
if self.as_block().box_.is_some() {
self.as_block().box_.get_ref().position.get().size
} else {
base(self).position.size
}
},
_ => {
base(self).position.size
}
};
for kid in child_iter(self) {
kid.build_display_lists(builder, dirty, 0u, &child_lists);
kid.build_display_lists(builder, &container_block_size, dirty, 0u, &child_lists);
}
let mut child_lists = Some(child_lists.unwrap());

View file

@ -494,6 +494,7 @@ impl InlineFlow {
pub fn build_display_list_inline<E:ExtraDisplayListData>(
&self,
builder: &DisplayListBuilder,
container_block_size: &Size2D<Au>,
dirty: &Rect<Au>,
index: uint,
lists: &RefCell<DisplayListCollection<E>>)
@ -510,7 +511,8 @@ impl InlineFlow {
self.boxes.len());
for box_ in self.boxes.iter() {
box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, index, lists);
let rel_offset: Point2D<Au> = box_.relative_position(container_block_size);
box_.build_display_list(builder, dirty, self.base.abs_position + rel_offset, (&*self) as &Flow, index, lists);
}
// TODO(#225): Should `inline-block` elements have flows as children of the inline flow or

View file

@ -615,7 +615,7 @@ impl LayoutTask {
let display_list_builder = DisplayListBuilder {
ctx: &layout_ctx,
};
layout_root.build_display_lists(&display_list_builder, &dirty, 0u, display_list_collection);
layout_root.build_display_lists(&display_list_builder, &root_size, &dirty, 0u, display_list_collection);
let display_list_collection = Arc::new(display_list_collection.unwrap());

View file

@ -26,3 +26,4 @@
== upper_id_attr.html upper_id_attr_ref.html
# inline_border_a.html inline_border_b.html
== anon_block_inherit_a.html anon_block_inherit_b.html
== position_relative_a.html position_relative_b.html

View file

@ -16,7 +16,7 @@ body {
</style>
</head>
<body>
<span style="border: 10px black solid"><img width="100" style="border:10px red solid" src="inline_border.jpeg"></span>
<span style="border: 10px black solid"><img width="100" style="border:10px red solid" src="test.jpeg"></span>
</body>
</html>

View file

@ -0,0 +1,17 @@
<html>
<head>
<title>
today, weather is very cold.....
</title>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<div style="width:500px;height:200px;position:relative;left:100px;top:100px" >
<img src="test.jpeg" style="width:100px;height:100px;"/><span style="position:relative;left:-200px;top:-100px"><img src="test.jpeg" style="position:relative;left:100px;top:100px;width:100px;height:100px"/></span></div>
</body>
</html>

View file

@ -0,0 +1,18 @@
<html>
<head>
<title>
today, weather is very cold.....
</title>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<div style="width:500px;height:200px;margin-left:100px;margin-top:100px" >
<img src="test.jpeg" style="width:100px;height:100px;"/>
</div>
</body>
</html>

View file

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Before After
Before After