Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement MutNullableJS for mutable, nullable member pointers to DOM objects. #3531

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Implement MutNullableJS for mutable, nullable member pointers to DOM …

…objects.
  • Loading branch information
jdm authored and Ms2ger committed Oct 1, 2014
commit 54fcab61d61533ce4de5436c8721aa7548f8509d
@@ -54,6 +54,7 @@ use layout_interface::TrustedNodeAddress;
use script_task::StackRoots;

use std::cell::{Cell, RefCell};
use std::default::Default;
use std::kinds::marker::ContravariantLifetime;
use std::mem;

@@ -192,6 +193,62 @@ impl<T: Reflectable> Reflectable for JS<T> {
}
}

/// A mutable `JS<T>` value, with nullability represented by an enclosing
/// Option wrapper. Must be used in place of traditional internal mutability
/// to ensure that the proper GC barriers are enforced.
#[must_root]
#[jstraceable]
pub struct MutNullableJS<T: Reflectable> {
ptr: Cell<Option<JS<T>>>
}

impl<T: Assignable<U>, U: Reflectable> MutNullableJS<U> {
pub fn new(initial: Option<T>) -> MutNullableJS<U> {
MutNullableJS {
ptr: Cell::new(initial.map(|initial| {
unsafe { initial.get_js() }
}))
}
}
}

impl<T: Reflectable> Default for MutNullableJS<T> {
fn default() -> MutNullableJS<T> {
MutNullableJS {
ptr: Cell::new(None)
}
}
}

impl<T: Reflectable> MutNullableJS<T> {
/// Store an unrooted value in this field. This is safe under the
/// assumption that `MutNullableJS<T>` values are only used as fields in
/// DOM types that are reachable in the GC graph, so this unrooted value
/// becomes transitively rooted for the lifetime of its new owner.
pub fn assign<U: Assignable<T>>(&self, val: Option<U>) {
self.ptr.set(val.map(|val| {
unsafe { val.get_js() }
}));
}

/// Set the inner value to null, without making API users jump through
/// useless type-ascription hoops.
pub fn clear(&self) {
self.assign(None::<JS<T>>);
}

/// Retrieve a copy of the current optional inner value.
pub fn get(&self) -> Option<Temporary<T>> {
self.ptr.get().map(Temporary::new)
}

/// Retrieve a copy of the inner optional `JS<T>`. For use by layout, which
/// can't use safe types like Temporary.
pub unsafe fn get_inner(&self) -> Option<JS<T>> {
self.ptr.get()
}
}

impl<T: Reflectable> JS<T> {
/// Returns an unsafe pointer to the interior of this JS object without touching the borrow
/// flags. This is the only method that be safely accessed from layout. (The fact that this
@@ -245,7 +302,7 @@ impl<'a, 'b, T: Reflectable> OptionalRootedReference<T> for Option<Option<Root<'
/// Trait that allows extracting a `JS<T>` value from a variety of rooting-related containers,
/// which in general is an unsafe operation since they can outlive the rooted lifetime of the
/// original value.
/*definitely not public*/ trait Assignable<T> {
pub trait Assignable<T> {
unsafe fn get_js(&self) -> JS<T>;
}

@@ -21,7 +21,7 @@ use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter
use dom::bindings::error::{HierarchyRequest, NamespaceError};
use dom::bindings::global::GlobalRef;
use dom::bindings::global;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, TemporaryPushable};
use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, OptionalSettable, TemporaryPushable};
use dom::bindings::js::OptionalRootable;
use dom::bindings::trace::{Traceable, Untraceable};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
@@ -57,12 +57,14 @@ use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks};
use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage};
use servo_util::namespace;
use servo_util::str::{DOMString, split_html_space_chars};

use string_cache::Atom;
use url::Url;

use std::collections::hashmap::HashMap;
use std::ascii::StrAsciiExt;
use std::cell::{Cell, RefCell};
use url::Url;
use std::default::Default;
use time;

