diff options
-rw-r--r-- | src/components/main/compositing/compositor.rs | 6 | ||||
-rw-r--r-- | src/components/main/compositing/compositor_layer.rs | 7 | ||||
-rw-r--r-- | src/components/main/css/matching.rs | 3 | ||||
-rw-r--r-- | src/components/main/layout/layout_task.rs | 45 | ||||
-rw-r--r-- | src/components/main/layout/util.rs | 8 | ||||
-rw-r--r-- | src/components/main/layout/wrapper.rs | 4 | ||||
-rw-r--r-- | src/components/main/platform/common/glfw_windowing.rs | 8 | ||||
-rw-r--r-- | src/components/main/windowing.rs | 2 | ||||
-rw-r--r-- | src/components/script/dom/node.rs | 18 | ||||
-rw-r--r-- | src/components/script/layout_interface.rs | 2 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 77 | ||||
-rw-r--r-- | src/components/style/node.rs | 2 | ||||
-rw-r--r-- | src/components/style/selector_matching.rs | 5 | ||||
-rw-r--r-- | src/components/style/selectors.rs | 4 |
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), |