aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/main/compositing/compositor.rs20
-rw-r--r--src/components/main/layout/wrapper.rs9
-rw-r--r--src/components/main/platform/common/glfw_windowing.rs127
-rw-r--r--src/components/main/platform/common/glut_windowing.rs108
-rw-r--r--src/components/main/windowing.rs13
-rw-r--r--src/components/msg/compositor_msg.rs4
-rw-r--r--src/components/script/dom/bindings/codegen/Bindings.conf1
-rw-r--r--src/components/script/dom/document.rs15
-rw-r--r--src/components/script/dom/node.rs126
-rw-r--r--src/components/script/dom/webidls/Node.webidl2
-rw-r--r--src/components/style/selectors.rs89
-rw-r--r--src/components/style/style.rs2
-rw-r--r--src/test/html/content/test_node_isEqualNode.html39
-rw-r--r--src/test/ref/attr_exists_selector.html13
-rw-r--r--src/test/ref/attr_exists_selector_ref.html10
-rw-r--r--src/test/ref/basic.list1
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