diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/main/compositing/compositor.rs | 20 | ||||
-rw-r--r-- | src/components/main/layout/wrapper.rs | 9 | ||||
-rw-r--r-- | src/components/main/platform/common/glfw_windowing.rs | 127 | ||||
-rw-r--r-- | src/components/main/platform/common/glut_windowing.rs | 108 | ||||
-rw-r--r-- | src/components/main/windowing.rs | 13 | ||||
-rw-r--r-- | src/components/msg/compositor_msg.rs | 4 | ||||
-rw-r--r-- | src/components/script/dom/bindings/codegen/Bindings.conf | 1 | ||||
-rw-r--r-- | src/components/script/dom/document.rs | 15 | ||||
-rw-r--r-- | src/components/script/dom/node.rs | 126 | ||||
-rw-r--r-- | src/components/script/dom/webidls/Node.webidl | 2 | ||||
-rw-r--r-- | src/components/style/selectors.rs | 89 | ||||
-rw-r--r-- | src/components/style/style.rs | 2 | ||||
-rw-r--r-- | src/test/html/content/test_node_isEqualNode.html | 39 | ||||
-rw-r--r-- | src/test/ref/attr_exists_selector.html | 13 | ||||
-rw-r--r-- | src/test/ref/attr_exists_selector_ref.html | 10 | ||||
-rw-r--r-- | src/test/ref/basic.list | 1 |
16 files changed, 426 insertions, 153 deletions
diff --git a/src/components/main/compositing/compositor.rs b/src/components/main/compositing/compositor.rs index 247cc459e09..9cdcb00d43c 100644 --- a/src/components/main/compositing/compositor.rs +++ b/src/components/main/compositing/compositor.rs @@ -39,11 +39,12 @@ use servo_util::{time, url}; use std::comm::Port; use std::num::Orderable; use std::path::Path; +use std::rc::Rc; pub struct IOCompositor { /// The application window. - window: @mut Window, + window: Rc<Window>, /// The port on which we receive messages. port: Port<Msg>, @@ -115,14 +116,14 @@ impl IOCompositor { port: Port<Msg>, constellation_chan: ConstellationChan, profiler_chan: ProfilerChan) -> IOCompositor { - let window: @mut Window = WindowMethods::new(app); + let window: Rc<Window> = WindowMethods::new(app); // Create an initial layer tree. // // TODO: There should be no initial layer tree until the renderer creates one from the display // list. This is only here because we don't have that logic in the renderer yet. let root_layer = @mut ContainerLayer(); - let window_size = window.size(); + let window_size = window.borrow().size(); IOCompositor { window: window, @@ -181,7 +182,8 @@ impl IOCompositor { } // Check for messages coming from the windowing system. - self.handle_window_message(self.window.recv()); + let msg = self.window.borrow().recv(); + self.handle_window_message(msg); // If asked to recomposite and renderer has run at least once if self.recomposite && self.composite_ready { @@ -231,7 +233,7 @@ impl IOCompositor { } (Some(ChangeReadyState(ready_state)), false) => { - self.window.set_ready_state(ready_state); + self.window.borrow().set_ready_state(ready_state); self.ready_state = ready_state; } @@ -293,7 +295,7 @@ impl IOCompositor { } fn change_render_state(&mut self, render_state: RenderState) { - self.window.set_render_state(render_state); + self.window.borrow().set_render_state(render_state); if render_state == IdleRenderState { self.composite_ready = true; } @@ -335,7 +337,7 @@ impl IOCompositor { self.compositor_layer = Some(layer); // Initialize the new constellation channel by sending it the root window size. - let window_size = self.window.size(); + let window_size = self.window.borrow().size(); let window_size = Size2D(window_size.width as uint, window_size.height as uint); new_constellation_chan.send(ResizedWindowMsg(window_size)); @@ -660,7 +662,7 @@ impl IOCompositor { profile(time::CompositingCategory, self.profiler_chan.clone(), || { debug!("compositor: compositing"); // Adjust the layer dimensions as necessary to correspond to the size of the window. - self.scene.size = self.window.size(); + self.scene.size = self.window.borrow().size(); // Render the scene. match self.compositor_layer { Some(ref mut layer) => { @@ -709,7 +711,7 @@ impl IOCompositor { self.shutting_down = true; } - self.window.present(); + self.window.borrow().present(); let exit = self.opts.exit_after_load; if exit { diff --git a/src/components/main/layout/wrapper.rs b/src/components/main/layout/wrapper.rs index 2e33daa9093..cee7a5095a5 100644 --- a/src/components/main/layout/wrapper.rs +++ b/src/components/main/layout/wrapper.rs @@ -27,7 +27,8 @@ use servo_util::namespace; use servo_util::namespace::Namespace; use std::cast; use std::cell::{Ref, RefMut}; -use style::{PropertyDeclarationBlock, TElement, TNode, AttrSelector}; +use style::{PropertyDeclarationBlock, TElement, TNode, + AttrSelector, SpecificNamespace, AnyNamespace}; use layout::util::LayoutDataWrapper; @@ -239,14 +240,14 @@ impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> { attr.name.as_slice() }; match attr.namespace { - Some(ref ns) => { + SpecificNamespace(ref ns) => { match element.get_attr(ns, name) { Some(value) => test(value), None => false, } }, - // FIXME: support `*|attr`, attribute selectors in any namespace - None => return false, + // FIXME: https://github.com/mozilla/servo/issues/1558 + AnyNamespace => return false, } }) } diff --git a/src/components/main/platform/common/glfw_windowing.rs b/src/components/main/platform/common/glfw_windowing.rs index 3f635f84f52..27cf7accc93 100644 --- a/src/components/main/platform/common/glfw_windowing.rs +++ b/src/components/main/platform/common/glfw_windowing.rs @@ -14,8 +14,11 @@ use windowing::{Forward, Back}; use alert::{Alert, AlertMethods}; use extra::time::Timespec; use extra::time; +use std::cell::{Cell, RefCell}; use std::libc::{exit, c_int}; use std::local_data; +use std::rc::Rc; + use geom::point::Point2D; use geom::size::Size2D; use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; @@ -86,60 +89,61 @@ macro_rules! glfw_callback( pub struct Window { glfw_window: glfw::Window, - event_queue: @mut ~[WindowEvent], + event_queue: RefCell<~[WindowEvent]>, drag_origin: Point2D<c_int>, - mouse_down_button: @mut Option<glfw::MouseButton>, - mouse_down_point: @mut Point2D<c_int>, + mouse_down_button: Cell<Option<glfw::MouseButton>>, + mouse_down_point: Cell<Point2D<c_int>>, - ready_state: ReadyState, - render_state: RenderState, + ready_state: Cell<ReadyState>, + render_state: Cell<RenderState>, - last_title_set_time: Timespec, + last_title_set_time: Cell<Timespec>, } impl WindowMethods<Application> for Window { /// Creates a new window. - fn new(_: &Application) -> @mut Window { + fn new(_: &Application) -> Rc<Window> { // Create the GLFW window. let glfw_window = glfw::Window::create(800, 600, "Servo", glfw::Windowed) .expect("Failed to create GLFW window"); glfw_window.make_context_current(); // Create our window object. - let window = @mut Window { + let window = Window { glfw_window: glfw_window, - event_queue: @mut ~[], + event_queue: RefCell::new(~[]), drag_origin: Point2D(0 as c_int, 0), - mouse_down_button: @mut None, - mouse_down_point: @mut Point2D(0 as c_int, 0), + mouse_down_button: Cell::new(None), + mouse_down_point: Cell::new(Point2D(0 as c_int, 0)), - ready_state: Blank, - render_state: IdleRenderState, + ready_state: Cell::new(Blank), + render_state: Cell::new(IdleRenderState), - last_title_set_time: Timespec::new(0, 0), + last_title_set_time: Cell::new(Timespec::new(0, 0)), }; - install_local_window(window); - // Register event handlers. window.glfw_window.set_framebuffer_size_callback( glfw_callback!(glfw::FramebufferSizeCallback(_win: &glfw::Window, width: i32, height: i32) { - local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint)); + let tmp = local_window(); + tmp.borrow().event_queue.with_mut(|queue| queue.push(ResizeWindowEvent(width as uint, height as uint))); })); window.glfw_window.set_refresh_callback( glfw_callback!(glfw::WindowRefreshCallback(_win: &glfw::Window) { - local_window().event_queue.push(RefreshWindowEvent); + let tmp = local_window(); + tmp.borrow().event_queue.with_mut(|queue| queue.push(RefreshWindowEvent)); })); window.glfw_window.set_key_callback( glfw_callback!(glfw::KeyCallback(_win: &glfw::Window, key: glfw::Key, _scancode: c_int, action: glfw::Action, mods: glfw::Modifiers) { if action == glfw::Press { - local_window().handle_key(key, mods) + let tmp = local_window(); + tmp.borrow().handle_key(key, mods) } })); window.glfw_window.set_mouse_button_callback( @@ -153,12 +157,14 @@ impl WindowMethods<Application> for Window { let x = x as f32 * hidpi; let y = y as f32 * hidpi; if button == glfw::MouseButtonLeft || button == glfw::MouseButtonRight { - local_window().handle_mouse(button, action, x as i32, y as i32); + let tmp = local_window(); + tmp.borrow().handle_mouse(button, action, x as i32, y as i32); } })); window.glfw_window.set_cursor_pos_callback( glfw_callback!(glfw::CursorPosCallback(_win: &glfw::Window, xpos: f64, ypos: f64) { - local_window().event_queue.push(MouseWindowMoveEventClass(Point2D(xpos as f32, ypos as f32))); + let tmp = local_window(); + tmp.borrow().event_queue.with_mut(|queue| 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) { @@ -173,10 +179,15 @@ impl WindowMethods<Application> for Window { let x = x as f32 * hidpi; let y = y as f32 * hidpi; - local_window().event_queue.push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32))); + let tmp = local_window(); + tmp.borrow().event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32)))); })); - window + let wrapped_window = Rc::from_send(window); + + install_local_window(wrapped_window.clone()); + + wrapped_window } /// Returns the size of the window. @@ -186,45 +197,45 @@ impl WindowMethods<Application> for Window { } /// Presents the window to the screen (perhaps by page flipping). - fn present(&mut self) { + fn present(&self) { self.glfw_window.swap_buffers(); } - fn recv(@mut self) -> WindowEvent { - if !self.event_queue.is_empty() { - return self.event_queue.shift() + fn recv(&self) -> WindowEvent { + if !self.event_queue.with_mut(|queue| queue.is_empty()) { + return self.event_queue.with_mut(|queue| queue.shift()) } glfw::poll_events(); if self.glfw_window.should_close() { QuitWindowEvent - } else if !self.event_queue.is_empty() { - self.event_queue.shift() + } else if !self.event_queue.with_mut(|queue| queue.is_empty()) { + self.event_queue.with_mut(|queue| queue.shift()) } else { IdleWindowEvent } } /// Sets the ready state. - fn set_ready_state(@mut self, ready_state: ReadyState) { - self.ready_state = ready_state; + fn set_ready_state(&self, ready_state: ReadyState) { + self.ready_state.set(ready_state); self.update_window_title() } /// Sets the render state. - fn set_render_state(@mut self, render_state: RenderState) { - if self.ready_state == FinishedLoading && - self.render_state == RenderingRenderState && + fn set_render_state(&self, render_state: RenderState) { + if self.ready_state.get() == FinishedLoading && + self.render_state.get() == RenderingRenderState && render_state == IdleRenderState { // page loaded - self.event_queue.push(FinishedWindowEvent); + self.event_queue.with_mut(|queue| queue.push(FinishedWindowEvent)); } - self.render_state = render_state; + self.render_state.set(render_state); self.update_window_title() } - fn hidpi_factor(@mut self) -> f32 { + fn hidpi_factor(&self) -> f32 { let (backing_size, _) = self.glfw_window.get_framebuffer_size(); let (window_size, _) = self.glfw_window.get_size(); (backing_size as f32) / (window_size as f32) @@ -233,14 +244,14 @@ impl WindowMethods<Application> for Window { impl Window { /// Helper function to set the window title in accordance with the ready state. - fn update_window_title(&mut self) { + fn update_window_title(&self) { let now = time::get_time(); - if now.sec == self.last_title_set_time.sec { + if now.sec == self.last_title_set_time.get().sec { return } - self.last_title_set_time = now; + self.last_title_set_time.set(now); - match self.ready_state { + match self.ready_state.get() { Blank => { self.glfw_window.set_title("blank — Servo") } @@ -251,7 +262,7 @@ impl Window { self.glfw_window.set_title("Performing Layout — Servo") } FinishedLoading => { - match self.render_state { + match self.render_state.get() { RenderingRenderState => { self.glfw_window.set_title("Rendering — Servo") } @@ -269,16 +280,16 @@ impl Window { glfw::KeyEscape => self.glfw_window.set_should_close(true), glfw::KeyL if mods.contains(glfw::Control) => self.load_url(), // Ctrl+L glfw::KeyEqual if mods.contains(glfw::Control) => { // Ctrl-+ - self.event_queue.push(ZoomWindowEvent(1.1)); + self.event_queue.with_mut(|queue| queue.push(ZoomWindowEvent(1.1))); } glfw::KeyMinus if mods.contains(glfw::Control) => { // Ctrl-- - self.event_queue.push(ZoomWindowEvent(0.90909090909)); + self.event_queue.with_mut(|queue| queue.push(ZoomWindowEvent(0.90909090909))); } glfw::KeyBackspace if mods.contains(glfw::Shift) => { // Shift-Backspace - self.event_queue.push(NavigationWindowEvent(Forward)); + self.event_queue.with_mut(|queue| queue.push(NavigationWindowEvent(Forward))); } glfw::KeyBackspace => { // Backspace - self.event_queue.push(NavigationWindowEvent(Back)); + self.event_queue.with_mut(|queue| queue.push(NavigationWindowEvent(Back))); } _ => {} } @@ -290,21 +301,21 @@ impl Window { let max_pixel_dist = 10f64; let event = match action { glfw::Press => { - *self.mouse_down_point = Point2D(x, y); - *self.mouse_down_button = Some(button); + self.mouse_down_point.set(Point2D(x, y)); + self.mouse_down_button.set(Some(button)); MouseWindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32)) } glfw::Release => { - match *self.mouse_down_button { + match self.mouse_down_button.get() { None => (), Some(but) if button == but => { - let pixel_dist = *self.mouse_down_point - Point2D(x, y); + let pixel_dist = self.mouse_down_point.get() - Point2D(x, y); let pixel_dist = ((pixel_dist.x * pixel_dist.x + pixel_dist.y * pixel_dist.y) as f64).sqrt(); if pixel_dist < max_pixel_dist { let click_event = MouseWindowClickEvent(button as uint, Point2D(x as f32, y as f32)); - self.event_queue.push(MouseWindowEventClass(click_event)); + self.event_queue.with_mut(|queue| queue.push(MouseWindowEventClass(click_event))); } } Some(_) => (), @@ -313,7 +324,7 @@ impl Window { } _ => fail!("I cannot recognize the type of mouse action that occured. :-(") }; - self.event_queue.push(MouseWindowEventClass(event)); + self.event_queue.with_mut(|queue| queue.push(MouseWindowEventClass(event))); } /// Helper function to pop up an alert box prompting the user to load a URL. @@ -323,16 +334,16 @@ impl Window { alert.run(); let value = alert.prompt_value(); if "" == value { // To avoid crashing on Linux. - self.event_queue.push(LoadUrlWindowEvent(~"http://purple.com/")) + self.event_queue.with_mut(|queue| queue.push(LoadUrlWindowEvent(~"http://purple.com/"))) } else { - self.event_queue.push(LoadUrlWindowEvent(value)) + self.event_queue.with_mut(|queue| queue.push(LoadUrlWindowEvent(value.clone()))) } } } -static TLS_KEY: local_data::Key<@mut Window> = &local_data::Key; +static TLS_KEY: local_data::Key<Rc<Window>> = &local_data::Key; -fn install_local_window(window: @mut Window) { +fn install_local_window(window: Rc<Window>) { local_data::set(TLS_KEY, window); } @@ -340,6 +351,6 @@ fn drop_local_window() { local_data::pop(TLS_KEY); } -fn local_window() -> @mut Window { - local_data::get(TLS_KEY, |v| *v.unwrap()) +fn local_window() -> Rc<Window> { + local_data::get(TLS_KEY, |v| v.unwrap().clone()) } diff --git a/src/components/main/platform/common/glut_windowing.rs b/src/components/main/platform/common/glut_windowing.rs index 38457aed4e5..51819207de1 100644 --- a/src/components/main/platform/common/glut_windowing.rs +++ b/src/components/main/platform/common/glut_windowing.rs @@ -11,8 +11,10 @@ use windowing::{MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMou use windowing::{Forward, Back}; use alert::{Alert, AlertMethods}; +use std::cell::{Cell, RefCell}; use std::libc::{c_int, c_uchar}; use std::local_data; +use std::rc::Rc; use geom::point::Point2D; use geom::size::Size2D; use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; @@ -45,43 +47,41 @@ impl Drop for Application { pub struct Window { glut_window: glut::Window, - event_queue: @mut ~[WindowEvent], + event_queue: RefCell<~[WindowEvent]>, drag_origin: Point2D<c_int>, - mouse_down_button: @mut c_int, - mouse_down_point: @mut Point2D<c_int>, + mouse_down_button: Cell<c_int>, + mouse_down_point: Cell<Point2D<c_int>>, - ready_state: ReadyState, - render_state: RenderState, - throbber_frame: u8, + ready_state: Cell<ReadyState>, + render_state: Cell<RenderState>, + throbber_frame: Cell<u8>, } impl WindowMethods<Application> for Window { /// Creates a new window. - fn new(_: &Application) -> @mut Window { + fn new(_: &Application) -> Rc<Window> { // Create the GLUT window. glut::init_window_size(800, 600); let glut_window = glut::create_window(~"Servo"); // Create our window object. - let window = @mut Window { + let window = Window { glut_window: glut_window, - event_queue: @mut ~[], + event_queue: RefCell::new(~[]), drag_origin: Point2D(0 as c_int, 0), - mouse_down_button: @mut 0, - mouse_down_point: @mut Point2D(0 as c_int, 0), + mouse_down_button: Cell::new(0), + mouse_down_point: Cell::new(Point2D(0 as c_int, 0)), - ready_state: Blank, - render_state: IdleRenderState, - throbber_frame: 0, + ready_state: Cell::new(Blank), + render_state: Cell::new(IdleRenderState), + throbber_frame: Cell::new(0), }; - install_local_window(window); - // Register event handlers. //Added dummy display callback to freeglut. According to freeglut ref, we should register some kind of display callback after freeglut 3.0. @@ -96,7 +96,7 @@ impl WindowMethods<Application> for Window { struct ReshapeCallbackState; impl glut::ReshapeCallback for ReshapeCallbackState { fn call(&self, width: c_int, height: c_int) { - local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint)) + local_window().event_queue.with_mut(|queue| queue.push(ResizeWindowEvent(width as uint, height as uint))) } } glut::reshape_func(glut_window, ~ReshapeCallbackState); @@ -115,10 +115,10 @@ impl WindowMethods<Application> for Window { } else { match button { 3 => { - local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))); + local_window().event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)))); }, 4 => { - local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))); + local_window().event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)))); }, _ => {} } @@ -127,7 +127,11 @@ impl WindowMethods<Application> for Window { } glut::mouse_func(~MouseCallbackState); - window + let wrapped_window = Rc::new(window); + + install_local_window(wrapped_window); + + wrapped_window } /// Returns the size of the window. @@ -136,44 +140,44 @@ impl WindowMethods<Application> for Window { } /// Presents the window to the screen (perhaps by page flipping). - fn present(&mut self) { + fn present(&self) { glut::swap_buffers(); } - fn recv(@mut self) -> WindowEvent { - if !self.event_queue.is_empty() { - return self.event_queue.shift() + fn recv(@self) -> WindowEvent { + if !self.event_queue.with_mut(|queue| queue.is_empty()) { + return self.event_queue.with_mut(|queue| queue.shift()) } glut::check_loop(); - if !self.event_queue.is_empty() { - self.event_queue.shift() + if !self.event_queue.with_mut(|queue| queue.is_empty()) { + self.event_queue.with_mut(|queue| queue.shift()) } else { IdleWindowEvent } } /// Sets the ready state. - fn set_ready_state(@mut self, ready_state: ReadyState) { - self.ready_state = ready_state; + fn set_ready_state(@self, ready_state: ReadyState) { + self.ready_state.set(ready_state); //FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked. //self.update_window_title() } /// Sets the render state. - fn set_render_state(@mut self, render_state: RenderState) { - if self.ready_state == FinishedLoading && - self.render_state == RenderingRenderState && + fn set_render_state(@self, render_state: RenderState) { + if self.ready_state.get() == FinishedLoading && + self.render_state.get() == RenderingRenderState && render_state == IdleRenderState { // page loaded - self.event_queue.push(FinishedWindowEvent); + self.event_queue.with_mut(|queue| queue.push(FinishedWindowEvent)); } - self.render_state = render_state; + self.render_state.set(render_state); //FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked. //self.update_window_title() } - fn hidpi_factor(@mut self) -> f32 { + fn hidpi_factor(@self) -> f32 { //FIXME: Do nothing in GLUT now. 0f32 } @@ -210,16 +214,16 @@ impl Window { let modifiers = glut::get_modifiers(); match key { 42 => self.load_url(), - 43 => self.event_queue.push(ZoomWindowEvent(1.1)), - 45 => self.event_queue.push(ZoomWindowEvent(0.909090909)), - 56 => self.event_queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))), - 50 => self.event_queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))), + 43 => self.event_queue.with_mut(|queue| queue.push(ZoomWindowEvent(1.1))), + 45 => self.event_queue.with_mut(|queue| queue.push(ZoomWindowEvent(0.909090909))), + 56 => self.event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)))), + 50 => self.event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)))), 127 => { if (modifiers & ACTIVE_SHIFT) != 0 { - self.event_queue.push(NavigationWindowEvent(Forward)); + self.event_queue.with_mut(|queue| queue.push(NavigationWindowEvent(Forward))); } else { - self.event_queue.push(NavigationWindowEvent(Back)); + self.event_queue.with_mut(|queue| queue.push(NavigationWindowEvent(Back))); } } _ => {} @@ -232,26 +236,26 @@ impl Window { let max_pixel_dist = 10f32; let event = match state { glut::MOUSE_DOWN => { - *self.mouse_down_point = Point2D(x, y); - *self.mouse_down_button = button; + self.mouse_down_point.set(Point2D(x, y)); + self.mouse_down_button.set(button); MouseWindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32)) } glut::MOUSE_UP => { - if *self.mouse_down_button == button { - let pixel_dist = *self.mouse_down_point - Point2D(x, y); + if self.mouse_down_button.get() == button { + let pixel_dist = self.mouse_down_point.get() - Point2D(x, y); let pixel_dist = ((pixel_dist.x * pixel_dist.x + pixel_dist.y * pixel_dist.y) as f32).sqrt(); if pixel_dist < max_pixel_dist { let click_event = MouseWindowClickEvent(button as uint, Point2D(x as f32, y as f32)); - self.event_queue.push(MouseWindowEventClass(click_event)); + self.event_queue.with_mut(|queue| queue.push(MouseWindowEventClass(click_event))); } } MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32)) } _ => fail!("I cannot recognize the type of mouse action that occured. :-(") }; - self.event_queue.push(MouseWindowEventClass(event)); + self.event_queue.with_mut(|queue| queue.push(MouseWindowEventClass(event))); } /// Helper function to pop up an alert box prompting the user to load a URL. @@ -261,16 +265,16 @@ impl Window { alert.run(); let value = alert.prompt_value(); if "" == value { // To avoid crashing on Linux. - self.event_queue.push(LoadUrlWindowEvent(~"http://purple.com/")) + self.event_queue.with_mut(|queue| queue.push(LoadUrlWindowEvent(~"http://purple.com/"))) } else { - self.event_queue.push(LoadUrlWindowEvent(value)) + self.event_queue.with_mut(|queue| queue.push(LoadUrlWindowEvent(value.clone()))) } } } -static TLS_KEY: local_data::Key<@mut Window> = &local_data::Key; +static TLS_KEY: local_data::Key<Rc<Window>> = &local_data::Key; -fn install_local_window(window: @mut Window) { +fn install_local_window(window: Rc<Window>) { local_data::set(TLS_KEY, window); } @@ -278,6 +282,6 @@ fn drop_local_window() { local_data::pop(TLS_KEY); } -fn local_window() -> @mut Window { - local_data::get(TLS_KEY, |v| *v.unwrap()) +fn local_window() -> Rc<Window> { + local_data::get(TLS_KEY, |v| v.unwrap().clone()) } diff --git a/src/components/main/windowing.rs b/src/components/main/windowing.rs index 690d13c10fa..370cb48ae49 100644 --- a/src/components/main/windowing.rs +++ b/src/components/main/windowing.rs @@ -7,6 +7,7 @@ use geom::point::Point2D; use geom::size::Size2D; use servo_msg::compositor_msg::{ReadyState, RenderState}; +use std::rc::Rc; pub enum MouseWindowEvent { MouseWindowClickEvent(uint, Point2D<f32>), @@ -55,21 +56,21 @@ pub trait ApplicationMethods { pub trait WindowMethods<A> { /// Creates a new window. - fn new(app: &A) -> @mut Self; + fn new(app: &A) -> Rc<Self>; /// Returns the size of the window. fn size(&self) -> Size2D<f32>; /// Presents the window to the screen (perhaps by page flipping). - fn present(&mut self); + fn present(&self); /// Spins the event loop and returns the next event. - fn recv(@mut self) -> WindowEvent; + fn recv(&self) -> WindowEvent; /// Sets the ready state of the current page. - fn set_ready_state(@mut self, ready_state: ReadyState); + fn set_ready_state(&self, ready_state: ReadyState); /// Sets the render state of the current page. - fn set_render_state(@mut self, render_state: RenderState); + fn set_render_state(&self, render_state: RenderState); /// Returns the hidpi factor of the monitor. - fn hidpi_factor(@mut self) -> f32; + fn hidpi_factor(&self) -> f32; } diff --git a/src/components/msg/compositor_msg.rs b/src/components/msg/compositor_msg.rs index c5c02c52098..c1c28d9b467 100644 --- a/src/components/msg/compositor_msg.rs +++ b/src/components/msg/compositor_msg.rs @@ -45,13 +45,13 @@ impl LayerBufferSet { } /// The status of the renderer. -#[deriving(Eq)] +#[deriving(Eq, Clone)] pub enum RenderState { IdleRenderState, RenderingRenderState, } -#[deriving(Eq)] +#[deriving(Eq, Clone)] pub enum ReadyState { /// Informs the compositor that nothing has been done yet. Used for setting status Blank, diff --git a/src/components/script/dom/bindings/codegen/Bindings.conf b/src/components/script/dom/bindings/codegen/Bindings.conf index d0eccd1334c..b45eca71ba8 100644 --- a/src/components/script/dom/bindings/codegen/Bindings.conf +++ b/src/components/script/dom/bindings/codegen/Bindings.conf @@ -328,6 +328,7 @@ DOMInterfaces = { 'textContent', 'childNodes', 'contains', + 'isEqualNode', ] }, diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index b52800eed52..81527995030 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -164,6 +164,7 @@ impl Document { } impl Document { + // http://dom.spec.whatwg.org/#dom-document pub fn Constructor(owner: @mut Window) -> Fallible<AbstractDocument> { Ok(Document::new(owner, None, XML, None)) } @@ -234,26 +235,32 @@ impl Document { self.content_type.clone() } + // http://dom.spec.whatwg.org/#dom-document-doctype pub fn GetDoctype(&self) -> Option<AbstractNode> { self.node.children().find(|child| child.is_doctype()) } + // http://dom.spec.whatwg.org/#dom-document-documentelement pub fn GetDocumentElement(&self) -> Option<AbstractNode> { self.node.child_elements().next() } + // http://dom.spec.whatwg.org/#dom-document-getelementsbytagname pub fn GetElementsByTagName(&self, tag: DOMString) -> @mut HTMLCollection { self.createHTMLCollection(|elem| eq_slice(elem.tag_name, tag)) } + // http://dom.spec.whatwg.org/#dom-document-getelementsbytagnamens pub fn GetElementsByTagNameNS(&self, _ns: Option<DOMString>, _tag: DOMString) -> @mut HTMLCollection { HTMLCollection::new(self.window, ~[]) } + // http://dom.spec.whatwg.org/#dom-document-getelementsbyclassname pub fn GetElementsByClassName(&self, _class: DOMString) -> @mut HTMLCollection { HTMLCollection::new(self.window, ~[]) } + // http://dom.spec.whatwg.org/#dom-nonelementparentnode-getelementbyid pub fn GetElementById(&self, id: DOMString) -> Option<AbstractNode> { // TODO: "in tree order, within the context object's tree" // http://dom.spec.whatwg.org/#dom-document-getelementbyid. @@ -263,6 +270,7 @@ impl Document { } } + // http://dom.spec.whatwg.org/#dom-document-createelement pub fn CreateElement(&self, abstract_self: AbstractDocument, local_name: DOMString) -> Fallible<AbstractNode> { if xml_name_type(local_name) == InvalidXMLName { @@ -273,15 +281,18 @@ impl Document { Ok(build_element_from_tag(local_name, abstract_self)) } + // http://dom.spec.whatwg.org/#dom-document-createdocumentfragment pub fn CreateDocumentFragment(&self, abstract_self: AbstractDocument) -> AbstractNode { DocumentFragment::new(abstract_self) } + // http://dom.spec.whatwg.org/#dom-document-createtextnode pub fn CreateTextNode(&self, abstract_self: AbstractDocument, data: DOMString) -> AbstractNode { Text::new(data, abstract_self) } + // http://dom.spec.whatwg.org/#dom-document-createcomment pub fn CreateComment(&self, abstract_self: AbstractDocument, data: DOMString) -> AbstractNode { Comment::new(data, abstract_self) } @@ -303,6 +314,7 @@ impl Document { Ok(ProcessingInstruction::new(target, data, abstract_self)) } + // http://dom.spec.whatwg.org/#dom-document-createevent pub fn CreateEvent(&self, interface: DOMString) -> Fallible<AbstractEvent> { match interface.as_slice() { "UIEvents" => Ok(UIEvent::new(self.window)), @@ -312,6 +324,7 @@ impl Document { } } + // http://www.whatwg.org/specs/web-apps/current-work/#document.title pub fn Title(&self, _: AbstractDocument) -> DOMString { let mut title = ~""; match self.doctype { @@ -345,6 +358,7 @@ impl Document { title } + // http://www.whatwg.org/specs/web-apps/current-work/#document.title pub fn SetTitle(&self, abstract_self: AbstractDocument, title: DOMString) -> ErrorResult { match self.doctype { SVG => { @@ -451,6 +465,7 @@ impl Document { Ok(()) } + // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-getelementsbyname pub fn GetElementsByName(&self, name: DOMString) -> @mut HTMLCollection { self.createHTMLCollection(|elem| elem.get_attribute(Null, "name").is_some() && eq_slice(elem.get_attribute(Null, "name").unwrap().value_ref(), name)) diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index 5cca4c0cbcf..c295b5e28cd 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -548,7 +548,7 @@ 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() } @@ -559,14 +559,17 @@ impl<'a> AbstractNode { } impl AbstractNode { + // http://dom.spec.whatwg.org/#dom-node-appendchild pub fn AppendChild(self, node: AbstractNode) -> Fallible<AbstractNode> { self.node().AppendChild(self, node) } + // http://dom.spec.whatwg.org/#dom-node-replacechild pub fn ReplaceChild(self, node: AbstractNode, child: AbstractNode) -> Fallible<AbstractNode> { self.node().ReplaceChild(self, node, child) } + // http://dom.spec.whatwg.org/#dom-node-removechild pub fn RemoveChild(self, node: AbstractNode) -> Fallible<AbstractNode> { self.node().RemoveChild(self, node) } @@ -951,6 +954,7 @@ impl Node { } } + // http://dom.spec.whatwg.org/#dom-node-nodename pub fn NodeName(&self, abstract_self: AbstractNode) -> DOMString { match self.type_id { ElementNodeTypeId(..) => { @@ -975,10 +979,12 @@ impl Node { } } + // http://dom.spec.whatwg.org/#dom-node-baseuri pub fn GetBaseURI(&self) -> Option<DOMString> { None } + // http://dom.spec.whatwg.org/#dom-node-ownerdocument pub fn GetOwnerDocument(&self) -> Option<AbstractDocument> { match self.type_id { ElementNodeTypeId(..) | @@ -991,34 +997,42 @@ impl Node { } } + // http://dom.spec.whatwg.org/#dom-node-parentnode pub fn GetParentNode(&self) -> Option<AbstractNode> { self.parent_node } + // http://dom.spec.whatwg.org/#dom-node-parentelement pub fn GetParentElement(&self) -> Option<AbstractNode> { self.parent_node.filtered(|parent| parent.is_element()) } + // http://dom.spec.whatwg.org/#dom-node-haschildnodes pub fn HasChildNodes(&self) -> bool { self.first_child.is_some() } + // http://dom.spec.whatwg.org/#dom-node-firstchild pub fn GetFirstChild(&self) -> Option<AbstractNode> { self.first_child } + // http://dom.spec.whatwg.org/#dom-node-lastchild pub fn GetLastChild(&self) -> Option<AbstractNode> { self.last_child } + // http://dom.spec.whatwg.org/#dom-node-previoussibling pub fn GetPreviousSibling(&self) -> Option<AbstractNode> { self.prev_sibling } + // http://dom.spec.whatwg.org/#dom-node-nextsibling pub fn GetNextSibling(&self) -> Option<AbstractNode> { self.next_sibling } + // http://dom.spec.whatwg.org/#dom-node-nodevalue pub fn GetNodeValue(&self, abstract_self: AbstractNode) -> Option<DOMString> { match self.type_id { CommentNodeTypeId | @@ -1034,11 +1048,14 @@ impl Node { } } + // http://dom.spec.whatwg.org/#dom-node-nodevalue pub fn SetNodeValue(&mut self, _abstract_self: AbstractNode, _val: Option<DOMString>) -> ErrorResult { + // FIXME: Stub - https://github.com/mozilla/servo/issues/1655 Ok(()) } + // http://dom.spec.whatwg.org/#dom-node-textcontent pub fn GetTextContent(&self, abstract_self: AbstractNode) -> Option<DOMString> { match self.type_id { DocumentFragmentNodeTypeId | @@ -1067,6 +1084,7 @@ impl Node { } } + // http://dom.spec.whatwg.org/#dom-node-childnodes pub fn ChildNodes(&mut self, abstract_self: AbstractNode) -> @mut NodeList { match self.child_list { None => { @@ -1350,6 +1368,7 @@ impl Node { } } + // http://dom.spec.whatwg.org/#dom-node-textcontent pub fn SetTextContent(&mut self, abstract_self: AbstractNode, value: Option<DOMString>) -> ErrorResult { let value = null_str_as_empty(&value); @@ -1385,6 +1404,7 @@ impl Node { Ok(()) } + // http://dom.spec.whatwg.org/#dom-node-insertbefore pub fn InsertBefore(&self, abstract_self: AbstractNode, node: AbstractNode, child: Option<AbstractNode>) -> Fallible<AbstractNode> { Node::pre_insert(node, abstract_self, child) @@ -1395,6 +1415,7 @@ impl Node { document.document().wait_until_safe_to_modify_dom(); } + // http://dom.spec.whatwg.org/#dom-node-appendchild pub fn AppendChild(&self, abstract_self: AbstractNode, node: AbstractNode) -> Fallible<AbstractNode> { Node::pre_insert(node, abstract_self, None) @@ -1528,26 +1549,114 @@ impl Node { Ok(child) } + // http://dom.spec.whatwg.org/#dom-node-removechild pub fn RemoveChild(&self, abstract_self: AbstractNode, node: AbstractNode) -> Fallible<AbstractNode> { Node::pre_remove(node, abstract_self) } + // http://dom.spec.whatwg.org/#dom-node-normalize pub fn Normalize(&mut self) { + // FIXME: stub - https://github.com/mozilla/servo/issues/1655 } + // http://dom.spec.whatwg.org/#dom-node-clonenode pub fn CloneNode(&self, _deep: bool) -> Fallible<AbstractNode> { + // FIXME: stub - https://github.com/mozilla/servo/issues/1240 fail!("stub") } - pub fn IsEqualNode(&self, _node: Option<AbstractNode>) -> bool { - false + // http://dom.spec.whatwg.org/#dom-node-isequalnode + pub fn IsEqualNode(&self, abstract_self: AbstractNode, maybe_node: Option<AbstractNode>) -> bool { + fn is_equal_doctype(node: AbstractNode, other: AbstractNode) -> bool { + node.with_imm_doctype(|doctype| { + other.with_imm_doctype(|other_doctype| { + (doctype.name == other_doctype.name) && + (doctype.public_id == other_doctype.public_id) && + (doctype.system_id == other_doctype.system_id) + }) + }) + } + fn is_equal_element(node: AbstractNode, other: AbstractNode) -> bool { + node.with_imm_element(|element| { + other.with_imm_element(|other_element| { + // FIXME: namespace prefix + (element.namespace == other_element.namespace) && + (element.tag_name == other_element.tag_name) && + (element.attrs.len() == other_element.attrs.len()) + }) + }) + } + fn is_equal_processinginstruction(node: AbstractNode, other: AbstractNode) -> bool { + node.with_imm_processing_instruction(|pi| { + other.with_imm_processing_instruction(|other_pi| { + (pi.target == other_pi.target) && + (pi.element.data == other_pi.element.data) + }) + }) + } + fn is_equal_characterdata(node: AbstractNode, other: AbstractNode) -> bool { + node.with_imm_characterdata(|characterdata| { + other.with_imm_characterdata(|other_characterdata| { + characterdata.data == other_characterdata.data + }) + }) + } + fn is_equal_element_attrs(node: AbstractNode, other: AbstractNode) -> bool { + node.with_imm_element(|element| { + other.with_imm_element(|other_element| { + assert!(element.attrs.len() == other_element.attrs.len()); + element.attrs.iter().all(|attr| { + other_element.attrs.iter().any(|other_attr| { + (attr.namespace == other_attr.namespace) && + (attr.local_name == other_attr.local_name) && + (attr.value == other_attr.value) + }) + }) + }) + }) + } + fn is_equal_node(this: AbstractNode, node: AbstractNode) -> bool { + // Step 2. + if this.type_id() != node.type_id() { + return false; + } + + match node.type_id() { + // Step 3. + DoctypeNodeTypeId if !is_equal_doctype(this, node) => return false, + ElementNodeTypeId(..) if !is_equal_element(this, node) => return false, + ProcessingInstructionNodeTypeId if !is_equal_processinginstruction(this, node) => return false, + TextNodeTypeId | + CommentNodeTypeId if !is_equal_characterdata(this, node) => return false, + // Step 4. + ElementNodeTypeId(..) if !is_equal_element_attrs(this, node) => return false, + _ => () + } + + // Step 5. + if this.children().len() != node.children().len() { + return false; + } + + // Step 6. + this.children().zip(node.children()).all(|(child, other_child)| is_equal_node(child, other_child)) + } + match maybe_node { + // Step 1. + None => false, + // Step 2-6. + Some(node) => is_equal_node(abstract_self, node) + } } + // http://dom.spec.whatwg.org/#dom-node-comparedocumentposition pub fn CompareDocumentPosition(&self, _other: AbstractNode) -> u16 { + // FIXME: stub - https://github.com/mozilla/servo/issues/1655 0 } + // http://dom.spec.whatwg.org/#dom-node-contains pub fn Contains(&self, abstract_self: AbstractNode, maybe_other: Option<AbstractNode>) -> bool { match maybe_other { None => false, @@ -1555,35 +1664,44 @@ impl Node { } } + // http://dom.spec.whatwg.org/#dom-node-lookupprefix pub fn LookupPrefix(&self, _prefix: Option<DOMString>) -> Option<DOMString> { + // FIXME: stub - https://github.com/mozilla/servo/issues/1655 None } + // http://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri pub fn LookupNamespaceURI(&self, _namespace: Option<DOMString>) -> Option<DOMString> { + // FIXME: stub - https://github.com/mozilla/servo/issues/1655 None } + // http://dom.spec.whatwg.org/#dom-node-isdefaultnamespace pub fn IsDefaultNamespace(&self, _namespace: Option<DOMString>) -> bool { + // FIXME: stub - https://github.com/mozilla/servo/issues/1655 false } + // http://dom.spec.whatwg.org/#dom-node-namespaceuri pub fn GetNamespaceURI(&self) -> Option<DOMString> { None } + // http://dom.spec.whatwg.org/#dom-node-prefix pub fn GetPrefix(&self) -> Option<DOMString> { None } + // http://dom.spec.whatwg.org/#dom-node-localname pub fn GetLocalName(&self) -> Option<DOMString> { None } + // http://dom.spec.whatwg.org/#dom-node-hasattributes pub fn HasAttributes(&self) -> bool { false } - // // Low-level pointer stitching // diff --git a/src/components/script/dom/webidls/Node.webidl b/src/components/script/dom/webidls/Node.webidl index ba48fd94e11..c81a4228ae2 100644 --- a/src/components/script/dom/webidls/Node.webidl +++ b/src/components/script/dom/webidls/Node.webidl @@ -69,7 +69,7 @@ interface Node : EventTarget { [Throws] Node cloneNode(optional boolean deep = true); - // boolean isEqualNode(Node? node); //XXXjdm we don't deal well with Node? parameters + boolean isEqualNode(Node? node); const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01; const unsigned short DOCUMENT_POSITION_PRECEDING = 0x02; diff --git a/src/components/style/selectors.rs b/src/components/style/selectors.rs index 1c92f4b4568..144ebe593ef 100644 --- a/src/components/style/selectors.rs +++ b/src/components/style/selectors.rs @@ -93,8 +93,13 @@ pub enum SimpleSelector { pub struct AttrSelector { name: ~str, lower_name: ~str, - /// None means "any namespace", `*|attr` - namespace: Option<Namespace>, + namespace: NamespaceConstraint, +} + +#[deriving(Eq, Clone)] +pub enum NamespaceConstraint { + AnyNamespace, + SpecificNamespace(Namespace), } @@ -269,14 +274,14 @@ enum TypeSelectorParseResult { fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap) -> TypeSelectorParseResult { skip_whitespace(iter); - match parse_qualified_name(iter, /* allow_universal = */ true, namespaces) { + match parse_qualified_name(iter, /* in_attr_selector = */ false, namespaces) { InvalidQualifiedName => InvalidTypeSelector, NotAQualifiedName => NotATypeSelector, QualifiedName(namespace, local_name) => { let mut simple_selectors = ~[]; match namespace { - Some(ns) => simple_selectors.push(NamespaceSelector(ns)), - None => (), + SpecificNamespace(ns) => simple_selectors.push(NamespaceSelector(ns)), + AnyNamespace => (), } match local_name { Some(name) => simple_selectors.push(LocalNameSelector(name)), @@ -363,24 +368,27 @@ enum QualifiedNameParseResult { InvalidQualifiedName, NotAQualifiedName, // Namespace URL, local name. None means '*' - QualifiedName(Option<Namespace>, Option<~str>) + QualifiedName(NamespaceConstraint, Option<~str>) } -fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &NamespaceMap) +fn parse_qualified_name(iter: &mut Iter, in_attr_selector: bool, namespaces: &NamespaceMap) -> QualifiedNameParseResult { #[inline] fn default_namespace(namespaces: &NamespaceMap, local_name: Option<~str>) -> QualifiedNameParseResult { - QualifiedName(namespaces.default.as_ref().map(|ns| ns.clone()), local_name) + QualifiedName(match namespaces.default { + Some(ref ns) => SpecificNamespace(ns.clone()), + None => AnyNamespace, + }, local_name) } #[inline] - fn explicit_namespace(iter: &mut Iter, allow_universal: bool, namespace: Option<Namespace>) + fn explicit_namespace(iter: &mut Iter, in_attr_selector: bool, namespace: NamespaceConstraint) -> QualifiedNameParseResult { assert!(iter.next() == Some(Delim('|')), "Implementation error, this should not happen."); match iter.peek() { - Some(&Delim('*')) if allow_universal => { + Some(&Delim('*')) if !in_attr_selector => { iter.next(); QualifiedName(namespace, None) }, @@ -401,22 +409,25 @@ fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &Nam None => return InvalidQualifiedName, // Undeclared namespace prefix Some(ref ns) => (*ns).clone(), }; - explicit_namespace(iter, allow_universal, Some(namespace)) + explicit_namespace(iter, in_attr_selector, SpecificNamespace(namespace)) }, + _ if in_attr_selector => QualifiedName( + SpecificNamespace(namespace::Null), Some(value)), _ => default_namespace(namespaces, Some(value)), } }, Some(&Delim('*')) => { iter.next(); // Consume '*' match iter.peek() { - Some(&Delim('|')) => explicit_namespace(iter, allow_universal, None), + Some(&Delim('|')) => explicit_namespace(iter, in_attr_selector, AnyNamespace), _ => { - if allow_universal { default_namespace(namespaces, None) } + if !in_attr_selector { default_namespace(namespaces, None) } else { InvalidQualifiedName } }, } }, - Some(&Delim('|')) => explicit_namespace(iter, allow_universal, Some(namespace::Null)), + Some(&Delim('|')) => explicit_namespace( + iter, in_attr_selector, SpecificNamespace(namespace::Null)), _ => NotAQualifiedName, } } @@ -425,7 +436,7 @@ fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &Nam fn parse_attribute_selector(content: ~[ComponentValue], namespaces: &NamespaceMap) -> Option<SimpleSelector> { let iter = &mut content.move_iter().peekable(); - let attr = match parse_qualified_name(iter, /* allow_universal = */ false, namespaces) { + let attr = match parse_qualified_name(iter, /* in_attr_selector = */ true, namespaces) { InvalidQualifiedName | NotAQualifiedName => return None, QualifiedName(_, None) => fail!("Implementation error, this should not happen."), QualifiedName(namespace, Some(local_name)) => AttrSelector { @@ -568,13 +579,18 @@ fn skip_whitespace(iter: &mut Iter) -> bool { mod tests { use extra::arc::Arc; use cssparser; + use servo_util::namespace; use namespaces::NamespaceMap; use super::*; fn parse(input: &str) -> Option<~[Selector]> { + parse_ns(input, &NamespaceMap::new()) + } + + fn parse_ns(input: &str, namespaces: &NamespaceMap) -> Option<~[Selector]> { parse_selector_list( cssparser::tokenize(input).map(|(v, _)| v).to_owned_vec(), - &NamespaceMap::new()) + namespaces) } fn specificity(a: u32, b: u32, c: u32) -> u32 { @@ -630,5 +646,46 @@ mod tests { pseudo_element: None, specificity: specificity(1, 1, 1), }])) + // Default namespace does not apply to attribute selectors + let mut namespaces = NamespaceMap::new(); + assert_eq!(parse_ns("[Foo]", &namespaces), Some(~[Selector{ + compound_selectors: Arc::new(CompoundSelector { + simple_selectors: ~[AttrExists(AttrSelector { + name: ~"Foo", + lower_name: ~"foo", + namespace: SpecificNamespace(namespace::Null), + })], + next: None, + }), + pseudo_element: None, + specificity: specificity(0, 1, 0), + }])) + // Default namespace does not apply to attribute selectors + namespaces.default = Some(namespace::MathML); + assert_eq!(parse_ns("[Foo]", &namespaces), Some(~[Selector{ + compound_selectors: Arc::new(CompoundSelector { + simple_selectors: ~[AttrExists(AttrSelector { + name: ~"Foo", + lower_name: ~"foo", + namespace: SpecificNamespace(namespace::Null), + })], + next: None, + }), + pseudo_element: None, + specificity: specificity(0, 1, 0), + }])) + // Default namespace does apply to type selectors + assert_eq!(parse_ns("e", &namespaces), Some(~[Selector{ + compound_selectors: Arc::new(CompoundSelector { + simple_selectors: ~[ + NamespaceSelector(namespace::MathML), + LocalNameSelector(~"e"), + ], + next: None, + }), + pseudo_element: None, + specificity: specificity(0, 0, 1), + }])) + } } diff --git a/src/components/style/style.rs b/src/components/style/style.rs index c5ae2428064..afd3787436d 100644 --- a/src/components/style/style.rs +++ b/src/components/style/style.rs @@ -23,7 +23,7 @@ pub use properties::{cascade, PropertyDeclaration, ComputedValues, computed_valu pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes pub use errors::with_errors_silenced; pub use node::{TElement, TNode}; -pub use selectors::{PseudoElement, Before, After, AttrSelector}; +pub use selectors::{PseudoElement, Before, After, AttrSelector, SpecificNamespace, AnyNamespace}; mod stylesheets; mod errors; diff --git a/src/test/html/content/test_node_isEqualNode.html b/src/test/html/content/test_node_isEqualNode.html new file mode 100644 index 00000000000..e7c55743725 --- /dev/null +++ b/src/test/html/content/test_node_isEqualNode.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html> + <head> + <script src="harness.js"></script> + <script> + // test1: simple checks + { + var elem = document.createElement("div"); + var other = document.createElement("div"); + is(elem.isEqualNode(elem), true); + is(elem.isEqualNode(other), true); + is(other.isEqualNode(elem), true); + is(elem.isEqualNode(document), false); + } + + // test2: non-element children + { + var parent_elem = document.createElement("div"); + var child_elem = document.createElement("div"); + parent_elem.appendChild(child_elem); + + var other_parent = document.createElement("div"); + var other_child = document.createElement("div"); + other_parent.appendChild(other_child); + + is(parent_elem.isEqualNode(other_parent), true); + is(child_elem.isEqualNode(other_child), true); + + var child_text = document.createTextNode("lorem ipsum"); + child_elem.appendChild(child_text); + + is(parent_elem.isEqualNode(other_parent), false); + is(child_elem.isEqualNode(other_child), false); + } + + finish(); + </script> + </head> +</html> diff --git a/src/test/ref/attr_exists_selector.html b/src/test/ref/attr_exists_selector.html new file mode 100644 index 00000000000..6d8f01e16aa --- /dev/null +++ b/src/test/ref/attr_exists_selector.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> + <head> + <title>Attribute exists selector: [foo]</title> + <style> + p[data-green] { color: green } + </style> + </head> + <body> + <p data-green="">This text should be green.</p> + <p>This text should be black.</p> + </body> +</html> diff --git a/src/test/ref/attr_exists_selector_ref.html b/src/test/ref/attr_exists_selector_ref.html new file mode 100644 index 00000000000..522883d8ed4 --- /dev/null +++ b/src/test/ref/attr_exists_selector_ref.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> + <head> + <title>Attribute exists selector: [foo] (reference)</title> + </head> + <body> + <p style="color: green">This text should be green.</p> + <p>This text should be black.</p> + </body> +</html> diff --git a/src/test/ref/basic.list b/src/test/ref/basic.list index 8f6d3fb4f68..16ff2c93568 100644 --- a/src/test/ref/basic.list +++ b/src/test/ref/basic.list @@ -27,3 +27,4 @@ # inline_border_a.html inline_border_b.html == anon_block_inherit_a.html anon_block_inherit_b.html == position_relative_a.html position_relative_b.html +== attr_exists_selector.html attr_exists_selector_ref.html |