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

Implement Box-model Computations #507

Closed
wants to merge 26 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
09292be
Update rust-geom
pcwalton May 29, 2013
11efed6
Implement the beginnings of the box model for render boxes
pcwalton May 29, 2013
43c83d2
Add horizontal borders, margins and padding. Broken until rust-css su…
May 30, 2013
c14a137
Update rust-geom
pcwalton May 29, 2013
233a204
Implement the beginnings of the box model for render boxes
pcwalton May 29, 2013
a1d1289
Add NSPR and NSS submodules
pcwalton May 29, 2013
0af3bbf
Add NSS and NSPR to the build
pcwalton May 29, 2013
2d1a00c
Don't clip layers to the screen area
pcwalton May 29, 2013
67eb533
Clamp scrolling to the page boundaries
pcwalton May 29, 2013
d97f002
Stop hammering on the compositor
pcwalton May 29, 2013
02c5772
Fix corrupted textures when resizing.
pcwalton May 30, 2013
dcfabb7
Don't try to remove whitespace twice if it's the only node.
pcwalton May 30, 2013
e2bcd36
Color links blue
pcwalton May 30, 2013
b6dd3f6
Refactor a bit and compute vertical margins as well.
May 30, 2013
2e4cecc
Add flows if requested to the display list info.
pcwalton May 30, 2013
25fb1e5
Add comments and compute heights properly
May 30, 2013
ea1a406
base and bounds methods for DisplayItem
May 25, 2013
f77eef5
Basic hit testing functionality
pcwalton May 31, 2013
facb707
Update rust-css and rust-netsurfcss
pcwalton May 31, 2013
d5e4793
Add horizontal borders, margins and padding. Broken until rust-css su…
May 30, 2013
4a2171c
Update border rendering
May 31, 2013
708f9b4
Fix method names and dynamic borrow check failures
pcwalton May 31, 2013
e3290a3
Merge
May 31, 2013
d6a9bc7
Fix merge problems
May 31, 2013
ff8d33e
Fix borrow-check and repo errors.
Jun 3, 2013
3e80e97
Compute percent widths/margins properly and fix numerous small visual…
Jun 4, 2013
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Basic hit testing functionality

  • Loading branch information
pcwalton committed May 31, 2013
commit f77eef59883dcb96f99c5633b1cca7a8df545159
@@ -28,7 +28,7 @@ use std::arc;

/// A list of rendering operations to be performed.
pub struct DisplayList<E> {
priv list: ~[DisplayItem<E>]
list: ~[DisplayItem<E>]
}

impl<E> DisplayList<E> {
@@ -4,8 +4,9 @@

use compositing::resize_rate_limiter::ResizeRateLimiter;
use platform::{Application, Window};
use script::script_task::{LoadMsg, ScriptMsg};
use script::script_task::{LoadMsg, ScriptMsg, SendEventMsg};
use windowing::{ApplicationMethods, WindowMethods};
use script::dom::event::ClickEvent;

use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods};
use core::cell::Cell;
@@ -222,10 +223,22 @@ fn run_main_loop(port: Port<Msg>,
resize_rate_limiter.window_resized(width, height)
}

let script_chan_clone = script_chan.clone();

// When the user enters a new URL, load it.
do window.set_load_url_callback |url_string| {
debug!("osmain: loading URL `%s`", url_string);
script_chan.send(LoadMsg(url::make_url(url_string.to_str(), None)))
script_chan_clone.send(LoadMsg(url::make_url(url_string.to_str(), None)))
}

let script_chan_clone = script_chan.clone();

// When the user clicks, perform hit testing
do window.set_click_callback |layer_click_point| {
let world_click_point = layer_click_point + *world_offset;
debug!("osmain: clicked at %?", world_click_point);

script_chan_clone.send(SendEventMsg(ClickEvent(world_click_point)));
}

// When the user scrolls, move the layer around.
@@ -8,6 +8,7 @@
use css::matching::MatchMethods;
use css::select::new_css_select_ctx;
use layout::aux::{LayoutData, LayoutAuxMethods};
use layout::box::RenderBox;
use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods};
@@ -32,15 +33,17 @@ use newcss::types::OriginAuthor;
use script::dom::event::ReflowEvent;
use script::dom::node::{AbstractNode, LayoutView};
use script::layout_interface::{AddStylesheetMsg, BuildData, BuildMsg, ContentBoxQuery};
use script::layout_interface::{ContentBoxResponse, ContentBoxesQuery, ContentBoxesResponse};
use script::layout_interface::{ExitMsg, LayoutQuery, LayoutResponse, LayoutTask};
use script::layout_interface::{MatchSelectorsDamage, Msg, NoDamage, QueryMsg, ReflowDamage};
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
use script::layout_interface::{LayoutResponse, LayoutTask, MatchSelectorsDamage, Msg, NoDamage};
use script::layout_interface::{QueryMsg, ReflowDamage};
use script::script_task::{ScriptMsg, SendEventMsg};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::LocalImageCache;
use servo_util::tree::{TreeNodeRef, TreeUtils};
use servo_util::time::{ProfilerChan, profile, time};
use servo_util::time;
use std::net::url::Url;