#[deriving(PartialEq)]
@@ -79,7 +81,7 @@ pub struct Document {
reflector_: Reflector,
pub window: JS<Window>,
idmap: Traceable<RefCell<HashMap<Atom, Vec<JS<Element>>>>>,
implementation: Cell<Option<JS<DOMImplementation>>>,
implementation: MutNullableJS<DOMImplementation>,
content_type: DOMString,
last_modified: Traceable<RefCell<Option<DOMString>>>,
pub encoding_name: Traceable<RefCell<DOMString>>,
@@ -288,7 +290,7 @@ impl Document {
reflector_: Reflector::new(),
window: JS::from_rooted(window),
idmap: Traceable::new(RefCell::new(HashMap::new())),
implementation: Cell::new(None),
implementation: Default::default(),
content_type: match content_type {
Some(string) => string.clone(),
None => match is_html_document {
@@ -382,7 +384,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
if self.implementation.get().is_none() {
self.implementation.assign(Some(DOMImplementation::new(self)));
}
Temporary::new(self.implementation.get().as_ref().unwrap().clone())
self.implementation.get().unwrap()
}

// http://dom.spec.whatwg.org/#dom-document-url
@@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::ElementBinding;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
use dom::bindings::codegen::InheritTypes::{ElementDerived, NodeCast};
use dom::bindings::js::{JS, JSRef, Temporary, TemporaryPushable};
use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable};
use dom::bindings::js::{OptionalSettable, OptionalRootable, Root};
use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector};
@@ -38,7 +38,8 @@ use servo_util::namespace;
use servo_util::str::DOMString;

use std::ascii::StrAsciiExt;
use std::cell::{Cell, RefCell};
use std::cell::RefCell;
use std::default::Default;
use std::mem;
use string_cache::{Atom, Namespace};

@@ -51,8 +52,8 @@ pub struct Element {
pub prefix: Option<DOMString>,
pub attrs: RefCell<Vec<JS<Attr>>>,
pub style_attribute: Traceable<RefCell<Option<style::PropertyDeclarationBlock>>>,
pub attr_list: Cell<Option<JS<NamedNodeMap>>>,
class_list: Cell<Option<JS<DOMTokenList>>>,
pub attr_list: MutNullableJS<NamedNodeMap>,
class_list: MutNullableJS<DOMTokenList>,
}

impl ElementDerived for EventTarget {
@@ -156,8 +157,8 @@ impl Element {
namespace: namespace,
prefix: prefix,
attrs: RefCell::new(vec!()),
attr_list: Cell::new(None),
class_list: Cell::new(None),
attr_list: Default::default(),
class_list: Default::default(),
style_attribute: Traceable::new(RefCell::new(None)),
}
}
@@ -557,31 +558,25 @@ impl<'a> ElementMethods for JSRef<'a, Element> {

// http://dom.spec.whatwg.org/#dom-element-classlist
fn ClassList(self) -> Temporary<DOMTokenList> {
match self.class_list.get() {
Some(class_list) => Temporary::new(class_list),
None => {
let class_list = DOMTokenList::new(self, "class").root();
self.class_list.assign(Some(class_list.deref().clone()));
Temporary::from_rooted(*class_list)
}
if self.class_list.get().is_none() {
let class_list = DOMTokenList::new(self, "class");
self.class_list.assign(Some(class_list));
}
self.class_list.get().unwrap()
}

// http://dom.spec.whatwg.org/#dom-element-attributes
fn Attributes(self) -> Temporary<NamedNodeMap> {
match self.attr_list.get() {
None => (),
Some(ref list) => return Temporary::new(list.clone()),
if self.attr_list.get().is_none() {
let doc = {
let node: JSRef<Node> = NodeCast::from_ref(self);
node.owner_doc().root()
};
let window = doc.deref().window.root();
let list = NamedNodeMap::new(*window, self);
self.attr_list.assign(Some(list));
}

let doc = {
let node: JSRef<Node> = NodeCast::from_ref(self);
node.owner_doc().root()
};
let window = doc.deref().window.root();
let list = NamedNodeMap::new(*window, self);
self.attr_list.assign(Some(list));
Temporary::new(self.attr_list.get().as_ref().unwrap().clone())
self.attr_list.get().unwrap()
}

// http://dom.spec.whatwg.org/#dom-element-getattribute
@@ -6,12 +6,13 @@ use dom::bindings::codegen::Bindings::EventBinding;
use dom::bindings::codegen::Bindings::EventBinding::{EventConstants, EventMethods};
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::js::{MutNullableJS, JSRef, Temporary};
use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::eventtarget::EventTarget;
use servo_util::str::DOMString;
use std::cell::{Cell, RefCell};
use std::default::Default;

use time;

@@ -40,8 +41,8 @@ pub enum EventTypeId {
pub struct Event {
pub type_id: EventTypeId,
reflector_: Reflector,
pub current_target: Cell<Option<JS<EventTarget>>>,
pub target: Cell<Option<JS<EventTarget>>>,
pub current_target: MutNullableJS<EventTarget>,
pub target: MutNullableJS<EventTarget>,
type_: Traceable<RefCell<DOMString>>,
pub phase: Traceable<Cell<EventPhase>>,
pub canceled: Traceable<Cell<bool>>,
@@ -60,8 +61,8 @@ impl Event {
Event {
type_id: type_id,
reflector_: Reflector::new(),
current_target: Cell::new(None),
target: Cell::new(None),
current_target: Default::default(),
target: Default::default(),
phase: Traceable::new(Cell::new(PhaseNone)),
type_: Traceable::new(RefCell::new("".to_string())),
canceled: Traceable::new(Cell::new(false)),
@@ -108,11 +109,11 @@ impl<'a> EventMethods for JSRef<'a, Event> {
}

fn GetTarget(self) -> Option<Temporary<EventTarget>> {
self.target.get().as_ref().map(|target| Temporary::new(target.clone()))
self.target.get()
}

fn GetCurrentTarget(self) -> Option<Temporary<EventTarget>> {
self.current_target.get().as_ref().map(|target| Temporary::new(target.clone()))
self.current_target.get()
}

fn DefaultPrevented(self) -> bool {
@@ -158,7 +159,7 @@ impl<'a> EventMethods for JSRef<'a, Event> {
self.stop_immediate.deref().set(false);
self.canceled.deref().set(false);
self.trusted.deref().set(false);
self.target.set(None);
self.target.clear();
*self.type_.deref().borrow_mut() = type_;
self.bubbles.deref().set(bubbles);
self.cancelable.deref().set(cancelable);
@@ -133,7 +133,7 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>,

event.dispatching.deref().set(false);
event.phase.deref().set(PhaseNone);
event.current_target.set(None);
event.current_target.clear();

!event.DefaultPrevented()
}
@@ -9,7 +9,7 @@ use dom::bindings::codegen::InheritTypes::{UIEventCast, MouseEventDerived};
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::global;
use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, OptionalSettable};
use dom::bindings::js::{MutNullableJS, JSRef, RootedReference, Temporary, OptionalSettable};
use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::event::{Event, MouseEventTypeId};
@@ -18,6 +18,7 @@ use dom::uievent::UIEvent;
use dom::window::Window;
use servo_util::str::DOMString;
use std::cell::Cell;
use std::default::Default;

#[jstraceable]
#[must_root]
@@ -32,7 +33,7 @@ pub struct MouseEvent {
pub alt_key: Traceable<Cell<bool>>,
pub meta_key: Traceable<Cell<bool>>,
pub button: Traceable<Cell<i16>>,
pub related_target: Cell<Option<JS<EventTarget>>>
pub related_target: MutNullableJS<EventTarget>
}

impl MouseEventDerived for Event {
@@ -54,7 +55,7 @@ impl MouseEvent {
alt_key: Traceable::new(Cell::new(false)),
meta_key: Traceable::new(Cell::new(false)),
button: Traceable::new(Cell::new(0)),
related_target: Cell::new(None)
related_target: Default::default(),
}
}

@@ -142,7 +143,7 @@ impl<'a> MouseEventMethods for JSRef<'a, MouseEvent> {
}

fn GetRelatedTarget(self) -> Option<Temporary<EventTarget>> {
self.related_target.get().clone().map(|target| Temporary::new(target))
self.related_target.get()
}

fn InitMouseEvent(self,
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.