mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
auto merge of #1298 : recrack/servo/overflow_property, r=metajack
Impl #1290 @jaeminMoon @ksh8281 Thanks @metajack
This commit is contained in:
commit
b867e54dd4
8 changed files with 232 additions and 101 deletions
|
@ -64,6 +64,7 @@ pub enum DisplayItem<E> {
|
||||||
TextDisplayItemClass(~TextDisplayItem<E>),
|
TextDisplayItemClass(~TextDisplayItem<E>),
|
||||||
ImageDisplayItemClass(~ImageDisplayItem<E>),
|
ImageDisplayItemClass(~ImageDisplayItem<E>),
|
||||||
BorderDisplayItemClass(~BorderDisplayItem<E>),
|
BorderDisplayItemClass(~BorderDisplayItem<E>),
|
||||||
|
ClipDisplayItemClass(~ClipDisplayItem<E>)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information common to all display items.
|
/// Information common to all display items.
|
||||||
|
@ -111,6 +112,12 @@ pub struct BorderDisplayItem<E> {
|
||||||
style: SideOffsets2D<border_style::T>
|
style: SideOffsets2D<border_style::T>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ClipDisplayItem<E> {
|
||||||
|
base: BaseDisplayItem<E>,
|
||||||
|
child_list: ~[DisplayItem<E>],
|
||||||
|
need_clip: bool
|
||||||
|
}
|
||||||
|
|
||||||
impl<E> DisplayItem<E> {
|
impl<E> DisplayItem<E> {
|
||||||
/// Renders this display item into the given render context.
|
/// Renders this display item into the given render context.
|
||||||
fn draw_into_context(&self, render_context: &RenderContext) {
|
fn draw_into_context(&self, render_context: &RenderContext) {
|
||||||
|
@ -119,6 +126,18 @@ impl<E> DisplayItem<E> {
|
||||||
render_context.draw_solid_color(&solid_color.base.bounds, solid_color.color)
|
render_context.draw_solid_color(&solid_color.base.bounds, solid_color.color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClipDisplayItemClass(ref clip) => {
|
||||||
|
if clip.need_clip {
|
||||||
|
render_context.draw_push_clip(&clip.base.bounds);
|
||||||
|
}
|
||||||
|
for item in clip.child_list.iter() {
|
||||||
|
(*item).draw_into_context(render_context);
|
||||||
|
}
|
||||||
|
if clip.need_clip {
|
||||||
|
render_context.draw_pop_clip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TextDisplayItemClass(ref text) => {
|
TextDisplayItemClass(ref text) => {
|
||||||
debug!("Drawing text at {:?}.", text.base.bounds);
|
debug!("Drawing text at {:?}.", text.base.bounds);
|
||||||
|
|
||||||
|
@ -182,7 +201,8 @@ impl<E> DisplayItem<E> {
|
||||||
SolidColorDisplayItemClass(ref solid_color) => transmute_region(&solid_color.base),
|
SolidColorDisplayItemClass(ref solid_color) => transmute_region(&solid_color.base),
|
||||||
TextDisplayItemClass(ref text) => transmute_region(&text.base),
|
TextDisplayItemClass(ref text) => transmute_region(&text.base),
|
||||||
ImageDisplayItemClass(ref image_item) => transmute_region(&image_item.base),
|
ImageDisplayItemClass(ref image_item) => transmute_region(&image_item.base),
|
||||||
BorderDisplayItemClass(ref border) => transmute_region(&border.base)
|
BorderDisplayItemClass(ref border) => transmute_region(&border.base),
|
||||||
|
ClipDisplayItemClass(ref clip) => transmute_region(&clip.base),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
src/components/gfx/render_context.rs
Normal file → Executable file
22
src/components/gfx/render_context.rs
Normal file → Executable file
|
@ -101,6 +101,28 @@ impl<'self> RenderContext<'self> {
|
||||||
&draw_opts);
|
&draw_opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn draw_push_clip(&self, bounds: &Rect<Au>) {
|
||||||
|
let rect = bounds.to_azure_rect();
|
||||||
|
let path_builder = self.draw_target.create_path_builder();
|
||||||
|
|
||||||
|
let left_top = Point2D(rect.origin.x, rect.origin.y);
|
||||||
|
let right_top = Point2D(rect.origin.x + rect.size.width, rect.origin.y);
|
||||||
|
let left_bottom = Point2D(rect.origin.x, rect.origin.y + rect.size.height);
|
||||||
|
let right_bottom = Point2D(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
|
||||||
|
|
||||||
|
path_builder.move_to(left_top);
|
||||||
|
path_builder.line_to(right_top);
|
||||||
|
path_builder.line_to(right_bottom);
|
||||||
|
path_builder.line_to(left_bottom);
|
||||||
|
|
||||||
|
let path = path_builder.finish();
|
||||||
|
self.draw_target.push_clip(&path);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_pop_clip(&self) {
|
||||||
|
self.draw_target.pop_clip();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw_image(&self, bounds: Rect<Au>, image: Arc<~Image>) {
|
pub fn draw_image(&self, bounds: Rect<Au>, image: Arc<~Image>) {
|
||||||
let image = image.get();
|
let image = image.get();
|
||||||
let size = Size2D(image.width as i32, image.height as i32);
|
let size = Size2D(image.width as i32, image.height as i32);
|
||||||
|
|
|
@ -9,7 +9,7 @@ use geom::{Point2D, Rect, Size2D, SideOffsets2D};
|
||||||
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};
|
||||||
use gfx::display_list::{SolidColorDisplayItem, SolidColorDisplayItemClass, TextDisplayItem};
|
use gfx::display_list::{SolidColorDisplayItem, SolidColorDisplayItemClass, TextDisplayItem};
|
||||||
use gfx::display_list::{TextDisplayItemClass};
|
use gfx::display_list::{TextDisplayItemClass, ClipDisplayItem, ClipDisplayItemClass};
|
||||||
use gfx::font::{FontStyle, FontWeight300};
|
use gfx::font::{FontStyle, FontWeight300};
|
||||||
use gfx::text::text_run::TextRun;
|
use gfx::text::text_run::TextRun;
|
||||||
use gfx::color::rgb;
|
use gfx::color::rgb;
|
||||||
|
@ -28,7 +28,7 @@ use std::unstable::raw::Box;
|
||||||
use style::ComputedValues;
|
use style::ComputedValues;
|
||||||
use style::computed_values::{
|
use style::computed_values::{
|
||||||
border_style, clear, float, font_family, font_style, line_height,
|
border_style, clear, float, font_family, font_style, line_height,
|
||||||
position, text_align, text_decoration, vertical_align, LengthOrPercentage};
|
position, text_align, text_decoration, vertical_align, LengthOrPercentage, overflow};
|
||||||
|
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToGfxColor};
|
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToGfxColor};
|
||||||
|
@ -78,6 +78,13 @@ pub trait RenderBox {
|
||||||
fail!("as_unscanned_text_render_box() called on a non-unscanned-text-render-box")
|
fail!("as_unscanned_text_render_box() called on a non-unscanned-text-render-box")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this is an unscanned text render box, returns the underlying object. Fails otherwise.
|
||||||
|
///
|
||||||
|
/// FIXME(pcwalton): Ugly. Replace with a real downcast operation.
|
||||||
|
fn as_generic_render_box(@self) -> @GenericRenderBox {
|
||||||
|
fail!("as_generic_render_box() called on a generic-render-box")
|
||||||
|
}
|
||||||
|
|
||||||
/// Cleans up all memory associated with this render box.
|
/// Cleans up all memory associated with this render box.
|
||||||
fn teardown(&self) {}
|
fn teardown(&self) {}
|
||||||
|
|
||||||
|
@ -188,6 +195,13 @@ impl GenericRenderBox {
|
||||||
base: base,
|
base: base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn need_clip(&self) -> bool {
|
||||||
|
if self.base.node.style().Box.overflow == overflow::hidden {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderBox for GenericRenderBox {
|
impl RenderBox for GenericRenderBox {
|
||||||
|
@ -195,6 +209,10 @@ impl RenderBox for GenericRenderBox {
|
||||||
GenericRenderBoxClass
|
GenericRenderBoxClass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_generic_render_box(@self) -> @GenericRenderBox {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn minimum_and_preferred_widths(&self) -> (Au, Au) {
|
fn minimum_and_preferred_widths(&self) -> (Au, Au) {
|
||||||
let guessed_width = self.base.guess_width();
|
let guessed_width = self.base.guess_width();
|
||||||
(guessed_width, guessed_width)
|
(guessed_width, guessed_width)
|
||||||
|
@ -1029,6 +1047,19 @@ impl RenderBoxUtils for @RenderBox {
|
||||||
// Add the background to the list, if applicable.
|
// Add the background to the list, if applicable.
|
||||||
self.paint_background_if_applicable(list, &absolute_box_bounds);
|
self.paint_background_if_applicable(list, &absolute_box_bounds);
|
||||||
|
|
||||||
|
do list.with_mut_ref |list| {
|
||||||
|
let item = ~ClipDisplayItem {
|
||||||
|
base: BaseDisplayItem {
|
||||||
|
bounds: absolute_box_bounds,
|
||||||
|
extra: ExtraDisplayListData::new(self),
|
||||||
|
},
|
||||||
|
child_list: ~[],
|
||||||
|
need_clip: false
|
||||||
|
};
|
||||||
|
list.append_item(ClipDisplayItemClass(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let nearest_ancestor_element = base.nearest_ancestor_element();
|
let nearest_ancestor_element = base.nearest_ancestor_element();
|
||||||
let color = nearest_ancestor_element.style().Color.color.to_gfx_color();
|
let color = nearest_ancestor_element.style().Color.color.to_gfx_color();
|
||||||
|
|
||||||
|
@ -1099,6 +1130,19 @@ impl RenderBoxUtils for @RenderBox {
|
||||||
// Add the background to the list, if applicable.
|
// Add the background to the list, if applicable.
|
||||||
self.paint_background_if_applicable(list, &absolute_box_bounds);
|
self.paint_background_if_applicable(list, &absolute_box_bounds);
|
||||||
|
|
||||||
|
let generic_box = self.as_generic_render_box();
|
||||||
|
do list.with_mut_ref |list| {
|
||||||
|
let item = ~ClipDisplayItem {
|
||||||
|
base: BaseDisplayItem {
|
||||||
|
bounds: absolute_box_bounds,
|
||||||
|
extra: ExtraDisplayListData::new(self),
|
||||||
|
},
|
||||||
|
child_list: ~[],
|
||||||
|
need_clip: generic_box.need_clip()
|
||||||
|
};
|
||||||
|
list.append_item(ClipDisplayItemClass(item));
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We
|
// FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We
|
||||||
// should have a real `SERVO_DEBUG` system.
|
// should have a real `SERVO_DEBUG` system.
|
||||||
debug!("{:?}", {
|
debug!("{:?}", {
|
||||||
|
@ -1122,11 +1166,23 @@ impl RenderBoxUtils for @RenderBox {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
ImageRenderBoxClass => {
|
ImageRenderBoxClass => {
|
||||||
let image_box = self.as_image_render_box();
|
|
||||||
|
|
||||||
// Add the background to the list, if applicable.
|
// Add the background to the list, if applicable.
|
||||||
self.paint_background_if_applicable(list, &absolute_box_bounds);
|
self.paint_background_if_applicable(list, &absolute_box_bounds);
|
||||||
|
|
||||||
|
do list.with_mut_ref |list| {
|
||||||
|
let item = ~ClipDisplayItem {
|
||||||
|
base: BaseDisplayItem {
|
||||||
|
bounds: absolute_box_bounds,
|
||||||
|
extra: ExtraDisplayListData::new(self),
|
||||||
|
},
|
||||||
|
child_list: ~[],
|
||||||
|
need_clip: false
|
||||||
|
};
|
||||||
|
list.append_item(ClipDisplayItemClass(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
let image_box = self.as_image_render_box();
|
||||||
|
|
||||||
match image_box.image.mutate().ptr.get_image() {
|
match image_box.image.mutate().ptr.get_image() {
|
||||||
Some(image) => {
|
Some(image) => {
|
||||||
debug!("(building display list) building image box");
|
debug!("(building display list) building image box");
|
||||||
|
|
|
@ -34,6 +34,7 @@ use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
||||||
use layout::float_context::{FloatContext, Invalid};
|
use layout::float_context::{FloatContext, Invalid};
|
||||||
use layout::incremental::RestyleDamage;
|
use layout::incremental::RestyleDamage;
|
||||||
use layout::inline::InlineFlow;
|
use layout::inline::InlineFlow;
|
||||||
|
use gfx::display_list::{ClipDisplayItemClass};
|
||||||
|
|
||||||
use extra::dlist::{DList, DListIterator, MutDListIterator};
|
use extra::dlist::{DList, DListIterator, MutDListIterator};
|
||||||
use extra::container::Deque;
|
use extra::container::Deque;
|
||||||
|
@ -526,7 +527,34 @@ impl<'self> MutableFlowUtils for &'self mut FlowContext {
|
||||||
InlineFlowClass => self.as_inline().build_display_list_inline(builder, dirty, list),
|
InlineFlowClass => self.as_inline().build_display_list_inline(builder, dirty, list),
|
||||||
FloatFlowClass => self.as_float().build_display_list_float(builder, dirty, list),
|
FloatFlowClass => self.as_float().build_display_list_float(builder, dirty, list),
|
||||||
_ => fail!("Tried to build_display_list_recurse of flow: {:?}", self),
|
_ => fail!("Tried to build_display_list_recurse of flow: {:?}", self),
|
||||||
|
};
|
||||||
|
|
||||||
|
if list.with_mut_ref(|list| list.list.len() == 0) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let child_list = ~Cell::new(DisplayList::new());
|
||||||
|
for kid in child_iter(self) {
|
||||||
|
kid.build_display_list(builder,dirty,child_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
do list.with_mut_ref |list| {
|
||||||
|
let result = list.list.mut_rev_iter().position(|item| {
|
||||||
|
match *item {
|
||||||
|
ClipDisplayItemClass(ref mut item) => {
|
||||||
|
item.child_list.push_all_move(child_list.take().list);
|
||||||
|
true
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if result.is_none() {
|
||||||
|
fail!("fail to find parent item");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ use extra::arc::{Arc, RWArc};
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::{DisplayList,DisplayItem,ClipDisplayItemClass};
|
||||||
use gfx::font_context::FontContext;
|
use gfx::font_context::FontContext;
|
||||||
use gfx::opts::Opts;
|
use gfx::opts::Opts;
|
||||||
use gfx::render_task::{RenderMsg, RenderChan, RenderLayer};
|
use gfx::render_task::{RenderMsg, RenderChan, RenderLayer};
|
||||||
|
@ -41,7 +41,6 @@ use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
|
||||||
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
|
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
|
||||||
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
|
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::range::Range;
|
|
||||||
use servo_util::time::{ProfilerChan, profile};
|
use servo_util::time::{ProfilerChan, profile};
|
||||||
use servo_util::time;
|
use servo_util::time;
|
||||||
use servo_util::tree::TreeNodeRef;
|
use servo_util::tree::TreeNodeRef;
|
||||||
|
@ -181,26 +180,6 @@ impl<'self> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The display list building traversal. In WebKit this corresponds to `paint`. In Gecko this
|
|
||||||
/// corresponds to `BuildDisplayListForChild`.
|
|
||||||
struct DisplayListBuildingTraversal<'self> {
|
|
||||||
builder: DisplayListBuilder<'self>,
|
|
||||||
root_pos: Rect<Au>,
|
|
||||||
display_list: ~Cell<DisplayList<AbstractNode<()>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'self> PreorderFlowTraversal for DisplayListBuildingTraversal<'self> {
|
|
||||||
#[inline]
|
|
||||||
fn process(&mut self, _: &mut FlowContext) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn should_prune(&mut self, flow: &mut FlowContext) -> bool {
|
|
||||||
flow.build_display_list(&self.builder, &self.root_pos, self.display_list)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LayoutImageResponder {
|
struct LayoutImageResponder {
|
||||||
id: PipelineId,
|
id: PipelineId,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
|
@ -472,49 +451,20 @@ impl LayoutTask {
|
||||||
// Build the display list if necessary, and send it to the renderer.
|
// Build the display list if necessary, and send it to the renderer.
|
||||||
if data.goal == ReflowForDisplay {
|
if data.goal == ReflowForDisplay {
|
||||||
do profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone()) {
|
do profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone()) {
|
||||||
// TODO: Set options on the builder before building.
|
let root_size = flow::base(layout_root).position.size;
|
||||||
// TODO: Be smarter about what needs painting.
|
let display_list= ~Cell::new(DisplayList::<AbstractNode<()>>::new());
|
||||||
let mut traversal = DisplayListBuildingTraversal {
|
let dirty = flow::base(layout_root).position.clone();
|
||||||
builder: DisplayListBuilder {
|
layout_root.build_display_list(
|
||||||
|
&DisplayListBuilder {
|
||||||
ctx: &layout_ctx,
|
ctx: &layout_ctx,
|
||||||
},
|
},
|
||||||
root_pos: flow::base(layout_root).position.clone(),
|
&dirty,
|
||||||
display_list: ~Cell::new(DisplayList::<AbstractNode<()>>::new()),
|
display_list);
|
||||||
};
|
|
||||||
|
|
||||||
let _ = layout_root.traverse_preorder(&mut traversal);
|
let display_list = Arc::new(display_list.take());
|
||||||
|
|
||||||
let root_size = flow::base(layout_root).position.size;
|
|
||||||
|
|
||||||
let display_list = Arc::new(traversal.display_list.take());
|
|
||||||
|
|
||||||
for i in range(0,display_list.get().list.len()) {
|
for i in range(0,display_list.get().list.len()) {
|
||||||
let node: AbstractNode<LayoutView> = unsafe {
|
self.display_item_bound_to_node(&display_list.get().list[i]);
|
||||||
transmute(display_list.get().list[i].base().extra)
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME(pcwalton): Why are we cloning the display list here?!
|
|
||||||
match *node.mutate_layout_data().ptr {
|
|
||||||
Some(ref mut layout_data) => {
|
|
||||||
let boxes = &mut layout_data.boxes;
|
|
||||||
boxes.display_list = Some(display_list.clone());
|
|
||||||
|
|
||||||
if boxes.range.is_none() {
|
|
||||||
debug!("Creating initial range for node");
|
|
||||||
boxes.range = Some(Range::new(i,1));
|
|
||||||
} else {
|
|
||||||
debug!("Appending item to range");
|
|
||||||
unsafe {
|
|
||||||
let old_node: AbstractNode<()> = transmute(node);
|
|
||||||
assert!(old_node == display_list.get().list[i-1].base().extra,
|
|
||||||
"Non-contiguous arrangement of display items");
|
|
||||||
}
|
|
||||||
|
|
||||||
boxes.range.unwrap().extend_by(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => fail!("no layout data"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut color = color::rgba(255.0, 255.0, 255.0, 255.0);
|
let mut color = color::rgba(255.0, 255.0, 255.0, 255.0);
|
||||||
|
@ -556,6 +506,42 @@ impl LayoutTask {
|
||||||
data.script_chan.send(ReflowCompleteMsg(self.id, data.id));
|
data.script_chan.send(ReflowCompleteMsg(self.id, data.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn display_item_bound_to_node(&mut self,item: &DisplayItem<AbstractNode<()>>) {
|
||||||
|
let node: AbstractNode<LayoutView> = unsafe {
|
||||||
|
transmute(item.base().extra)
|
||||||
|
};
|
||||||
|
|
||||||
|
match *node.mutate_layout_data().ptr {
|
||||||
|
Some(ref mut layout_data) => {
|
||||||
|
let boxes = &mut layout_data.boxes;
|
||||||
|
|
||||||
|
if boxes.display_bound_list.is_none() {
|
||||||
|
boxes.display_bound_list = Some(~[]);
|
||||||
|
}
|
||||||
|
match boxes.display_bound_list {
|
||||||
|
Some(ref mut list) => list.push(item.base().bounds),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if boxes.display_bound.is_none() {
|
||||||
|
boxes.display_bound = Some(item.base().bounds);
|
||||||
|
} else {
|
||||||
|
boxes.display_bound = Some(boxes.display_bound.unwrap().union(&item.base().bounds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => fail!("no layout data"),
|
||||||
|
}
|
||||||
|
|
||||||
|
match *item {
|
||||||
|
ClipDisplayItemClass(ref cc) => {
|
||||||
|
for item in cc.child_list.iter() {
|
||||||
|
self.display_item_bound_to_node(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handles a query from the script task. This is the main routine that DOM functions like
|
/// Handles a query from the script task. This is the main routine that DOM functions like
|
||||||
/// `getClientRects()` or `getBoundingClientRect()` ultimately invoke.
|
/// `getClientRects()` or `getBoundingClientRect()` ultimately invoke.
|
||||||
fn handle_query(&self, query: LayoutQuery) {
|
fn handle_query(&self, query: LayoutQuery) {
|
||||||
|
@ -570,19 +556,8 @@ impl LayoutTask {
|
||||||
// FIXME(pcwalton): Why are we cloning the display list here?!
|
// FIXME(pcwalton): Why are we cloning the display list here?!
|
||||||
let layout_data = node.borrow_layout_data();
|
let layout_data = node.borrow_layout_data();
|
||||||
let boxes = &layout_data.ptr.as_ref().unwrap().boxes;
|
let boxes = &layout_data.ptr.as_ref().unwrap().boxes;
|
||||||
match (boxes.display_list.clone(), boxes.range) {
|
match boxes.display_bound {
|
||||||
(Some(display_list), Some(range)) => {
|
Some(_) => boxes.display_bound,
|
||||||
let mut rect: Option<Rect<Au>> = None;
|
|
||||||
for i in range.eachi() {
|
|
||||||
rect = match rect {
|
|
||||||
Some(acc) => {
|
|
||||||
Some(acc.union(&display_list.get().list[i].bounds()))
|
|
||||||
}
|
|
||||||
None => Some(display_list.get().list[i].bounds())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rect
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
let mut acc: Option<Rect<Au>> = None;
|
let mut acc: Option<Rect<Au>> = None;
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
|
@ -614,10 +589,10 @@ impl LayoutTask {
|
||||||
-> ~[Rect<Au>] {
|
-> ~[Rect<Au>] {
|
||||||
let layout_data = node.borrow_layout_data();
|
let layout_data = node.borrow_layout_data();
|
||||||
let boxes = &layout_data.ptr.as_ref().unwrap().boxes;
|
let boxes = &layout_data.ptr.as_ref().unwrap().boxes;
|
||||||
match (boxes.display_list.clone(), boxes.range) {
|
match boxes.display_bound_list {
|
||||||
(Some(display_list), Some(range)) => {
|
Some(ref display_bound_list) => {
|
||||||
for i in range.eachi() {
|
for item in display_bound_list.iter() {
|
||||||
box_accumulator.push(display_list.get().list[i].bounds());
|
box_accumulator.push(*item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -634,29 +609,54 @@ impl LayoutTask {
|
||||||
reply_chan.send(ContentBoxesResponse(boxes))
|
reply_chan.send(ContentBoxesResponse(boxes))
|
||||||
}
|
}
|
||||||
HitTestQuery(_, point, reply_chan) => {
|
HitTestQuery(_, point, reply_chan) => {
|
||||||
|
fn hit_test(x:Au, y:Au, list: &[DisplayItem<AbstractNode<()>>]) -> Option<HitTestResponse> {
|
||||||
|
|
||||||
|
for item in list.rev_iter() {
|
||||||
|
match *item {
|
||||||
|
ClipDisplayItemClass(ref cc) => {
|
||||||
|
let ret = hit_test(x, y, cc.child_list);
|
||||||
|
if !ret.is_none() {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for item in list.rev_iter() {
|
||||||
|
match *item {
|
||||||
|
ClipDisplayItemClass(_) => continue,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let bounds = item.bounds();
|
||||||
|
// TODO this check should really be performed by a method of DisplayItem
|
||||||
|
if x < bounds.origin.x + bounds.size.width &&
|
||||||
|
bounds.origin.x <= x &&
|
||||||
|
y < bounds.origin.y + bounds.size.height &&
|
||||||
|
bounds.origin.y <= y {
|
||||||
|
let node: AbstractNode<LayoutView> = unsafe {
|
||||||
|
transmute(item.base().extra)
|
||||||
|
};
|
||||||
|
let resp = Some(HitTestResponse(node));
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret: Option<HitTestResponse> = None;
|
||||||
|
ret
|
||||||
|
}
|
||||||
let response = {
|
let response = {
|
||||||
match self.display_list {
|
match self.display_list {
|
||||||
Some(ref list) => {
|
Some(ref list) => {
|
||||||
let display_list = list.get();
|
let display_list = list.get();
|
||||||
let (x, y) = (Au::from_frac_px(point.x as f64),
|
let (x, y) = (Au::from_frac_px(point.x as f64),
|
||||||
Au::from_frac_px(point.y as f64));
|
Au::from_frac_px(point.y as f64));
|
||||||
let mut resp = Err(());
|
let resp = hit_test(x,y,display_list.list);
|
||||||
// iterate in reverse to ensure we have the most recently painted render box
|
if resp.is_none() {
|
||||||
for display_item in display_list.list.rev_iter() {
|
Err(())
|
||||||
let bounds = display_item.bounds();
|
} else {
|
||||||
// TODO this check should really be performed by a method of DisplayItem
|
Ok(resp.unwrap())
|
||||||
if x <= bounds.origin.x + bounds.size.width &&
|
|
||||||
bounds.origin.x <= x &&
|
|
||||||
y < bounds.origin.y + bounds.size.height &&
|
|
||||||
bounds.origin.y < y {
|
|
||||||
let node: AbstractNode<LayoutView> = unsafe {
|
|
||||||
transmute(display_item.base().extra)
|
|
||||||
};
|
|
||||||
resp = Ok(HitTestResponse(node));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
resp
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
error!("Can't hit test: no display list");
|
error!("Can't hit test: no display list");
|
||||||
|
|
|
@ -15,18 +15,22 @@ use std::cast;
|
||||||
use std::iter::Enumerate;
|
use std::iter::Enumerate;
|
||||||
use std::vec::VecIterator;
|
use std::vec::VecIterator;
|
||||||
use style::{ComputedValues, PropertyDeclaration};
|
use style::{ComputedValues, PropertyDeclaration};
|
||||||
|
use geom::rect::Rect;
|
||||||
|
use servo_util::geometry::Au;
|
||||||
|
|
||||||
/// The boxes associated with a node.
|
/// The boxes associated with a node.
|
||||||
pub struct DisplayBoxes {
|
pub struct DisplayBoxes {
|
||||||
display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
|
display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
|
||||||
range: Option<Range>,
|
display_bound_list: Option<~[Rect<Au>]>,
|
||||||
|
display_bound: Option<Rect<Au>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayBoxes {
|
impl DisplayBoxes {
|
||||||
pub fn init() -> DisplayBoxes {
|
pub fn init() -> DisplayBoxes {
|
||||||
DisplayBoxes {
|
DisplayBoxes {
|
||||||
display_list: None,
|
display_list: None,
|
||||||
range: None,
|
display_bound_list: None,
|
||||||
|
display_bound: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,6 +371,7 @@ pub mod longhands {
|
||||||
|
|
||||||
|
|
||||||
// CSS 2.1, Section 11 - Visual effects
|
// CSS 2.1, Section 11 - Visual effects
|
||||||
|
${single_keyword("overflow", "visible hidden", inherited=False)} // TODO: scroll auto
|
||||||
|
|
||||||
// CSS 2.1, Section 12 - Generated content, automatic numbering, and lists
|
// CSS 2.1, Section 12 - Generated content, automatic numbering, and lists
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 13fbdbeddfccbc3e451fa9ae47f334f4f626a051
|
Subproject commit 60ee86c802f45a8e87fa462cd21d4b074f837cec
|
Loading…
Add table
Add a link
Reference in a new issue