aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/main/compositing/compositor.rs6
-rw-r--r--src/components/main/compositing/compositor_layer.rs7
-rw-r--r--src/components/main/css/matching.rs3
-rw-r--r--src/components/main/layout/layout_task.rs45
-rw-r--r--src/components/main/layout/util.rs8
-rw-r--r--src/components/main/layout/wrapper.rs4
-rw-r--r--src/components/main/platform/common/glfw_windowing.rs8
-rw-r--r--src/components/main/windowing.rs2
-rw-r--r--src/components/script/dom/node.rs18
-rw-r--r--src/components/script/layout_interface.rs2
-rw-r--r--src/components/script/script_task.rs77
-rw-r--r--src/components/style/node.rs2
-rw-r--r--src/components/style/selector_matching.rs5
-rw-r--r--src/components/style/selectors.rs4
14 files changed, 171 insertions, 20 deletions
diff --git a/src/components/main/compositing/compositor.rs b/src/components/main/compositing/compositor.rs
index 2f3d399d885..247cc459e09 100644
--- a/src/components/main/compositing/compositor.rs
+++ b/src/components/main/compositing/compositor.rs
@@ -11,9 +11,9 @@ use platform::{Application, Window};
use windowing::{WindowEvent, WindowMethods,
WindowNavigateMsg,
IdleWindowEvent, RefreshWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent,
- MouseWindowEventClass,ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent,
+ MouseWindowEventClass, MouseWindowMoveEventClass,ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent,
FinishedWindowEvent, QuitWindowEvent,
- MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent, MouseMoveEventClass};
+ MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use azure::azure_hl::{SourceSurfaceMethods, Color};
@@ -515,7 +515,7 @@ impl IOCompositor {
self.on_mouse_window_event_class(mouse_window_event);
}
- MouseMoveEventClass(cursor) => {
+ MouseWindowMoveEventClass(cursor) => {
self.on_mouse_window_move_event_class(cursor);
}
diff --git a/src/components/main/compositing/compositor_layer.rs b/src/components/main/compositing/compositor_layer.rs
index 6abb6b4fc9c..bfdad4bf09e 100644
--- a/src/components/main/compositing/compositor_layer.rs
+++ b/src/components/main/compositing/compositor_layer.rs
@@ -18,7 +18,7 @@ use layers::platform::surface::{NativeCompositingGraphicsContext, NativeSurfaceM
use layers::texturegl::{Texture, TextureTarget};
#[cfg(target_os="macos")] use layers::texturegl::TextureTargetRectangle;
use pipeline::CompositionPipeline;
-use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent, MouseMoveEvent};
+use script::dom::event::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent};
use script::script_task::SendEventMsg;
use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile};
use servo_msg::constellation_msg::PipelineId;
@@ -247,15 +247,14 @@ impl CompositorLayer {
MouseWindowClickEvent(button, _) => ClickEvent(button, cursor),
MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, cursor),
MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, cursor),
- };
-
+ };
self.pipeline.script_chan.send(SendEventMsg(self.pipeline.id.clone(), message));
}
pub fn send_mouse_move_event(&self, cursor: Point2D<f32>) {
let message = MouseMoveEvent(cursor);
self.pipeline.script_chan.send(SendEventMsg(self.pipeline.id.clone(), message));
- }
+ }
// Given the current window size, determine which tiles need to be (re)rendered
// and sends them off the the appropriate renderer.
diff --git a/src/components/main/css/matching.rs b/src/components/main/css/matching.rs
index 5c74cfa7fe9..b38bdc1e1c6 100644
--- a/src/components/main/css/matching.rs
+++ b/src/components/main/css/matching.rs
@@ -40,6 +40,9 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref.get() {
Some(ref mut layout_data) => {
+ //FIXME To implement a clear() on SmallVec and use it(init_applicable_declarations).
+ layout_data.data.init_applicable_declarations();
+
stylist.push_applicable_declarations(self,
style_attribute,
None,
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index d6aa0473d76..4480c975861 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -35,9 +35,9 @@ use script::dom::node::{ElementNodeTypeId, LayoutDataRef};
use script::dom::element::{HTMLBodyElementTypeId, HTMLHtmlElementTypeId};
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitNowMsg, LayoutQuery};
-use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
+use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse, MouseOverQuery, MouseOverResponse};
use script::layout_interface::{ContentChangedDocumentDamage, LayoutChan, Msg, PrepareToExitMsg};
-use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, ReflowDocumentDamage};
+use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, ReflowDocumentDamage, UntrustedNodeAddress};
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
@@ -753,7 +753,6 @@ impl LayoutTask {
.to_untrusted_node_address()))
}
}
-
let ret: Option<HitTestResponse> = None;
ret
}
@@ -769,6 +768,46 @@ impl LayoutTask {
reply_chan.send(Err(()));
}
+ MouseOverQuery(_, point, reply_chan) => {
+ fn mouse_over_test(x: Au, y: Au, list: &[DisplayItem<OpaqueNode>], result: &mut ~[UntrustedNodeAddress]) {
+ for item in list.rev_iter() {
+ match *item {
+ ClipDisplayItemClass(ref cc) => {
+ mouse_over_test(x, y, cc.child_list, result);
+ }
+ _ => {}
+ }
+ }
+
+ for item in list.rev_iter() {
+ let bounds = item.bounds();
+
+ // TODO(tikue): 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 {
+ result.push(item.base()
+ .extra
+ .to_untrusted_node_address());
+ }
+ }
+ }
+
+ let mut mouse_over_list:~[UntrustedNodeAddress] = ~[];
+ for display_list in self.display_list_collection.as_ref().unwrap().get().lists.rev_iter() {
+ let (x, y) = (Au::from_frac_px(point.x as f64),
+ Au::from_frac_px(point.y as f64));
+ mouse_over_test(x,y,display_list.list, &mut mouse_over_list);
+ }
+
+ if mouse_over_list.is_empty() {
+ reply_chan.send(Err(()));
+ } else {
+ reply_chan.send(Ok(MouseOverResponse(mouse_over_list)));
+ }
+ }
}
}
diff --git a/src/components/main/layout/util.rs b/src/components/main/layout/util.rs
index 08596646f55..8b0f075b1f6 100644
--- a/src/components/main/layout/util.rs
+++ b/src/components/main/layout/util.rs
@@ -170,6 +170,14 @@ impl PrivateLayoutData {
parallel: DomParallelInfo::new(),
}
}
+
+ /// Initialize the function for applicable_declarations.
+ pub fn init_applicable_declarations(&mut self) {
+ //FIXME To implement a clear() on SmallVec and use it(init_applicable_declarations).
+ self.applicable_declarations = SmallVec16::new();
+ self.before_applicable_declarations = SmallVec0::new();
+ self.after_applicable_declarations = SmallVec0::new();
+ }
}
pub struct LayoutDataWrapper {
diff --git a/src/components/main/layout/wrapper.rs b/src/components/main/layout/wrapper.rs
index f1af40c8888..2e33daa9093 100644
--- a/src/components/main/layout/wrapper.rs
+++ b/src/components/main/layout/wrapper.rs
@@ -349,6 +349,10 @@ impl<'le> TElement for LayoutElement<'le> {
_ => None,
}
}
+
+ fn get_hover_state(&self) -> bool {
+ self.element.node.get_hover_state()
+ }
}
/// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout
diff --git a/src/components/main/platform/common/glfw_windowing.rs b/src/components/main/platform/common/glfw_windowing.rs
index 1c851222397..3f635f84f52 100644
--- a/src/components/main/platform/common/glfw_windowing.rs
+++ b/src/components/main/platform/common/glfw_windowing.rs
@@ -5,9 +5,9 @@
//! A windowing implementation using GLFW.
use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
-use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
+use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass, MouseWindowMoveEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
-use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent, MouseMoveEventClass};
+use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use windowing::RefreshWindowEvent;
use windowing::{Forward, Back};
@@ -157,8 +157,8 @@ impl WindowMethods<Application> for Window {
}
}));
window.glfw_window.set_cursor_pos_callback(
- glfw_callback!(glfw::CursorPosCallback(win: &glfw::Window, xpos: f64, ypos: f64) {
- local_window().event_queue.push(MouseMoveEventClass(Point2D(xpos as f32, ypos as f32)));
+ glfw_callback!(glfw::CursorPosCallback(_win: &glfw::Window, xpos: f64, ypos: f64) {
+ local_window().event_queue.push(MouseWindowMoveEventClass(Point2D(xpos as f32, ypos as f32)));
}));
window.glfw_window.set_scroll_callback(
glfw_callback!(glfw::ScrollCallback(win: &glfw::Window, xpos: f64, ypos: f64) {
diff --git a/src/components/main/windowing.rs b/src/components/main/windowing.rs
index 4cada3ac3e3..690d13c10fa 100644
--- a/src/components/main/windowing.rs
+++ b/src/components/main/windowing.rs
@@ -35,7 +35,7 @@ pub enum WindowEvent {
/// Sent when a mouse hit test is to be performed.
MouseWindowEventClass(MouseWindowEvent),
/// Sent when a mouse move.
- MouseMoveEventClass(Point2D<f32>),
+ MouseWindowMoveEventClass(Point2D<f32>),
/// Sent when the user scrolls. Includes the current cursor position.
ScrollWindowEvent(Point2D<f32>, Point2D<i32>),
/// Sent when the user zooms.
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index 8857e503b64..5cca4c0cbcf 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -101,6 +101,8 @@ impl NodeFlags {
/// Specifies whether this node is in a document.
bitfield!(NodeFlags, is_in_doc, set_is_in_doc, 0x01)
+/// Specifies whether this node is hover state for this node
+bitfield!(NodeFlags, get_in_hover_state, set_is_in_hover_state, 0x02)
#[unsafe_destructor]
impl Drop for Node {
@@ -546,6 +548,14 @@ impl<'a> AbstractNode {
pub fn is_in_doc(&self) -> bool {
self.node().flags.is_in_doc()
}
+
+ pub fn get_hover_state(&self) -> bool {
+ self.node().flags.get_in_hover_state()
+ }
+
+ pub fn set_hover_state(&self, state: bool) {
+ self.mut_node().flags.set_is_in_hover_state(state);
+ }
}
impl AbstractNode {
@@ -1607,6 +1617,14 @@ impl Node {
doc.document().wait_until_safe_to_modify_dom();
self.next_sibling = new_next_sibling
}
+
+ pub fn get_hover_state(&self) -> bool {
+ self.flags.get_in_hover_state()
+ }
+
+ pub fn set_hover_state(&mut self, state: bool) {
+ self.flags.set_is_in_hover_state(state);
+ }
}
impl Reflectable for Node {
diff --git a/src/components/script/layout_interface.rs b/src/components/script/layout_interface.rs
index b0b9ec479f4..8f6688b84aa 100644
--- a/src/components/script/layout_interface.rs
+++ b/src/components/script/layout_interface.rs
@@ -57,6 +57,7 @@ pub enum LayoutQuery {
ContentBoxesQuery(AbstractNode, Chan<ContentBoxesResponse>),
/// Requests the node containing the point of interest
HitTestQuery(AbstractNode, Point2D<f32>, Chan<Result<HitTestResponse, ()>>),
+ MouseOverQuery(AbstractNode, Point2D<f32>, Chan<Result<MouseOverResponse, ()>>),
}
/// The address of a node. Layout sends these back. They must be validated via
@@ -66,6 +67,7 @@ pub type UntrustedNodeAddress = *c_void;
pub struct ContentBoxResponse(Rect<Au>);
pub struct ContentBoxesResponse(~[Rect<Au>]);
pub struct HitTestResponse(UntrustedNodeAddress);
+pub struct MouseOverResponse(~[UntrustedNodeAddress]);
/// Determines which part of the
#[deriving(Eq, Ord)]
diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs
index e7f00045582..17c60cd45bf 100644
--- a/src/components/script/script_task.rs
+++ b/src/components/script/script_task.rs
@@ -9,7 +9,7 @@ use dom::bindings::codegen::RegisterBindings;
use dom::bindings::utils::{Reflectable, GlobalStaticData};
use dom::document::AbstractDocument;
use dom::element::Element;
-use dom::event::{Event_, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, MouseUpEvent, MouseMoveEvent};
+use dom::event::{Event_, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent};
use dom::event::Event;
use dom::eventtarget::AbstractEventTarget;
use dom::htmldocument::HTMLDocument;
@@ -20,7 +20,7 @@ use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredIFrame, HtmlDi
use html::hubbub_html_parser;
use layout_interface::{AddStylesheetMsg, DocumentDamage};
use layout_interface::{ContentBoxQuery, ContentBoxResponse};
-use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery};
+use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery, MouseOverQuery, MouseOverResponse};
use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg};
use layout_interface::{Reflow, ReflowDocumentDamage, ReflowForDisplay, ReflowGoal, ReflowMsg};
use layout_interface::ContentChangedDocumentDamage;
@@ -405,6 +405,8 @@ pub struct ScriptTask {
/// The JavaScript runtime.
js_runtime: js::rust::rt,
+
+ mouse_over_targets:Option<~[AbstractNode]>
}
/// Returns the relevant page from the associated JS Context.
@@ -440,6 +442,7 @@ impl ScriptTask {
compositor: compositor,
js_runtime: js_runtime,
+ mouse_over_targets:None
};
script_task
@@ -882,7 +885,75 @@ impl ScriptTask {
}
MouseDownEvent(..) => {}
MouseUpEvent(..) => {}
- MouseMoveEvent(point) => {}
+ MouseMoveEvent(point) => {
+ let document = page.frame.expect("root frame is None").document;
+ let root = document.document().GetDocumentElement();
+ if root.is_none() {
+ return;
+ }
+ let (port, chan) = Chan::new();
+ match page.query_layout(MouseOverQuery(root.unwrap(), point, chan), port) {
+ Ok(MouseOverResponse(node_address)) => {
+
+ let mut target_list:~[AbstractNode] = ~[];
+ let mut target_compare = false;
+
+ match self.mouse_over_targets {
+ Some(ref mut mouse_over_targets) => {
+ for node in mouse_over_targets.iter() {
+ node.set_hover_state(false);
+ }
+ }
+ None => {}
+ }
+
+ for node_address in node_address.iter() {
+ let mut node = AbstractNode::from_untrusted_node_address(self.js_runtime
+ .ptr,
+ *node_address);
+ // Traverse node generations until a node that is an element is
+ // found.
+ while !node.is_element() {
+ match node.parent_node() {
+ Some(parent) => node = parent,
+ None => break,
+ }
+ }
+
+ if node.is_element() {
+ node.set_hover_state(true);
+
+ match self.mouse_over_targets {
+ Some(ref mouse_over_targets) => {
+ if !target_compare {
+ target_compare = !mouse_over_targets.contains(&node);
+ }
+ }
+ None => {}
+ }
+ target_list.push(node);
+ }
+ }
+ match self.mouse_over_targets {
+ Some(ref mouse_over_targets) => {
+ if mouse_over_targets.len() != target_list.len() {
+ target_compare = true;
+ }
+ }
+ None => { target_compare = true; }
+ }
+
+ if target_compare {
+ if self.mouse_over_targets.is_some() {
+ page.damage(MatchSelectorsDocumentDamage);
+ page.reflow(ReflowForDisplay, self.chan.clone(), self.compositor);
+ }
+ self.mouse_over_targets = Some(target_list);
+ }
+ },
+ Err(()) => {},
+ }
+ }
}
}
diff --git a/src/components/style/node.rs b/src/components/style/node.rs
index dc6df8427bd..86021d9c895 100644
--- a/src/components/style/node.rs
+++ b/src/components/style/node.rs
@@ -13,7 +13,6 @@ pub trait TNode<E:TElement> : Clone {
fn parent_node(&self) -> Option<Self>;
fn prev_sibling(&self) -> Option<Self>;
fn next_sibling(&self) -> Option<Self>;
-
fn is_document(&self) -> bool;
fn is_element(&self) -> bool;
@@ -28,5 +27,6 @@ pub trait TElement {
fn get_link(&self) -> Option<&'static str>;
fn get_local_name<'a>(&'a self) -> &'a str;
fn get_namespace<'a>(&'a self) -> &'a Namespace;
+ fn get_hover_state(&self) -> bool;
}
diff --git a/src/components/style/selector_matching.rs b/src/components/style/selector_matching.rs
index ccaf715b387..3fab94da4e8 100644
--- a/src/components/style/selector_matching.rs
+++ b/src/components/style/selector_matching.rs
@@ -615,6 +615,11 @@ fn matches_simple_selector<E:TElement,N:TNode<E>>(selector: &SimpleSelector, ele
})
}
+ Hover => {
+ element.with_element(|element: &E| {
+ element.get_hover_state()
+ })
+ },
FirstChild => matches_first_child(element),
LastChild => matches_last_child(element),
OnlyChild => matches_first_child(element) &&
diff --git a/src/components/style/selectors.rs b/src/components/style/selectors.rs
index c15259917a4..1c92f4b4568 100644
--- a/src/components/style/selectors.rs
+++ b/src/components/style/selectors.rs
@@ -74,6 +74,7 @@ pub enum SimpleSelector {
AnyLink,
Link,
Visited,
+ Hover,
FirstChild, LastChild, OnlyChild,
// Empty,
Root,
@@ -210,7 +211,7 @@ fn compute_specificity(mut selector: &CompoundSelector,
&ClassSelector(..)
| &AttrExists(..) | &AttrEqual(..) | &AttrIncludes(..) | &AttrDashMatch(..)
| &AttrPrefixMatch(..) | &AttrSubstringMatch(..) | &AttrSuffixMatch(..)
- | &AnyLink | &Link | &Visited
+ | &AnyLink | &Link | &Visited | &Hover
| &FirstChild | &LastChild | &OnlyChild | &Root
// | &Empty | &Lang(*)
| &NthChild(..) | &NthLastChild(..)
@@ -468,6 +469,7 @@ fn parse_simple_pseudo_class(name: &str) -> Option<SimpleSelector> {
"any-link" => Some(AnyLink),
"link" => Some(Link),
"visited" => Some(Visited),
+ "hover" => Some(Hover),
"first-child" => Some(FirstChild),
"last-child" => Some(LastChild),
"only-child" => Some(OnlyChild),