aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/script_task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/script_task.rs')
-rw-r--r--components/script/script_task.rs184
1 files changed, 66 insertions, 118 deletions
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index f29e5690cf5..78e50516420 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -66,8 +66,7 @@ use util::task::spawn_named_with_send_on_failure;
use util::task_state;
use geom::point::Point2D;
-use hyper::header::{Header, Headers, HeaderFormat};
-use hyper::header::parsing as header_parsing;
+use hyper::header::{LastModified, Headers};
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
use js::jsapi::{JSContext, JSRuntime, JSObject};
use js::jsapi::{JS_SetGCParameter, JSGC_MAX_BYTES};
@@ -80,14 +79,13 @@ use libc;
use std::any::Any;
use std::borrow::ToOwned;
use std::cell::Cell;
-use std::fmt::{self, Display};
use std::mem::replace;
use std::num::ToPrimitive;
use std::rc::Rc;
use std::result::Result;
use std::sync::mpsc::{channel, Sender, Receiver, Select};
use std::u32;
-use time::{Tm, strptime};
+use time::Tm;
thread_local!(pub static STACK_ROOTS: Cell<Option<RootCollectionPtr>> = Cell::new(None));
@@ -222,7 +220,7 @@ pub struct ScriptTask {
/// The JSContext.
js_context: DOMRefCell<Option<Rc<Cx>>>,
- mouse_over_targets: DOMRefCell<Option<Vec<JS<Node>>>>
+ mouse_over_targets: DOMRefCell<Vec<JS<Node>>>
}
/// In the event of task failure, all data on the stack runs its destructor. However, there
@@ -385,7 +383,7 @@ impl ScriptTask {
js_runtime: js_runtime,
js_context: DOMRefCell::new(Some(js_context)),
- mouse_over_targets: DOMRefCell::new(None)
+ mouse_over_targets: DOMRefCell::new(vec!())
}
}
@@ -1151,87 +1149,72 @@ impl ScriptTask {
fn handle_mouse_move_event(&self, pipeline_id: PipelineId, point: Point2D<f32>) {
let page = get_page(&*self.page.borrow(), pipeline_id);
- match page.get_nodes_under_mouse(&point) {
- Some(node_address) => {
- let mut target_list = vec!();
- let mut target_compare = false;
-
- let mouse_over_targets = &mut *self.mouse_over_targets.borrow_mut();
- match *mouse_over_targets {
- Some(ref mut mouse_over_targets) => {
- for node in mouse_over_targets.iter_mut() {
- let node = node.root();
- node.r().set_hover_state(false);
- }
- }
- None => {}
- }
-
- if node_address.len() > 0 {
- let top_most_node =
- node::from_untrusted_node_address(self.js_runtime.ptr, node_address[0]).root();
-
- if let Some(ref frame) = *page.frame() {
- let window = frame.window.root();
-
- let x = point.x.to_i32().unwrap_or(0);
- let y = point.y.to_i32().unwrap_or(0);
-
- let mouse_event = MouseEvent::new(window.r(),
- "mousemove".to_owned(),
- true,
- true,
- Some(window.r()),
- 0i32,
- x, y, x, y,
- false, false, false, false,
- 0i16,
- None).root();
-
- let event: JSRef<Event> = EventCast::from_ref(mouse_event.r());
- let target: JSRef<EventTarget> = EventTargetCast::from_ref(top_most_node.r());
- event.fire(target);
- }
- }
+ let mut needs_reflow = false;
+
+ // Build a list of elements that are currently under the mouse.
+ let mouse_over_addresses = page.get_nodes_under_mouse(&point);
+ let mouse_over_targets: Vec<JS<Node>> = mouse_over_addresses.iter()
+ .filter_map(|node_address| {
+ let node = node::from_untrusted_node_address(self.js_runtime.ptr, *node_address);
+ node.root().r().inclusive_ancestors().find(|node| node.is_element()).map(JS::from_rooted)
+ }).collect();
+
+ // Remove hover from any elements in the previous list that are no longer
+ // under the mouse.
+ let prev_mouse_over_targets = &mut *self.mouse_over_targets.borrow_mut();
+ for target in prev_mouse_over_targets.iter() {
+ if !mouse_over_targets.contains(target) {
+ target.root().r().set_hover_state(false);
+ needs_reflow = true;
+ }
+ }
- for node_address in node_address.iter() {
- let temp_node =
- node::from_untrusted_node_address(self.js_runtime.ptr, *node_address).root();
-
- let maybe_node = temp_node.r().ancestors().find(|node| node.is_element());
- match maybe_node {
- Some(node) => {
- node.set_hover_state(true);
- match *mouse_over_targets {
- Some(ref mouse_over_targets) if !target_compare => {
- target_compare =
- !mouse_over_targets.contains(&JS::from_rooted(node));
- }
- _ => {}
- }
- target_list.push(JS::from_rooted(node));
- }
- None => {}
- }
- }
- match *mouse_over_targets {
- Some(ref mouse_over_targets) => {
- if mouse_over_targets.len() != target_list.len() {
- target_compare = true
- }
- }
- None => target_compare = true,
- }
+ // Set hover state for any elements in the current mouse over list.
+ // Check if any of them changed state to determine whether to
+ // force a reflow below.
+ for target in mouse_over_targets.iter() {
+ let target = target.root();
+ let target_ref = target.r();
+ if !target_ref.get_hover_state() {
+ target_ref.set_hover_state(true);
+ needs_reflow = true;
+ }
+ }
- if target_compare {
- if mouse_over_targets.is_some() {
- self.force_reflow(&*page)
- }
- *mouse_over_targets = Some(target_list);
- }
+ // Send mousemove event to topmost target
+ if mouse_over_addresses.len() > 0 {
+ let top_most_node =
+ node::from_untrusted_node_address(self.js_runtime.ptr, mouse_over_addresses[0]).root();
+
+ if let Some(ref frame) = *page.frame() {
+ let window = frame.window.root();
+
+ let x = point.x.to_i32().unwrap_or(0);
+ let y = point.y.to_i32().unwrap_or(0);
+
+ let mouse_event = MouseEvent::new(window.r(),
+ "mousemove".to_owned(),
+ true,
+ true,
+ Some(window.r()),
+ 0i32,
+ x, y, x, y,
+ false, false, false, false,
+ 0i16,
+ None).root();
+
+ let event: JSRef<Event> = EventCast::from_ref(mouse_event.r());
+ let target: JSRef<EventTarget> = EventTargetCast::from_ref(top_most_node.r());
+ event.fire(target);
}
+ }
- None => {}
+ // Store the current mouse over targets for next frame
+ *prev_mouse_over_targets = mouse_over_targets;
+
+ // Reflow if hover state changed
+ if needs_reflow {
+ self.force_reflow(&*page);
}
}
}
@@ -1278,41 +1261,6 @@ pub fn get_page(page: &Rc<Page>, pipeline_id: PipelineId) -> Rc<Page> {
This is a bug.")
}
-//FIXME(seanmonstar): uplift to Hyper
-#[derive(Clone)]
-struct LastModified(pub Tm);
-
-impl Header for LastModified {
- #[inline]
- fn header_name() -> &'static str {
- "Last-Modified"
- }
-
- // Parses an RFC 2616 compliant date/time string,
- fn parse_header(raw: &[Vec<u8>]) -> Option<LastModified> {
- header_parsing::from_one_raw_str(raw).and_then(|s: String| {
- let s = s.as_slice();
- strptime(s, "%a, %d %b %Y %T %Z").or_else(|_| {
- strptime(s, "%A, %d-%b-%y %T %Z")
- }).or_else(|_| {
- strptime(s, "%c")
- }).ok().map(|tm| LastModified(tm))
- })
- }
-}
-
-impl HeaderFormat for LastModified {
- // a localized date/time string in a format suitable
- // for document.lastModified.
- fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let LastModified(ref tm) = *self;
- match tm.tm_utcoff {
- 0 => <_ as Display>::fmt(&tm.rfc822(), f),
- _ => <_ as Display>::fmt(&tm.to_utc().rfc822(), f)
- }
- }
-}
-
fn dom_last_modified(tm: &Tm) -> String {
format!("{}", tm.to_local().strftime("%m/%d/%Y %H:%M:%S").unwrap())
}