pub fn create_layout_task(render_task: RenderTask,
img_cache_task: ImageCacheTask,
@@ -67,6 +70,8 @@ struct Layout {
local_image_cache: @mut LocalImageCache,
from_script: Port<Msg>,
font_ctx: @mut FontContext,
doc_url: Option<Url>,
screen_size: Option<Size2D<Au>>,

/// This is used to root reader data.
layout_refs: ~[@mut LayoutData],
@@ -90,6 +95,9 @@ impl Layout {
local_image_cache: @mut LocalImageCache(image_cache_task),
from_script: from_script,
font_ctx: fctx,
doc_url: None,
screen_size: None,

layout_refs: ~[],
css_select_ctx: @mut new_css_select_ctx(),
profiler_chan: profiler_chan,
@@ -102,6 +110,21 @@ impl Layout {
}
}

// Create a layout context for use in building display lists, hit testing, &c.
fn build_layout_context(&self) -> LayoutContext {
let image_cache = self.local_image_cache;
let font_ctx = self.font_ctx;
let screen_size = self.screen_size.unwrap();
let doc_url = self.doc_url.clone();

LayoutContext {
image_cache: image_cache,
font_ctx: font_ctx,
doc_url: doc_url.unwrap(),
screen_size: Rect(Point2D(Au(0), Au(0)), screen_size),
}
}

fn handle_request(&mut self) -> bool {
match self.from_script.recv() {
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
@@ -147,20 +170,16 @@ impl Layout {
debug!("layout: damage is %?", data.damage);
debug!("layout: parsed Node tree");
debug!("%?", node.dump());

// Reset the image cache.
self.local_image_cache.next_round(self.make_on_image_available_cb(script_chan));

self.doc_url = Some(doc_url);
let screen_size = Size2D(Au::from_px(data.window_size.width as int),
Au::from_px(data.window_size.height as int));
self.screen_size = Some(screen_size);

// Create a layout context for use throughout the following passes.
let mut layout_ctx = LayoutContext {
image_cache: self.local_image_cache,
font_ctx: self.font_ctx,
doc_url: doc_url,
screen_size: Rect(Point2D(Au(0), Au(0)), screen_size)
};
let mut layout_ctx = self.build_layout_context();

// Initialize layout data for each node.
//
@@ -290,6 +309,55 @@ impl Layout {
}
};

reply_chan.send(response)
}
HitTestQuery(node, point) => {
// FIXME: Isolate this transmutation into a single "bridge" module.
let node: AbstractNode<LayoutView> = unsafe {
transmute(node)
};
let mut flow_node: AbstractNode<LayoutView> = node;
for node.traverse_preorder |node| {
if node.layout_data().flow.is_some() {
flow_node = node;
break;
}
};

let response = match flow_node.layout_data().flow {
None => {
debug!("HitTestQuery: flow is None");
Err(())
}
Some(flow) => {
let layout_ctx = self.build_layout_context();
let builder = DisplayListBuilder {
ctx: &layout_ctx,
};
let display_list: @Cell<DisplayList<RenderBox>> =
@Cell(DisplayList::new());
flow.build_display_list(&builder,
&flow.position(),
display_list);
// iterate in reverse to ensure we have the most recently painted render box
let (x, y) = (Au::from_frac_px(point.x as float),
Au::from_frac_px(point.y as float));
let mut resp = Err(());
let display_list = &display_list.take().list;
for display_list.each_reverse |display_item| {
let bounds = display_item.bounds();
if x <= bounds.origin.x + bounds.size.width &&
bounds.origin.x <= x &&
y < bounds.origin.y + bounds.size.height &&
bounds.origin.y < y {
resp = Ok(HitTestResponse(display_item.base().extra.node()));
break;
}
}
resp
}
};

reply_chan.send(response)
}
}
@@ -7,8 +7,8 @@
/// GLUT is a very old and bare-bones toolkit. However, it has good cross-platform support, at
/// least on desktops. It is designed for testing Servo without the need of a UI.

use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, ResizeCallback};
use windowing::{ScrollCallback, WindowMethods};
use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, ClickCallback};
use windowing::{ResizeCallback, ScrollCallback, WindowMethods};

use alert::{Alert, AlertMethods};
use core::libc::c_int;
@@ -35,6 +35,7 @@ pub struct Window {
composite_callback: Option<CompositeCallback>,
resize_callback: Option<ResizeCallback>,
load_url_callback: Option<LoadUrlCallback>,
click_callback: Option<ClickCallback>,
scroll_callback: Option<ScrollCallback>,

drag_origin: Point2D<c_int>,
@@ -54,6 +55,7 @@ impl WindowMethods<Application> for Window {
composite_callback: None,
resize_callback: None,
load_url_callback: None,
click_callback: None,
scroll_callback: None,

drag_origin: Point2D(0, 0),
@@ -77,6 +79,7 @@ impl WindowMethods<Application> for Window {
window.handle_key(key)
}
do glut::mouse_func |_, _, x, y| {
window.handle_click(x, y);
window.start_drag(x, y)
}
do glut::motion_func |x, y| {
@@ -111,6 +114,11 @@ impl WindowMethods<Application> for Window {
self.load_url_callback = Some(new_load_url_callback)
}

/// Registers a callback to be run when a click event occurs.
pub fn set_click_callback(&mut self, new_click_callback: ClickCallback) {
self.click_callback = Some(new_click_callback)
}

/// Registers a callback to be run when the user scrolls.
pub fn set_scroll_callback(&mut self, new_scroll_callback: ScrollCallback) {
self.scroll_callback = Some(new_scroll_callback)
@@ -136,6 +144,14 @@ impl Window {
}
}

/// Helper function to handle a click
fn handle_click(&self, x: c_int, y: c_int) {
match self.click_callback {
None => {}
Some(callback) => callback(Point2D(x as f32, y as f32)),
}
}

/// Helper function to start a drag.
fn start_drag(&mut self, x: c_int, y: c_int) {
self.drag_origin = Point2D(x, y)
@@ -16,6 +16,10 @@ pub type ResizeCallback = @fn(uint, uint);
/// Type of the function that is called when a new URL is to be loaded.
pub type LoadUrlCallback = @fn(&str);

/// Type of the function that is called when hit testing is to be performed.
/// FIXME this currently does not discriminate between left and right clicks or any modifiers
pub type ClickCallback = @fn(Point2D<f32>);

/// Type of the function that is called when the user scrolls.
pub type ScrollCallback = @fn(Point2D<f32>);

@@ -38,6 +42,8 @@ pub trait WindowMethods<A> {
pub fn set_resize_callback(&mut self, new_resize_callback: ResizeCallback);
/// Registers a callback to run when a new URL is to be loaded.
pub fn set_load_url_callback(&mut self, new_load_url_callback: LoadUrlCallback);
/// Registers a callback to run when the user clicks.
pub fn set_click_callback(&mut self, new_click_callback: ClickCallback);
/// Registers a callback to run when the user scrolls.
pub fn set_scroll_callback(&mut self, new_scroll_callback: ScrollCallback);

@@ -7,9 +7,12 @@ use dom::window::Window;
use dom::bindings::codegen::EventBinding;
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};

use geom::point::Point2D;

pub enum Event {
ResizeEvent(uint, uint, comm::Chan<()>),
ReflowEvent
ReflowEvent,
ClickEvent(Point2D<f32>),
}

pub struct Event_ {
@@ -6,12 +6,13 @@
/// coupling between these two components, and enables the DOM to be placed in a separate crate
/// from layout.

use dom::node::{AbstractNode, ScriptView};
use dom::node::{AbstractNode, ScriptView, LayoutView};
use script_task::ScriptMsg;

use core::comm::{Chan, SharedChan};
use geom::rect::Rect;
use geom::size::Size2D;
use geom::point::Point2D;
use gfx::geometry::Au;
use newcss::stylesheet::Stylesheet;
use std::net::url::Url;
@@ -43,6 +44,8 @@ pub enum LayoutQuery {
ContentBoxQuery(AbstractNode<ScriptView>),
/// Requests the dimensions of all the content boxes, as in the `getClientRects()` call.
ContentBoxesQuery(AbstractNode<ScriptView>),
/// Requests the node containing the point of interest
HitTestQuery(AbstractNode<ScriptView>, Point2D<f32>),
}

/// The reply of a synchronous message from script to layout.
@@ -54,6 +57,8 @@ pub enum LayoutResponse {
ContentBoxResponse(Rect<Au>),
/// A response to the `ContentBoxesQuery` message.
ContentBoxesResponse(~[Rect<Au>]),
/// A response to the `HitTestQuery` message.
HitTestResponse(AbstractNode<LayoutView>),
}

/// Dirty bits for layout.
@@ -7,11 +7,11 @@

use dom::bindings::utils::GlobalStaticData;
use dom::document::Document;
use dom::event::{Event, ResizeEvent, ReflowEvent};
use dom::event::{Event, ResizeEvent, ReflowEvent, ClickEvent};
use dom::node::define_bindings;
use dom::window::Window;
use layout_interface::{AddStylesheetMsg, BuildData, BuildMsg, Damage, LayoutQuery};
use layout_interface::{LayoutResponse, LayoutTask, MatchSelectorsDamage, NoDamage};
use layout_interface::{AddStylesheetMsg, BuildData, BuildMsg, Damage, LayoutQuery, HitTestQuery};
use layout_interface::{LayoutResponse, HitTestResponse, LayoutTask, MatchSelectorsDamage, NoDamage};
use layout_interface::{QueryMsg, ReflowDamage};
use layout_interface;

@@ -460,6 +460,23 @@ impl ScriptContext {
self.relayout()
}
}

ClickEvent(point) => {
debug!("ClickEvent: clicked at %?", point);
let root = match self.root_frame {
Some(ref frame) => frame.document.root,
None => fail!("root frame is None")
};
match self.query_layout(HitTestQuery(root, point)) {
Ok(node) => match node {
HitTestResponse(node) => debug!("clicked on %?", node.debug_str()),
_ => fail!(~"unexpected layout reply")
},
Err(()) => {
println(fmt!("layout query error"));
}
};
}
}
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.