mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Several orthogonal changes that all got tangled up:
* Split ClientRect, ClientRectList, and HTMLCollection blobs into separate DOM implementation and binding-related files. * Enforce wrapper initialization at creation time for all DOM objects * Set up the basis for triggering reflow on DOM changes, such as Element.setAttribute * Fix crashes stemming from storing pointers to stack-local AbstractNode objects in DOM node wrappers * Add untested trace hooks for DOM nodes * Implement proper CharacterData inheritance for Text and Comment nodes
This commit is contained in:
parent
6c6d070dab
commit
56c4efde7c
27 changed files with 642 additions and 278 deletions
|
@ -151,14 +151,30 @@ pub fn Content(layout_task: LayoutTask,
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.set_cx_private(ptr::to_unsafe_ptr(&*content) as *());
|
cx.set_cx_private(ptr::to_unsafe_ptr(&*content) as *());
|
||||||
|
unsafe { task::local_data::local_data_set(global_content_key, cast::transmute(content)); }
|
||||||
|
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn global_content_key(_: @Content) {}
|
||||||
|
|
||||||
|
pub fn global_content() -> @Content {
|
||||||
|
unsafe {
|
||||||
|
return task::local_data::local_data_get(global_content_key).get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn task_from_context(cx: *JSContext) -> *mut Content {
|
pub fn task_from_context(cx: *JSContext) -> *mut Content {
|
||||||
JS_GetContextPrivate(cx) as *mut Content
|
JS_GetContextPrivate(cx) as *mut Content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unsafe_destructor]
|
||||||
|
impl Drop for Content {
|
||||||
|
fn finalize(&self) {
|
||||||
|
unsafe { task::local_data::local_data_pop(global_content_key) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
pub impl Content {
|
pub impl Content {
|
||||||
fn start(&mut self) {
|
fn start(&mut self) {
|
||||||
|
@ -185,6 +201,8 @@ pub impl Content {
|
||||||
ParseMsg(url) => {
|
ParseMsg(url) => {
|
||||||
debug!("content: Received url `%s` to parse", url_to_str(&url));
|
debug!("content: Received url `%s` to parse", url_to_str(&url));
|
||||||
|
|
||||||
|
define_bindings(self.compartment.get());
|
||||||
|
|
||||||
// Note: we can parse the next document in parallel
|
// Note: we can parse the next document in parallel
|
||||||
// with any previous documents.
|
// with any previous documents.
|
||||||
|
|
||||||
|
@ -209,8 +227,13 @@ pub impl Content {
|
||||||
let js_scripts = result.js_port.recv();
|
let js_scripts = result.js_port.recv();
|
||||||
debug!("js_scripts: %?", js_scripts);
|
debug!("js_scripts: %?", js_scripts);
|
||||||
|
|
||||||
let document = @mut Document(root);
|
let window = Window(self.control_chan.clone(),
|
||||||
let window = @mut Window(self.control_chan.clone());
|
self.event_chan.clone());
|
||||||
|
let document = Document(root, Some(window));
|
||||||
|
|
||||||
|
do root.with_mut_node |node| {
|
||||||
|
node.add_to_doc(document);
|
||||||
|
}
|
||||||
|
|
||||||
self.damage.add(MatchSelectorsDamage);
|
self.damage.add(MatchSelectorsDamage);
|
||||||
self.relayout(document, &url);
|
self.relayout(document, &url);
|
||||||
|
@ -221,7 +244,6 @@ pub impl Content {
|
||||||
|
|
||||||
let compartment = self.compartment.expect(~"TODO error checking");
|
let compartment = self.compartment.expect(~"TODO error checking");
|
||||||
compartment.define_functions(debug_fns);
|
compartment.define_functions(debug_fns);
|
||||||
define_bindings(compartment, document, window);
|
|
||||||
|
|
||||||
do vec::consume(js_scripts) |_i, bytes| {
|
do vec::consume(js_scripts) |_i, bytes| {
|
||||||
self.cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u);
|
self.cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u);
|
||||||
|
|
|
@ -2,63 +2,25 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use content::content_task::task_from_context;
|
use content::content_task::{task_from_context, global_content};
|
||||||
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
|
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
|
||||||
use dom::bindings::codegen::ClientRectBinding;
|
use dom::bindings::codegen::ClientRectBinding;
|
||||||
|
use dom::clientrect::ClientRect;
|
||||||
use js::jsapi::{JSObject, JSContext, JSVal};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
|
use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
|
||||||
|
|
||||||
pub trait ClientRect {
|
pub impl ClientRect {
|
||||||
fn Top(&self) -> f32;
|
pub fn init_wrapper(@mut self) {
|
||||||
fn Bottom(&self) -> f32;
|
let content = global_content();
|
||||||
fn Left(&self) -> f32;
|
let cx = content.compartment.get().cx.ptr;
|
||||||
fn Right(&self) -> f32;
|
let owner = content.window.get();
|
||||||
fn Width(&self) -> f32;
|
let cache = owner.get_wrappercache();
|
||||||
fn Height(&self) -> f32;
|
let scope = cache.get_wrapper();
|
||||||
}
|
self.wrap_object_shared(cx, scope);
|
||||||
|
|
||||||
pub struct ClientRectImpl {
|
|
||||||
wrapper: WrapperCache,
|
|
||||||
top: f32,
|
|
||||||
bottom: f32,
|
|
||||||
left: f32,
|
|
||||||
right: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClientRect for ClientRectImpl {
|
|
||||||
fn Top(&self) -> f32 {
|
|
||||||
self.top
|
|
||||||
}
|
|
||||||
|
|
||||||
fn Bottom(&self) -> f32 {
|
|
||||||
self.bottom
|
|
||||||
}
|
|
||||||
|
|
||||||
fn Left(&self) -> f32 {
|
|
||||||
self.left
|
|
||||||
}
|
|
||||||
|
|
||||||
fn Right(&self) -> f32 {
|
|
||||||
self.right
|
|
||||||
}
|
|
||||||
|
|
||||||
fn Width(&self) -> f32 {
|
|
||||||
f32::abs(self.right - self.left)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn Height(&self) -> f32 {
|
|
||||||
f32::abs(self.bottom - self.top)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ClientRect(top: f32, bottom: f32, left: f32, right: f32) -> ClientRectImpl {
|
impl CacheableWrapper for ClientRect {
|
||||||
ClientRectImpl {
|
|
||||||
top: top, bottom: bottom, left: left, right: right,
|
|
||||||
wrapper: WrapperCache::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CacheableWrapper for ClientRectImpl {
|
|
||||||
fn get_wrappercache(&mut self) -> &mut WrapperCache {
|
fn get_wrappercache(&mut self) -> &mut WrapperCache {
|
||||||
unsafe { cast::transmute(&self.wrapper) }
|
unsafe { cast::transmute(&self.wrapper) }
|
||||||
}
|
}
|
||||||
|
@ -73,14 +35,14 @@ impl CacheableWrapper for ClientRectImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindingObject for ClientRectImpl {
|
impl BindingObject for ClientRect {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let content = task_from_context(cx);
|
let content = task_from_context(cx);
|
||||||
unsafe { (*content).window.get() as @mut CacheableWrapper }
|
unsafe { (*content).window.get() as @mut CacheableWrapper }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerivedWrapper for ClientRectImpl {
|
impl DerivedWrapper for ClientRect {
|
||||||
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
|
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
|
||||||
fail!(~"nyi")
|
fail!(~"nyi")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,53 +2,24 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use content::content_task::task_from_context;
|
use content::content_task::{task_from_context, global_content};
|
||||||
use dom::bindings::clientrect::{ClientRect, ClientRectImpl};
|
|
||||||
use dom::bindings::codegen::ClientRectListBinding;
|
use dom::bindings::codegen::ClientRectListBinding;
|
||||||
use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject};
|
use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject};
|
||||||
|
use dom::clientrectlist::ClientRectList;
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext};
|
||||||
|
|
||||||
pub trait ClientRectList {
|
pub impl ClientRectList {
|
||||||
fn Length(&self) -> u32;
|
fn init_wrapper(@mut self) {
|
||||||
fn Item(&self, index: u32) -> Option<@mut ClientRectImpl>;
|
let content = global_content();
|
||||||
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRectImpl>;
|
let cx = content.compartment.get().cx.ptr;
|
||||||
}
|
let owner = content.window.get();
|
||||||
|
let cache = owner.get_wrappercache();
|
||||||
pub struct ClientRectListImpl {
|
let scope = cache.get_wrapper();
|
||||||
wrapper: WrapperCache,
|
self.wrap_object_shared(cx, scope);
|
||||||
rects: ~[(f32, f32, f32, f32)]
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClientRectList for ClientRectListImpl {
|
|
||||||
fn Length(&self) -> u32 {
|
|
||||||
self.rects.len() as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
fn Item(&self, index: u32) -> Option<@mut ClientRectImpl> {
|
|
||||||
if index < self.rects.len() as u32 {
|
|
||||||
let (top, bottom, left, right) = self.rects[index];
|
|
||||||
Some(@mut ClientRect(top, bottom, left, right))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRectImpl> {
|
|
||||||
*found = index < self.rects.len() as u32;
|
|
||||||
self.Item(index)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl ClientRectListImpl {
|
impl CacheableWrapper for ClientRectList {
|
||||||
fn new() -> ClientRectListImpl {
|
|
||||||
ClientRectListImpl {
|
|
||||||
wrapper: WrapperCache::new(),
|
|
||||||
rects: ~[(5.6, 80.2, 3.7, 4.8), (800.1, 8001.1, -50.000001, -45.01)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CacheableWrapper for ClientRectListImpl {
|
|
||||||
fn get_wrappercache(&mut self) -> &mut WrapperCache {
|
fn get_wrappercache(&mut self) -> &mut WrapperCache {
|
||||||
unsafe { cast::transmute(&self.wrapper) }
|
unsafe { cast::transmute(&self.wrapper) }
|
||||||
}
|
}
|
||||||
|
@ -63,7 +34,7 @@ impl CacheableWrapper for ClientRectListImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindingObject for ClientRectListImpl {
|
impl BindingObject for ClientRectList {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let content = task_from_context(cx);
|
let content = task_from_context(cx);
|
||||||
unsafe { (*content).window.get() as @mut CacheableWrapper }
|
unsafe { (*content).window.get() as @mut CacheableWrapper }
|
||||||
|
|
|
@ -115,13 +115,13 @@ DOMInterfaces = {
|
||||||
|
|
||||||
'ClientRect': [
|
'ClientRect': [
|
||||||
{
|
{
|
||||||
'nativeType': 'ClientRectImpl',
|
'nativeType': 'ClientRect',
|
||||||
'pointerType': '@mut '
|
'pointerType': '@mut '
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'ClientRectList': [
|
'ClientRectList': [
|
||||||
{
|
{
|
||||||
'nativeType': 'ClientRectListImpl',
|
'nativeType': 'ClientRectList',
|
||||||
'pointerType': '@mut '
|
'pointerType': '@mut '
|
||||||
}],
|
}],
|
||||||
|
|
||||||
|
|
|
@ -3906,9 +3906,9 @@ class CGBindingRoot(CGThing):
|
||||||
'dom::document::Document', #XXXjdm
|
'dom::document::Document', #XXXjdm
|
||||||
'dom::bindings::utils::*',
|
'dom::bindings::utils::*',
|
||||||
'dom::bindings::conversions::*',
|
'dom::bindings::conversions::*',
|
||||||
'dom::bindings::clientrect::*', #XXXjdm
|
'dom::clientrect::*', #XXXjdm
|
||||||
'dom::bindings::clientrectlist::*', #XXXjdm
|
'dom::clientrectlist::*', #XXXjdm
|
||||||
'dom::bindings::htmlcollection::*', #XXXjdm
|
'dom::htmlcollection::*', #XXXjdm
|
||||||
'dom::bindings::proxyhandler::*',
|
'dom::bindings::proxyhandler::*',
|
||||||
'dom::domparser::*', #XXXjdm
|
'dom::domparser::*', #XXXjdm
|
||||||
'content::content_task::task_from_context',
|
'content::content_task::task_from_context',
|
||||||
|
|
|
@ -17,11 +17,10 @@ use core::libc::c_uint;
|
||||||
use content::content_task::task_from_context;
|
use content::content_task::task_from_context;
|
||||||
use dom::bindings::utils::{DOMString, rust_box, squirrel_away, str};
|
use dom::bindings::utils::{DOMString, rust_box, squirrel_away, str};
|
||||||
use dom::bindings::utils::{jsval_to_str, WrapNewBindingObject, CacheableWrapper};
|
use dom::bindings::utils::{jsval_to_str, WrapNewBindingObject, CacheableWrapper};
|
||||||
use dom::bindings::utils::WrapperCache;
|
use dom::bindings::utils::{WrapperCache, DerivedWrapper};
|
||||||
|
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::bindings::htmlcollection::HTMLCollection;
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::bindings::node;
|
|
||||||
use dom::bindings::utils;
|
use dom::bindings::utils;
|
||||||
|
|
||||||
extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
||||||
|
@ -32,7 +31,9 @@ extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> J
|
||||||
}
|
}
|
||||||
|
|
||||||
let doc = &mut (*unwrap(obj)).payload;
|
let doc = &mut (*unwrap(obj)).payload;
|
||||||
*vp = RUST_OBJECT_TO_JSVAL(node::create(cx, &mut doc.root).ptr);
|
let root = &mut doc.root;
|
||||||
|
assert!(root.is_element());
|
||||||
|
root.wrap(cx, ptr::null(), vp); //XXXjdm proper scope at some point
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +81,7 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(compartment: @mut Compartment, doc: @mut Document) {
|
pub fn init(compartment: @mut Compartment) {
|
||||||
let obj = utils::define_empty_prototype(~"Document", None, compartment);
|
let obj = utils::define_empty_prototype(~"Document", None, compartment);
|
||||||
|
|
||||||
let attrs = @~[
|
let attrs = @~[
|
||||||
|
@ -115,14 +116,9 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) {
|
||||||
JS_DefineFunctions(compartment.cx.ptr, obj.ptr, fns);
|
JS_DefineFunctions(compartment.cx.ptr, obj.ptr, fns);
|
||||||
});
|
});
|
||||||
|
|
||||||
compartment.register_class(utils::instance_jsclass(~"DocumentInstance", finalize));
|
compartment.register_class(utils::instance_jsclass(~"DocumentInstance",
|
||||||
|
finalize,
|
||||||
let ptr = create(compartment, doc);
|
ptr::null()));
|
||||||
|
|
||||||
compartment.define_property(~"document", RUST_OBJECT_TO_JSVAL(ptr),
|
|
||||||
GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
|
|
||||||
GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8,
|
|
||||||
JSPROP_ENUMERATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(compartment: @mut Compartment, doc: @mut Document) -> *JSObject {
|
pub fn create(compartment: @mut Compartment, doc: @mut Document) -> *JSObject {
|
||||||
|
@ -135,6 +131,12 @@ pub fn create(compartment: @mut Compartment, doc: @mut Document) -> *JSObject {
|
||||||
let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(doc));
|
let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(doc));
|
||||||
JS_SetReservedSlot(instance.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
JS_SetReservedSlot(instance.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compartment.define_property(~"document", RUST_OBJECT_TO_JSVAL(instance.ptr),
|
||||||
|
GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
|
||||||
|
GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8,
|
||||||
|
JSPROP_ENUMERATE);
|
||||||
|
|
||||||
instance.ptr
|
instance.ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use content::content_task::task_from_context;
|
use content::content_task::task_from_context;
|
||||||
|
use dom::bindings::node::unwrap;
|
||||||
use dom::bindings::utils::{domstring_to_jsval, WrapNewBindingObject};
|
use dom::bindings::utils::{domstring_to_jsval, WrapNewBindingObject};
|
||||||
use dom::bindings::utils::{str, CacheableWrapper, DOM_OBJECT_SLOT};
|
use dom::bindings::utils::{str, CacheableWrapper, DOM_OBJECT_SLOT, DOMString};
|
||||||
|
use dom::bindings::utils::jsval_to_str;
|
||||||
use dom::element::*;
|
use dom::element::*;
|
||||||
use dom::node::{AbstractNode, Element, ElementNodeTypeId};
|
use dom::node::{AbstractNode, Element, ElementNodeTypeId};
|
||||||
use layout::layout_task;
|
use layout::layout_task;
|
||||||
|
@ -16,20 +18,44 @@ use js::glue::bindgen::*;
|
||||||
use js::jsapi::bindgen::*;
|
use js::jsapi::bindgen::*;
|
||||||
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSFreeOp, JSPropertySpec};
|
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSFreeOp, JSPropertySpec};
|
||||||
use js::jsapi::{JSPropertyOpWrapper, JSStrictPropertyOpWrapper, JSFunctionSpec};
|
use js::jsapi::{JSPropertyOpWrapper, JSStrictPropertyOpWrapper, JSFunctionSpec};
|
||||||
use js::jsapi::JSNativeWrapper;
|
use js::jsapi::{JSNativeWrapper, JSTracer, JSTRACE_OBJECT};
|
||||||
use js::rust::{Compartment, jsobj};
|
use js::rust::{Compartment, jsobj};
|
||||||
use js::{JS_ARGV, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL};
|
use js::{JS_ARGV, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL};
|
||||||
use js::{JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS};
|
use js::{JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS};
|
||||||
|
|
||||||
extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
debug!("element finalize: %?!", obj as uint);
|
debug!("element finalize: %x!", obj as uint);
|
||||||
unsafe {
|
unsafe {
|
||||||
let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32);
|
let node: AbstractNode = unwrap(obj);
|
||||||
let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
|
//XXXjdm We need separate finalizers for each specialty element type like headings
|
||||||
let _elem: ~Element = cast::transmute(node.raw_object());
|
let _elem: ~Element = cast::transmute(node.raw_object());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub extern fn trace(tracer: *JSTracer, obj: *JSObject) {
|
||||||
|
let node = unsafe { unwrap(obj) };
|
||||||
|
|
||||||
|
fn trace_node(tracer: *JSTracer, node: Option<AbstractNode>, name: &str) {
|
||||||
|
if node.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
error!("tracing %s", name);
|
||||||
|
let mut node = node.get();
|
||||||
|
let cache = node.get_wrappercache();
|
||||||
|
let wrapper = cache.get_wrapper();
|
||||||
|
assert!(wrapper.is_not_null());
|
||||||
|
unsafe {
|
||||||
|
JS_CallTracer(tracer, wrapper, JSTRACE_OBJECT as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error!("tracing %?:", obj as uint);
|
||||||
|
trace_node(tracer, node.parent_node(), "parent");
|
||||||
|
trace_node(tracer, node.first_child(), "first child");
|
||||||
|
trace_node(tracer, node.last_child(), "last child");
|
||||||
|
trace_node(tracer, node.next_sibling(), "next sibling");
|
||||||
|
trace_node(tracer, node.prev_sibling(), "prev sibling");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn init(compartment: @mut Compartment) {
|
pub fn init(compartment: @mut Compartment) {
|
||||||
let obj = utils::define_empty_prototype(~"Element", Some(~"Node"), compartment);
|
let obj = utils::define_empty_prototype(~"Element", Some(~"Node"), compartment);
|
||||||
let attrs = @~[
|
let attrs = @~[
|
||||||
|
@ -55,6 +81,11 @@ pub fn init(compartment: @mut Compartment) {
|
||||||
nargs: 0,
|
nargs: 0,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
selfHostedName: null()},
|
selfHostedName: null()},
|
||||||
|
JSFunctionSpec {name: compartment.add_name(~"setAttribute"),
|
||||||
|
call: JSNativeWrapper {op: setAttribute, info: null()},
|
||||||
|
nargs: 0,
|
||||||
|
flags: 0,
|
||||||
|
selfHostedName: null()},
|
||||||
JSFunctionSpec {name: null(),
|
JSFunctionSpec {name: null(),
|
||||||
call: JSNativeWrapper {op: null(), info: null()},
|
call: JSNativeWrapper {op: null(), info: null()},
|
||||||
nargs: 0,
|
nargs: 0,
|
||||||
|
@ -65,7 +96,7 @@ pub fn init(compartment: @mut Compartment) {
|
||||||
});
|
});
|
||||||
|
|
||||||
compartment.register_class(utils::instance_jsclass(~"GenericElementInstance",
|
compartment.register_class(utils::instance_jsclass(~"GenericElementInstance",
|
||||||
finalize));
|
finalize, trace));
|
||||||
|
|
||||||
let _ = utils::define_empty_prototype(~"HTMLElement", Some(~"Element"), compartment);
|
let _ = utils::define_empty_prototype(~"HTMLElement", Some(~"Element"), compartment);
|
||||||
let _ = utils::define_empty_prototype(~"HTMLDivElement", Some(~"HTMLElement"), compartment);
|
let _ = utils::define_empty_prototype(~"HTMLDivElement", Some(~"HTMLElement"), compartment);
|
||||||
|
@ -93,8 +124,7 @@ pub fn init(compartment: @mut Compartment) {
|
||||||
extern fn getClientRects(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool {
|
extern fn getClientRects(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let obj = JS_THIS_OBJECT(cx, vp);
|
let obj = JS_THIS_OBJECT(cx, vp);
|
||||||
let mut box = utils::unwrap::<*mut AbstractNode>(obj);
|
let mut node = unwrap(obj);
|
||||||
let node = &mut *box;
|
|
||||||
let rval = do node.with_imm_element |elem| {
|
let rval = do node.with_imm_element |elem| {
|
||||||
elem.getClientRects()
|
elem.getClientRects()
|
||||||
};
|
};
|
||||||
|
@ -111,6 +141,39 @@ extern fn getClientRects(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern fn setAttribute(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
|
||||||
|
unsafe {
|
||||||
|
let obj = JS_THIS_OBJECT(cx, vp);
|
||||||
|
let mut node = unwrap(obj);
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
return 0; //XXXjdm throw exception
|
||||||
|
}
|
||||||
|
|
||||||
|
let argv = JS_ARGV(cx, cast::transmute(vp));
|
||||||
|
|
||||||
|
let arg0: DOMString;
|
||||||
|
let strval = jsval_to_str(cx, (*argv.offset(0)));
|
||||||
|
if strval.is_err() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
arg0 = str(strval.get());
|
||||||
|
|
||||||
|
let arg1: DOMString;
|
||||||
|
let strval = jsval_to_str(cx, (*argv.offset(1)));
|
||||||
|
if strval.is_err() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
arg1 = str(strval.get());
|
||||||
|
|
||||||
|
do node.as_mut_element |elem| {
|
||||||
|
elem.set_attr(&arg0, &arg1);
|
||||||
|
};
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -119,12 +182,11 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut box = utils::unwrap::<*mut AbstractNode>(obj);
|
let mut node = unwrap(obj);
|
||||||
let node = &mut *box;
|
|
||||||
let width = match node.type_id() {
|
let width = match node.type_id() {
|
||||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||||
let content = task_from_context(cx);
|
let content = task_from_context(cx);
|
||||||
match (*content).query_layout(layout_task::ContentBox(*node)) {
|
match (*content).query_layout(layout_task::ContentBox(node)) {
|
||||||
Ok(rect) => rect.width,
|
Ok(rect) => rect.width,
|
||||||
Err(()) => 0
|
Err(()) => 0
|
||||||
}
|
}
|
||||||
|
@ -148,13 +210,13 @@ extern fn HTMLImageElement_setWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut box = utils::unwrap::<*mut AbstractNode>(obj);
|
let mut node = unwrap(obj);
|
||||||
let node = &mut *box;
|
|
||||||
match node.type_id() {
|
match node.type_id() {
|
||||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||||
do node.as_mut_element |elem| {
|
do node.as_mut_element |elem| {
|
||||||
let arg = ptr::offset(JS_ARGV(cx, cast::reinterpret_cast(&vp)), 0);
|
let arg = ptr::offset(JS_ARGV(cx, cast::reinterpret_cast(&vp)), 0);
|
||||||
elem.set_attr(~"width", (RUST_JSVAL_TO_INT(*arg) as int).to_str())
|
elem.set_attr(&str(~"width"),
|
||||||
|
&str((RUST_JSVAL_TO_INT(*arg) as int).to_str()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ElementNodeTypeId(_) => fail!(~"why is this not an image element?"),
|
ElementNodeTypeId(_) => fail!(~"why is this not an image element?"),
|
||||||
|
@ -165,7 +227,6 @@ extern fn HTMLImageElement_setWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
|
||||||
extern fn getTagName(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
extern fn getTagName(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let obj = JS_THIS_OBJECT(cx, cast::reinterpret_cast(&vp));
|
let obj = JS_THIS_OBJECT(cx, cast::reinterpret_cast(&vp));
|
||||||
|
@ -173,8 +234,7 @@ extern fn getTagName(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut box = utils::unwrap::<*mut AbstractNode>(obj);
|
let mut node = unwrap(obj);
|
||||||
let node = &mut *box;
|
|
||||||
do node.with_imm_element |elem| {
|
do node.with_imm_element |elem| {
|
||||||
let s = str(copy elem.tag_name);
|
let s = str(copy elem.tag_name);
|
||||||
*vp = domstring_to_jsval(cx, &s);
|
*vp = domstring_to_jsval(cx, &s);
|
||||||
|
@ -183,7 +243,6 @@ extern fn getTagName(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
|
||||||
pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj {
|
pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj {
|
||||||
let proto = match node.type_id() {
|
let proto = match node.type_id() {
|
||||||
ElementNodeTypeId(HTMLDivElementTypeId) => ~"HTMLDivElement",
|
ElementNodeTypeId(HTMLDivElementTypeId) => ~"HTMLDivElement",
|
||||||
|
@ -201,9 +260,11 @@ pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj {
|
||||||
proto,
|
proto,
|
||||||
compartment.global_obj.ptr));
|
compartment.global_obj.ptr));
|
||||||
|
|
||||||
node.get_wrappercache().set_wrapper(obj.ptr);
|
let cache = node.get_wrappercache();
|
||||||
|
assert!(cache.get_wrapper().is_null());
|
||||||
|
cache.set_wrapper(obj.ptr);
|
||||||
|
|
||||||
let raw_ptr = ptr::addr_of(node) as *libc::c_void;
|
let raw_ptr = node.raw_object() as *libc::c_void;
|
||||||
JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT as u32, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT as u32, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
|
|
@ -2,46 +2,20 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use content::content_task::task_from_context;
|
use content::content_task::{task_from_context, global_content};
|
||||||
use dom::node::AbstractNode;
|
|
||||||
use dom::bindings::codegen::HTMLCollectionBinding;
|
use dom::bindings::codegen::HTMLCollectionBinding;
|
||||||
use dom::bindings::utils::{DOMString, ErrorResult};
|
|
||||||
use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache};
|
use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache};
|
||||||
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext};
|
||||||
|
|
||||||
pub struct HTMLCollection {
|
|
||||||
elements: ~[AbstractNode],
|
|
||||||
wrapper: WrapperCache
|
|
||||||
}
|
|
||||||
|
|
||||||
pub impl HTMLCollection {
|
pub impl HTMLCollection {
|
||||||
fn new(elements: ~[AbstractNode]) -> HTMLCollection {
|
fn init_wrapper(@mut self) {
|
||||||
HTMLCollection {
|
let content = global_content();
|
||||||
elements: elements,
|
let cx = content.compartment.get().cx.ptr;
|
||||||
wrapper: WrapperCache::new()
|
let owner = content.window.get();
|
||||||
}
|
let cache = owner.get_wrappercache();
|
||||||
}
|
let scope = cache.get_wrapper();
|
||||||
|
self.wrap_object_shared(cx, scope);
|
||||||
fn Length(&self) -> u32 {
|
|
||||||
self.elements.len() as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
fn Item(&self, index: u32) -> Option<AbstractNode> {
|
|
||||||
if index < self.Length() {
|
|
||||||
Some(self.elements[index])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn NamedItem(&self, _cx: *JSContext, _name: DOMString, rv: &mut ErrorResult) -> *JSObject {
|
|
||||||
*rv = Ok(());
|
|
||||||
ptr::null()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<AbstractNode> {
|
|
||||||
*found = true;
|
|
||||||
self.Item(index)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,24 +2,22 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::utils::{CacheableWrapper, WrapperCache};
|
use dom::bindings::element;
|
||||||
use dom::bindings::utils::{DOM_OBJECT_SLOT};
|
use dom::bindings::text;
|
||||||
|
use dom::bindings::utils;
|
||||||
|
use dom::bindings::utils::{CacheableWrapper, WrapperCache, DerivedWrapper};
|
||||||
use dom::node::{AbstractNode, Node, ElementNodeTypeId, TextNodeTypeId, CommentNodeTypeId};
|
use dom::node::{AbstractNode, Node, ElementNodeTypeId, TextNodeTypeId, CommentNodeTypeId};
|
||||||
use dom::node::{DoctypeNodeTypeId};
|
use dom::node::{DoctypeNodeTypeId};
|
||||||
use super::element;
|
|
||||||
use super::utils;
|
|
||||||
|
|
||||||
use core::libc::c_uint;
|
use core::libc::c_uint;
|
||||||
use core::ptr::null;
|
use core::ptr::null;
|
||||||
use js::glue::bindgen::*;
|
|
||||||
use js::jsapi::bindgen::*;
|
use js::jsapi::bindgen::*;
|
||||||
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSPropertySpec};
|
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSPropertySpec};
|
||||||
use js::jsapi::{JSPropertyOpWrapper, JSStrictPropertyOpWrapper};
|
use js::jsapi::{JSPropertyOpWrapper, JSStrictPropertyOpWrapper};
|
||||||
use js::jsval::{INT_TO_JSVAL, JSVAL_TO_PRIVATE};
|
use js::jsval::{INT_TO_JSVAL};
|
||||||
use js::rust::{Compartment, jsobj};
|
use js::rust::{Compartment, jsobj};
|
||||||
use js::{JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL};
|
use js::{JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL};
|
||||||
use js::{JS_THIS_OBJECT, JSPROP_NATIVE_ACCESSORS};
|
use js::{JS_THIS_OBJECT, JSPROP_NATIVE_ACCESSORS};
|
||||||
use js;
|
|
||||||
|
|
||||||
pub fn init(compartment: @mut Compartment) {
|
pub fn init(compartment: @mut Compartment) {
|
||||||
let obj = utils::define_empty_prototype(~"Node", None, compartment);
|
let obj = utils::define_empty_prototype(~"Node", None, compartment);
|
||||||
|
@ -62,15 +60,15 @@ pub fn init(compartment: @mut Compartment) {
|
||||||
pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj {
|
pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj {
|
||||||
match node.type_id() {
|
match node.type_id() {
|
||||||
ElementNodeTypeId(_) => element::create(cx, node),
|
ElementNodeTypeId(_) => element::create(cx, node),
|
||||||
TextNodeTypeId => fail!(~"no text node bindings yet"),
|
TextNodeTypeId |
|
||||||
CommentNodeTypeId => fail!(~"no comment node bindings yet"),
|
CommentNodeTypeId |
|
||||||
DoctypeNodeTypeId => fail!(~"no doctype node bindings yet")
|
DoctypeNodeTypeId => text::create(cx, node),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn unwrap(obj: *JSObject) -> *AbstractNode {
|
pub unsafe fn unwrap(obj: *JSObject) -> AbstractNode {
|
||||||
let val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT as u64);
|
let raw = unsafe { utils::unwrap::<*mut Node>(obj) };
|
||||||
cast::transmute(JSVAL_TO_PRIVATE(val))
|
AbstractNode::from_raw(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
|
@ -81,14 +79,13 @@ extern fn getFirstChild(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = *unwrap(obj);
|
let node = unwrap(obj);
|
||||||
let rval = do node.with_mut_node |node| {
|
let rval = do node.with_mut_node |node| {
|
||||||
node.getFirstChild()
|
node.getFirstChild()
|
||||||
};
|
};
|
||||||
match rval {
|
match rval {
|
||||||
Some(n) => {
|
Some(n) => {
|
||||||
let obj = create(cx, n).ptr;
|
n.wrap(cx, ptr::null(), vp); //XXXjdm pass a real scope
|
||||||
*vp = RUST_OBJECT_TO_JSVAL(obj)
|
|
||||||
}
|
}
|
||||||
None => *vp = JSVAL_NULL
|
None => *vp = JSVAL_NULL
|
||||||
};
|
};
|
||||||
|
@ -104,14 +101,13 @@ extern fn getNextSibling(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBoo
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = *unwrap(obj);
|
let node = unwrap(obj);
|
||||||
let rval = do node.with_mut_node |node| {
|
let rval = do node.with_mut_node |node| {
|
||||||
node.getNextSibling()
|
node.getNextSibling()
|
||||||
};
|
};
|
||||||
match rval {
|
match rval {
|
||||||
Some(n) => {
|
Some(n) => {
|
||||||
let obj = create(cx, n).ptr;
|
n.wrap(cx, ptr::null(), vp); //XXXjdm pass a real scope
|
||||||
*vp = RUST_OBJECT_TO_JSVAL(obj)
|
|
||||||
}
|
}
|
||||||
None => *vp = JSVAL_NULL
|
None => *vp = JSVAL_NULL
|
||||||
};
|
};
|
||||||
|
@ -155,7 +151,7 @@ extern fn getNodeType(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = *unwrap(obj);
|
let node = unwrap(obj);
|
||||||
let rval = do node.with_imm_node |node| {
|
let rval = do node.with_imm_node |node| {
|
||||||
node.getNodeType()
|
node.getNodeType()
|
||||||
};
|
};
|
||||||
|
|
90
src/servo/dom/bindings/text.rs
Normal file
90
src/servo/dom/bindings/text.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use dom::bindings::element;
|
||||||
|
use dom::bindings::utils;
|
||||||
|
use dom::bindings::utils::{DOM_OBJECT_SLOT, CacheableWrapper};
|
||||||
|
use dom::node::{AbstractNode, Text, Comment, Doctype, TextNodeTypeId, CommentNodeTypeId};
|
||||||
|
use dom::node::{DoctypeNodeTypeId};
|
||||||
|
|
||||||
|
use js::jsapi::{JSFreeOp, JSObject, JSContext};
|
||||||
|
use js::jsapi::bindgen::{JS_GetReservedSlot, JS_SetReservedSlot};
|
||||||
|
use js::glue::bindgen::{RUST_JSVAL_TO_PRIVATE, RUST_PRIVATE_TO_JSVAL};
|
||||||
|
use js::rust::{Compartment, jsobj};
|
||||||
|
|
||||||
|
extern fn finalize_text(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
|
debug!("text finalize: %?!", obj as uint);
|
||||||
|
unsafe {
|
||||||
|
let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32);
|
||||||
|
let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
|
||||||
|
let _elem: ~Text = cast::transmute(node.raw_object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn finalize_comment(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
|
debug!("comment finalize: %?!", obj as uint);
|
||||||
|
unsafe {
|
||||||
|
let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32);
|
||||||
|
let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
|
||||||
|
let _elem: ~Comment = cast::transmute(node.raw_object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn finalize_doctype(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
|
debug!("doctype finalize: %?!", obj as uint);
|
||||||
|
unsafe {
|
||||||
|
let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32);
|
||||||
|
let node: AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
|
||||||
|
let _elem: ~Doctype = cast::transmute(node.raw_object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(compartment: @mut Compartment) {
|
||||||
|
let _ = utils::define_empty_prototype(~"CharacterData", Some(~"Node"), compartment);
|
||||||
|
|
||||||
|
let _ = utils::define_empty_prototype(~"TextPrototype",
|
||||||
|
Some(~"CharacterData"),
|
||||||
|
compartment);
|
||||||
|
let _ = utils::define_empty_prototype(~"CommentPrototype",
|
||||||
|
Some(~"CharacterData"),
|
||||||
|
compartment);
|
||||||
|
let _ = utils::define_empty_prototype(~"DocumentTypePrototype",
|
||||||
|
Some(~"Node"),
|
||||||
|
compartment);
|
||||||
|
|
||||||
|
compartment.register_class(utils::instance_jsclass(~"Text",
|
||||||
|
finalize_text,
|
||||||
|
element::trace));
|
||||||
|
compartment.register_class(utils::instance_jsclass(~"Comment",
|
||||||
|
finalize_comment,
|
||||||
|
element::trace));
|
||||||
|
compartment.register_class(utils::instance_jsclass(~"DocumentType",
|
||||||
|
finalize_doctype,
|
||||||
|
element::trace));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj {
|
||||||
|
let (proto, instance) = match node.type_id() {
|
||||||
|
TextNodeTypeId => (~"TextPrototype", ~"Text"),
|
||||||
|
CommentNodeTypeId => (~"CommentPrototype", ~"Comment"),
|
||||||
|
DoctypeNodeTypeId => (~"DocumentTypePrototype", ~"DocumentType"),
|
||||||
|
_ => fail!(~"text::create only handles textual nodes")
|
||||||
|
};
|
||||||
|
|
||||||
|
//XXXjdm the parent should probably be the node parent instead of the global
|
||||||
|
//TODO error checking
|
||||||
|
let compartment = utils::get_compartment(cx);
|
||||||
|
let obj = result::unwrap(compartment.new_object_with_proto(instance,
|
||||||
|
proto,
|
||||||
|
compartment.global_obj.ptr));
|
||||||
|
|
||||||
|
let cache = node.get_wrappercache();
|
||||||
|
assert!(cache.get_wrapper().is_null());
|
||||||
|
cache.set_wrapper(obj.ptr);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let raw_ptr = ptr::to_unsafe_ptr(node) as *libc::c_void;
|
||||||
|
JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT as u32, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
|
@ -30,9 +30,7 @@ use content::content_task::task_from_context;
|
||||||
|
|
||||||
use core::hashmap::HashMap;
|
use core::hashmap::HashMap;
|
||||||
|
|
||||||
use dom::bindings::document;
|
|
||||||
use dom::bindings::node;
|
use dom::bindings::node;
|
||||||
use dom::document::Document;
|
|
||||||
use dom::node::AbstractNode;
|
use dom::node::AbstractNode;
|
||||||
|
|
||||||
static TOSTRING_CLASS_RESERVED_SLOT: u64 = 0;
|
static TOSTRING_CLASS_RESERVED_SLOT: u64 = 0;
|
||||||
|
@ -93,6 +91,15 @@ pub enum DOMString {
|
||||||
null_string
|
null_string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub impl DOMString {
|
||||||
|
fn to_str(&self) -> ~str {
|
||||||
|
match *self {
|
||||||
|
str(ref s) => s.clone(),
|
||||||
|
null_string => ~""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct rust_box<T> {
|
pub struct rust_box<T> {
|
||||||
rc: uint,
|
rc: uint,
|
||||||
td: *sys::TypeDesc,
|
td: *sys::TypeDesc,
|
||||||
|
@ -219,7 +226,7 @@ pub fn prototype_jsclass(name: ~str) -> @fn(compartment: @mut Compartment) -> JS
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn instance_jsclass(name: ~str, finalize: *u8)
|
pub fn instance_jsclass(name: ~str, finalize: *u8, trace: *u8)
|
||||||
-> @fn(compartment: @mut Compartment) -> JSClass {
|
-> @fn(compartment: @mut Compartment) -> JSClass {
|
||||||
let f: @fn(@mut Compartment) -> JSClass = |compartment: @mut Compartment| {
|
let f: @fn(@mut Compartment) -> JSClass = |compartment: @mut Compartment| {
|
||||||
JSClass {
|
JSClass {
|
||||||
|
@ -237,7 +244,7 @@ pub fn instance_jsclass(name: ~str, finalize: *u8)
|
||||||
call: null(),
|
call: null(),
|
||||||
hasInstance: has_instance,
|
hasInstance: has_instance,
|
||||||
construct: null(),
|
construct: null(),
|
||||||
trace: null(),
|
trace: trace,
|
||||||
reserved: (null(), null(), null(), null(), null(), // 05
|
reserved: (null(), null(), null(), null(), null(), // 05
|
||||||
null(), null(), null(), null(), null(), // 10
|
null(), null(), null(), null(), null(), // 10
|
||||||
null(), null(), null(), null(), null(), // 15
|
null(), null(), null(), null(), null(), // 15
|
||||||
|
@ -788,40 +795,6 @@ impl DerivedWrapper for AbstractNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*impl DerivedWrapper for Document {
|
|
||||||
fn wrap(&mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
|
|
||||||
let cache = self.get_wrappercache();
|
|
||||||
let wrapper = cache.get_wrapper();
|
|
||||||
if wrapper.is_not_null() {
|
|
||||||
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
let content = task_from_context(cx);
|
|
||||||
unsafe {
|
|
||||||
let compartment = (*content).compartment.get();
|
|
||||||
*vp = RUST_OBJECT_TO_JSVAL(document::create(compartment, self));
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
pub impl Document {
|
|
||||||
fn wrap(@mut self, cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 {
|
|
||||||
let cache = self.get_wrappercache();
|
|
||||||
let wrapper = cache.get_wrapper();
|
|
||||||
if wrapper.is_not_null() {
|
|
||||||
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
let content = task_from_context(cx);
|
|
||||||
unsafe {
|
|
||||||
let compartment = (*content).compartment.get();
|
|
||||||
*vp = RUST_OBJECT_TO_JSVAL(document::create(compartment, self));
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
FailureUnknown
|
FailureUnknown
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,13 +76,9 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(compartment: @mut Compartment, win: @mut Window) {
|
pub fn init(compartment: @mut Compartment) {
|
||||||
let proto = utils::define_empty_prototype(~"Window", None, compartment);
|
let proto = utils::define_empty_prototype(~"Window", None, compartment);
|
||||||
compartment.register_class(utils::instance_jsclass(~"WindowInstance", finalize));
|
compartment.register_class(utils::instance_jsclass(~"WindowInstance", finalize, null()));
|
||||||
|
|
||||||
let obj = result::unwrap(
|
|
||||||
compartment.new_object_with_proto(~"WindowInstance",
|
|
||||||
~"Window", null()));
|
|
||||||
|
|
||||||
/* Define methods on a window */
|
/* Define methods on a window */
|
||||||
let methods = [
|
let methods = [
|
||||||
|
@ -116,11 +112,19 @@ pub fn init(compartment: @mut Compartment, win: @mut Window) {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
JS_DefineFunctions(compartment.cx.ptr, proto.ptr, &methods[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(compartment: @mut Compartment, win: @mut Window) {
|
||||||
|
let obj = result::unwrap(
|
||||||
|
compartment.new_object_with_proto(~"WindowInstance",
|
||||||
|
~"Window", null()));
|
||||||
|
|
||||||
win.get_wrappercache().set_wrapper(obj.ptr);
|
win.get_wrappercache().set_wrapper(obj.ptr);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
JS_DefineFunctions(compartment.cx.ptr, proto.ptr, &methods[0]);
|
|
||||||
|
|
||||||
let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(win));
|
let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(win));
|
||||||
JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
||||||
}
|
}
|
||||||
|
|
57
src/servo/dom/characterdata.rs
Normal file
57
src/servo/dom/characterdata.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use dom::bindings::utils::{DOMString, null_string, str};
|
||||||
|
use dom::node::{Node, NodeTypeId};
|
||||||
|
|
||||||
|
use core::str;
|
||||||
|
|
||||||
|
pub struct CharacterData {
|
||||||
|
parent: Node,
|
||||||
|
data: DOMString
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl CharacterData {
|
||||||
|
fn new(id: NodeTypeId, data: ~str) -> CharacterData {
|
||||||
|
CharacterData {
|
||||||
|
parent: Node::new(id),
|
||||||
|
data: str(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetData(&self) -> DOMString {
|
||||||
|
copy self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SetData(&mut self, arg: DOMString) {
|
||||||
|
self.data = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Length(&self) -> u32 {
|
||||||
|
match self.data {
|
||||||
|
str(ref s) => s.len() as u32,
|
||||||
|
null_string => 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SubstringData(&self, offset: u32, count: u32) -> DOMString {
|
||||||
|
match self.data {
|
||||||
|
str(ref s) => str(s.slice(offset as uint, count as uint).to_str()),
|
||||||
|
null_string => null_string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn AppendData(&mut self, arg: DOMString) {
|
||||||
|
let s = self.data.to_str();
|
||||||
|
self.data = str(str::append(s, arg.to_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn InsertData(&mut self, _offset: u32, _arg: DOMString) {
|
||||||
|
fail!(~"nyi")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DeleteData(&mut self, _offset: u32, _count: u32) {
|
||||||
|
fail!(~"nyi")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ReplaceData(&mut self, _offset: u32, _count: u32, _arg: DOMString) {
|
||||||
|
fail!(~"nyi")
|
||||||
|
}
|
||||||
|
}
|
45
src/servo/dom/clientrect.rs
Normal file
45
src/servo/dom/clientrect.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
//use dom::bindings::clientrect::ClientRect;
|
||||||
|
use dom::bindings::utils::WrapperCache;
|
||||||
|
|
||||||
|
pub struct ClientRect {
|
||||||
|
wrapper: WrapperCache,
|
||||||
|
top: f32,
|
||||||
|
bottom: f32,
|
||||||
|
left: f32,
|
||||||
|
right: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl ClientRect {
|
||||||
|
fn new(top: f32, bottom: f32, left: f32, right: f32) -> @mut ClientRect {
|
||||||
|
let rect = @mut ClientRect {
|
||||||
|
top: top, bottom: bottom, left: left, right: right,
|
||||||
|
wrapper: WrapperCache::new()
|
||||||
|
};
|
||||||
|
rect.init_wrapper();
|
||||||
|
rect
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Top(&self) -> f32 {
|
||||||
|
self.top
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Bottom(&self) -> f32 {
|
||||||
|
self.bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Left(&self) -> f32 {
|
||||||
|
self.left
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Right(&self) -> f32 {
|
||||||
|
self.right
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Width(&self) -> f32 {
|
||||||
|
f32::abs(self.right - self.left)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Height(&self) -> f32 {
|
||||||
|
f32::abs(self.bottom - self.top)
|
||||||
|
}
|
||||||
|
}
|
36
src/servo/dom/clientrectlist.rs
Normal file
36
src/servo/dom/clientrectlist.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use dom::clientrect::ClientRect;
|
||||||
|
use dom::bindings::utils::WrapperCache;
|
||||||
|
|
||||||
|
pub struct ClientRectList {
|
||||||
|
wrapper: WrapperCache,
|
||||||
|
rects: ~[(f32, f32, f32, f32)]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl ClientRectList {
|
||||||
|
fn new() -> @mut ClientRectList {
|
||||||
|
let list = @mut ClientRectList {
|
||||||
|
wrapper: WrapperCache::new(),
|
||||||
|
rects: ~[(5.6, 80.2, 3.7, 4.8), (800.1, 8001.1, -50.000001, -45.01)]
|
||||||
|
};
|
||||||
|
list.init_wrapper();
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Length(&self) -> u32 {
|
||||||
|
self.rects.len() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Item(&self, index: u32) -> Option<@mut ClientRect> {
|
||||||
|
if index < self.rects.len() as u32 {
|
||||||
|
let (top, bottom, left, right) = self.rects[index];
|
||||||
|
Some(ClientRect::new(top, bottom, left, right))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRect> {
|
||||||
|
*found = index < self.rects.len() as u32;
|
||||||
|
self.Item(index)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,30 +2,55 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::htmlcollection::HTMLCollection;
|
use content::content_task::global_content;
|
||||||
use dom::bindings::utils::{DOMString, WrapperCache, str};
|
use dom::bindings::document;
|
||||||
|
use dom::bindings::utils::{DOMString, WrapperCache};
|
||||||
|
use dom::event::ReflowEvent;
|
||||||
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::node::AbstractNode;
|
use dom::node::AbstractNode;
|
||||||
|
use dom::window::Window;
|
||||||
|
|
||||||
|
use js::jsapi::bindgen::{JS_AddObjectRoot, JS_RemoveObjectRoot};
|
||||||
|
|
||||||
pub struct Document {
|
pub struct Document {
|
||||||
root: AbstractNode,
|
root: AbstractNode,
|
||||||
wrapper: WrapperCache
|
wrapper: WrapperCache,
|
||||||
|
window: Option<@mut Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Document(root: AbstractNode) -> Document {
|
pub fn Document(root: AbstractNode,
|
||||||
Document {
|
window: Option<@mut Window>) -> @mut Document {
|
||||||
|
let doc = @mut Document {
|
||||||
root: root,
|
root: root,
|
||||||
wrapper: WrapperCache::new()
|
wrapper: WrapperCache::new(),
|
||||||
|
window: window
|
||||||
|
};
|
||||||
|
let compartment = global_content().compartment.get();
|
||||||
|
do root.with_imm_node |node| {
|
||||||
|
let wrapper = node.wrapper.get_wrapper();
|
||||||
|
assert!(wrapper.is_not_null());
|
||||||
|
unsafe { JS_AddObjectRoot(compartment.cx.ptr, ptr::addr_of(&wrapper)); }
|
||||||
|
}
|
||||||
|
document::create(compartment, doc);
|
||||||
|
doc
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe_destructor]
|
||||||
|
impl Drop for Document {
|
||||||
|
fn finalize(&self) {
|
||||||
|
let compartment = global_content().compartment.get();
|
||||||
|
do self.root.with_imm_node |node| {
|
||||||
|
let wrapper = node.wrapper.get_wrapper();
|
||||||
|
assert!(wrapper.is_not_null());
|
||||||
|
unsafe { JS_RemoveObjectRoot(compartment.cx.ptr, ptr::addr_of(&wrapper)); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Document {
|
pub impl Document {
|
||||||
fn getElementsByTagName(&self, tag: DOMString) -> Option<@mut HTMLCollection> {
|
fn getElementsByTagName(&self, tag: DOMString) -> Option<@mut HTMLCollection> {
|
||||||
let mut elements = ~[];
|
let mut elements = ~[];
|
||||||
let tag = match tag {
|
let tag = tag.to_str();
|
||||||
str(s) => s,
|
|
||||||
_ => ~""
|
|
||||||
};
|
|
||||||
let _ = for self.root.traverse_preorder |child| {
|
let _ = for self.root.traverse_preorder |child| {
|
||||||
if child.is_element() {
|
if child.is_element() {
|
||||||
do child.with_imm_element |elem| {
|
do child.with_imm_element |elem| {
|
||||||
|
@ -35,6 +60,13 @@ pub impl Document {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some(@mut HTMLCollection::new(elements))
|
Some(HTMLCollection::new(elements))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn content_changed(&self) {
|
||||||
|
do self.window.map |window| {
|
||||||
|
let chan = &mut window.dom_event_chan;
|
||||||
|
chan.send(ReflowEvent)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
|
use content::content_task::global_content;
|
||||||
|
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache, CacheableWrapper};
|
||||||
use dom::bindings::codegen::DOMParserBinding;
|
use dom::bindings::codegen::DOMParserBinding;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::{Element, HTMLHtmlElement, HTMLHtmlElementTypeId};
|
use dom::element::{Element, HTMLHtmlElement, HTMLHtmlElementTypeId};
|
||||||
|
@ -11,20 +12,25 @@ pub struct DOMParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl DOMParser {
|
pub impl DOMParser {
|
||||||
fn new(owner: @mut Window) -> DOMParser {
|
fn new(owner: @mut Window) -> @mut DOMParser {
|
||||||
DOMParser {
|
let parser = @mut DOMParser {
|
||||||
owner: owner,
|
owner: owner,
|
||||||
wrapper: WrapperCache::new()
|
wrapper: WrapperCache::new()
|
||||||
}
|
};
|
||||||
|
let cx = global_content().compartment.get().cx.ptr;
|
||||||
|
let cache = owner.get_wrappercache();
|
||||||
|
let scope = cache.get_wrapper();
|
||||||
|
parser.wrap_object_shared(cx, scope);
|
||||||
|
parser
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Constructor(owner: @mut Window, _rv: &mut ErrorResult) -> @mut DOMParser {
|
fn Constructor(owner: @mut Window, _rv: &mut ErrorResult) -> @mut DOMParser {
|
||||||
@mut DOMParser::new(owner)
|
DOMParser::new(owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ParseFromString(&self, _s: DOMString, _type_: DOMParserBinding::SupportedType, _rv: &mut ErrorResult) -> @mut Document {
|
fn ParseFromString(&self, _s: DOMString, _type_: DOMParserBinding::SupportedType, _rv: &mut ErrorResult) -> @mut Document {
|
||||||
let root = ~HTMLHtmlElement { parent: Element::new(HTMLHtmlElementTypeId, ~"html") };
|
let root = ~HTMLHtmlElement { parent: Element::new(HTMLHtmlElementTypeId, ~"html") };
|
||||||
let root = unsafe { Node::as_abstract_node(root) };
|
let root = unsafe { Node::as_abstract_node(root) };
|
||||||
@mut Document(root)
|
Document(root, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,7 +7,8 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
use dom::node::{ElementNodeTypeId, Node};
|
use dom::node::{ElementNodeTypeId, Node};
|
||||||
use dom::bindings::clientrectlist::ClientRectListImpl;
|
use dom::clientrectlist::ClientRectList;
|
||||||
|
use dom::bindings::utils::DOMString;
|
||||||
|
|
||||||
use core::str::eq_slice;
|
use core::str::eq_slice;
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
|
@ -19,6 +20,13 @@ pub struct Element {
|
||||||
attrs: ~[Attr],
|
attrs: ~[Attr],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unsafe_destructor]
|
||||||
|
impl Drop for Element {
|
||||||
|
fn finalize(&self) {
|
||||||
|
fail!(~"uh oh");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[deriving(Eq)]
|
#[deriving(Eq)]
|
||||||
pub enum ElementTypeId {
|
pub enum ElementTypeId {
|
||||||
HTMLAnchorElementTypeId,
|
HTMLAnchorElementTypeId,
|
||||||
|
@ -132,20 +140,31 @@ pub impl<'self> Element {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_attr(&mut self, name: &str, value: ~str) {
|
fn set_attr(&mut self, name: &DOMString, value: &DOMString) {
|
||||||
|
let name = name.to_str();
|
||||||
|
let value = value.to_str();
|
||||||
// FIXME: We need a better each_mut in Rust; this is ugly.
|
// FIXME: We need a better each_mut in Rust; this is ugly.
|
||||||
let value_cell = Cell(value);
|
let value_cell = Cell(value);
|
||||||
|
let mut found = false;
|
||||||
for uint::range(0, self.attrs.len()) |i| {
|
for uint::range(0, self.attrs.len()) |i| {
|
||||||
if eq_slice(self.attrs[i].name, name) {
|
if eq_slice(self.attrs[i].name, name) {
|
||||||
self.attrs[i].value = value_cell.take();
|
self.attrs[i].value = value_cell.take().clone();
|
||||||
return;
|
found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.attrs.push(Attr::new(name.to_str(), value_cell.take()));
|
if !found {
|
||||||
|
self.attrs.push(Attr::new(name.to_str(), value_cell.take().clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.parent.owner_doc {
|
||||||
|
Some(owner) => owner.content_changed(),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getClientRects(&self) -> Option<@mut ClientRectListImpl> {
|
fn getClientRects(&self) -> Option<@mut ClientRectList> {
|
||||||
Some(@mut ClientRectListImpl::new())
|
Some(ClientRectList::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
43
src/servo/dom/htmlcollection.rs
Normal file
43
src/servo/dom/htmlcollection.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use dom::bindings::utils::WrapperCache;
|
||||||
|
use dom::bindings::utils::{DOMString, ErrorResult};
|
||||||
|
use dom::node::AbstractNode;
|
||||||
|
|
||||||
|
use js::jsapi::{JSObject, JSContext};
|
||||||
|
|
||||||
|
pub struct HTMLCollection {
|
||||||
|
elements: ~[AbstractNode],
|
||||||
|
wrapper: WrapperCache
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl HTMLCollection {
|
||||||
|
fn new(elements: ~[AbstractNode]) -> @mut HTMLCollection {
|
||||||
|
let collection = @mut HTMLCollection {
|
||||||
|
elements: elements,
|
||||||
|
wrapper: WrapperCache::new()
|
||||||
|
};
|
||||||
|
collection.init_wrapper();
|
||||||
|
collection
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Length(&self) -> u32 {
|
||||||
|
self.elements.len() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Item(&self, index: u32) -> Option<AbstractNode> {
|
||||||
|
if index < self.Length() {
|
||||||
|
Some(self.elements[index])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn NamedItem(&self, _cx: *JSContext, _name: DOMString, rv: &mut ErrorResult) -> *JSObject {
|
||||||
|
*rv = Ok(());
|
||||||
|
ptr::null()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<AbstractNode> {
|
||||||
|
*found = true;
|
||||||
|
self.Item(index)
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,13 +6,15 @@
|
||||||
// The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
|
// The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use content::content_task::global_content;
|
||||||
use dom::bindings;
|
use dom::bindings;
|
||||||
use dom::bindings::codegen;
|
use dom::bindings::codegen;
|
||||||
|
use dom::bindings::node;
|
||||||
use dom::bindings::utils::WrapperCache;
|
use dom::bindings::utils::WrapperCache;
|
||||||
|
use dom::characterdata::CharacterData;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::{Element, ElementTypeId, HTMLImageElement, HTMLImageElementTypeId};
|
use dom::element::{Element, ElementTypeId, HTMLImageElement, HTMLImageElementTypeId};
|
||||||
use dom::element::{HTMLStyleElementTypeId};
|
use dom::element::{HTMLStyleElementTypeId};
|
||||||
use dom::window::Window;
|
|
||||||
use layout::debug::DebugMethods;
|
use layout::debug::DebugMethods;
|
||||||
use layout::flow::FlowContext;
|
use layout::flow::FlowContext;
|
||||||
use newcss::complete::CompleteSelectResults;
|
use newcss::complete::CompleteSelectResults;
|
||||||
|
@ -47,6 +49,8 @@ pub struct Node {
|
||||||
next_sibling: Option<AbstractNode>,
|
next_sibling: Option<AbstractNode>,
|
||||||
prev_sibling: Option<AbstractNode>,
|
prev_sibling: Option<AbstractNode>,
|
||||||
|
|
||||||
|
owner_doc: Option<@mut Document>,
|
||||||
|
|
||||||
// You must not touch this if you are not layout.
|
// You must not touch this if you are not layout.
|
||||||
priv layout_data: Option<@mut LayoutData>
|
priv layout_data: Option<@mut LayoutData>
|
||||||
}
|
}
|
||||||
|
@ -106,29 +110,25 @@ impl Doctype {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Comment {
|
pub struct Comment {
|
||||||
parent: Node,
|
parent: CharacterData,
|
||||||
text: ~str,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Comment {
|
impl Comment {
|
||||||
pub fn new(text: ~str) -> Comment {
|
pub fn new(text: ~str) -> Comment {
|
||||||
Comment {
|
Comment {
|
||||||
parent: Node::new(CommentNodeTypeId),
|
parent: CharacterData::new(CommentNodeTypeId, text)
|
||||||
text: text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Text {
|
pub struct Text {
|
||||||
parent: Node,
|
parent: CharacterData,
|
||||||
text: ~str,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Text {
|
impl Text {
|
||||||
pub fn new(text: ~str) -> Text {
|
pub fn new(text: ~str) -> Text {
|
||||||
Text {
|
Text {
|
||||||
parent: Node::new(TextNodeTypeId),
|
parent: CharacterData::new(TextNodeTypeId, text)
|
||||||
text: text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,6 +316,12 @@ pub impl AbstractNode {
|
||||||
unsafe fn raw_object(self) -> *mut Node {
|
unsafe fn raw_object(self) -> *mut Node {
|
||||||
self.obj
|
self.obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_raw(raw: *mut Node) -> AbstractNode {
|
||||||
|
AbstractNode {
|
||||||
|
obj: raw
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugMethods for AbstractNode {
|
impl DebugMethods for AbstractNode {
|
||||||
|
@ -348,8 +354,25 @@ impl DebugMethods for AbstractNode {
|
||||||
impl Node {
|
impl Node {
|
||||||
pub unsafe fn as_abstract_node<N>(node: ~N) -> AbstractNode {
|
pub unsafe fn as_abstract_node<N>(node: ~N) -> AbstractNode {
|
||||||
// This surrenders memory management of the node!
|
// This surrenders memory management of the node!
|
||||||
AbstractNode {
|
let mut node = AbstractNode {
|
||||||
obj: transmute(node),
|
obj: transmute(node),
|
||||||
|
};
|
||||||
|
let cx = global_content().compartment.get().cx.ptr;
|
||||||
|
node::create(cx, &mut node);
|
||||||
|
node
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_to_doc(&mut self, doc: @mut Document) {
|
||||||
|
self.owner_doc = Some(doc);
|
||||||
|
let mut node = self.first_child;
|
||||||
|
while node.is_some() {
|
||||||
|
node.get().traverse_preorder(|n| {
|
||||||
|
do n.with_mut_node |n| {
|
||||||
|
n.owner_doc = Some(doc);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
});
|
||||||
|
node = node.get().next_sibling();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,16 +387,19 @@ impl Node {
|
||||||
next_sibling: None,
|
next_sibling: None,
|
||||||
prev_sibling: None,
|
prev_sibling: None,
|
||||||
|
|
||||||
|
owner_doc: None,
|
||||||
|
|
||||||
layout_data: None,
|
layout_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn define_bindings(compartment: @mut Compartment, doc: @mut Document, win: @mut Window) {
|
pub fn define_bindings(compartment: @mut Compartment) {
|
||||||
bindings::window::init(compartment, win);
|
bindings::window::init(compartment);
|
||||||
bindings::document::init(compartment, doc);
|
bindings::document::init(compartment);
|
||||||
bindings::node::init(compartment);
|
bindings::node::init(compartment);
|
||||||
bindings::element::init(compartment);
|
bindings::element::init(compartment);
|
||||||
|
bindings::text::init(compartment);
|
||||||
bindings::utils::initialize_global(compartment.global_obj.ptr);
|
bindings::utils::initialize_global(compartment.global_obj.ptr);
|
||||||
let mut unused = false;
|
let mut unused = false;
|
||||||
assert!(codegen::ClientRectBinding::DefineDOMInterface(compartment.cx.ptr,
|
assert!(codegen::ClientRectBinding::DefineDOMInterface(compartment.cx.ptr,
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use content::content_task::{ControlMsg, Timer, ExitMsg};
|
use content::content_task::{ControlMsg, Timer, ExitMsg, global_content};
|
||||||
use dom::bindings::utils::WrapperCache;
|
use dom::bindings::utils::WrapperCache;
|
||||||
|
use dom::bindings::window;
|
||||||
|
use dom::event::Event;
|
||||||
use js::jsapi::JSVal;
|
use js::jsapi::JSVal;
|
||||||
use util::task::spawn_listener;
|
use util::task::spawn_listener;
|
||||||
|
|
||||||
use core::comm::{Port, Chan};
|
use core::comm::{Port, Chan, SharedChan};
|
||||||
use std::timer;
|
use std::timer;
|
||||||
use std::uv_global_loop;
|
use std::uv_global_loop;
|
||||||
|
|
||||||
|
@ -19,6 +21,7 @@ pub enum TimerControlMsg {
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
timer_chan: Chan<TimerControlMsg>,
|
timer_chan: Chan<TimerControlMsg>,
|
||||||
|
dom_event_chan: SharedChan<Event>,
|
||||||
wrapper: WrapperCache
|
wrapper: WrapperCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,10 +80,12 @@ pub impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Window(content_chan: comm::SharedChan<ControlMsg>) -> Window {
|
pub fn Window(content_chan: comm::SharedChan<ControlMsg>,
|
||||||
|
dom_event_chan: comm::SharedChan<Event>) -> @mut Window {
|
||||||
|
|
||||||
Window {
|
let win = @mut Window {
|
||||||
wrapper: WrapperCache::new(),
|
wrapper: WrapperCache::new(),
|
||||||
|
dom_event_chan: dom_event_chan,
|
||||||
timer_chan: do spawn_listener |timer_port: Port<TimerControlMsg>| {
|
timer_chan: do spawn_listener |timer_port: Port<TimerControlMsg>| {
|
||||||
loop {
|
loop {
|
||||||
match timer_port.recv() {
|
match timer_port.recv() {
|
||||||
|
@ -92,5 +97,8 @@ pub fn Window(content_chan: comm::SharedChan<ControlMsg>) -> Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
let compartment = global_content().compartment.get();
|
||||||
|
window::create(compartment, win);
|
||||||
|
win
|
||||||
}
|
}
|
||||||
|
|
|
@ -489,7 +489,7 @@ pub impl LayoutTreeBuilder {
|
||||||
|
|
||||||
// FIXME: Don't copy text. I guess it should be atomically reference counted?
|
// FIXME: Don't copy text. I guess it should be atomically reference counted?
|
||||||
do node.with_imm_text |text_node| {
|
do node.with_imm_text |text_node| {
|
||||||
let string = text_node.text.to_str();
|
let string = text_node.parent.data.to_str();
|
||||||
@mut UnscannedTextBox(RenderBoxData(node, ctx, self.next_box_id()), string)
|
@mut UnscannedTextBox(RenderBoxData(node, ctx, self.next_box_id()), string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ pub mod dom {
|
||||||
pub mod document;
|
pub mod document;
|
||||||
pub mod element;
|
pub mod element;
|
||||||
pub mod node;
|
pub mod node;
|
||||||
|
pub mod text;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod conversions;
|
pub mod conversions;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
@ -77,10 +78,14 @@ pub mod dom {
|
||||||
pub mod HTMLCollectionBinding;
|
pub mod HTMLCollectionBinding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub mod characterdata;
|
||||||
|
pub mod clientrect;
|
||||||
|
pub mod clientrectlist;
|
||||||
pub mod document;
|
pub mod document;
|
||||||
pub mod domparser;
|
pub mod domparser;
|
||||||
pub mod element;
|
pub mod element;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
|
pub mod htmlcollection;
|
||||||
pub mod node;
|
pub mod node;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
window.alert("1");
|
window.alert("1");
|
||||||
let elem = document.documentElement;
|
let elem = document.documentElement;
|
||||||
|
window.alert(elem.nodeType);
|
||||||
window.alert(elem);
|
window.alert(elem);
|
||||||
window.alert("2");
|
window.alert("2");
|
||||||
var rects = elem.getClientRects();
|
var rects = elem.getClientRects();
|
||||||
|
@ -24,11 +25,13 @@ window.alert(rect.width);
|
||||||
window.alert(rect.height);
|
window.alert(rect.height);
|
||||||
|
|
||||||
window.alert("HTMLCollection:");
|
window.alert("HTMLCollection:");
|
||||||
let tags = document.getElementsByTagName("head");
|
let tags = document.getElementsByTagName("div");
|
||||||
//let tag = tags[0];
|
//let tag = tags[0];
|
||||||
window.alert(tags);
|
window.alert(tags);
|
||||||
window.alert(tags.length);
|
window.alert(tags.length);
|
||||||
window.alert(tags[0]);
|
window.alert(tags[0]);
|
||||||
|
window.alert(tags[0].tagName);
|
||||||
|
window.alert(tags[0].getClientRects());
|
||||||
window.alert(tags[1]);
|
window.alert(tags[1]);
|
||||||
window.alert(tags[2]);
|
window.alert(tags[2]);
|
||||||
window.alert(tags[3]);
|
window.alert(tags[3]);
|
||||||
|
|
3
src/test/test_hammer_layout.css
Normal file
3
src/test/test_hammer_layout.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
div #styled {
|
||||||
|
color: red;
|
||||||
|
}
|
9
src/test/test_hammer_layout.html
Normal file
9
src/test/test_hammer_layout.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="test_hammer_layout.css">
|
||||||
|
<script src="test_hammer_layout.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="styled">This text is unstyled.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
17
src/test/test_hammer_layout.js
Normal file
17
src/test/test_hammer_layout.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
window.setTimeout(function() {
|
||||||
|
//var divs = document.getElementsByTagName("div");
|
||||||
|
// divs[0].setAttribute('id', 'styled');
|
||||||
|
function print_tree(n) {
|
||||||
|
window.alert(n.nodeType);
|
||||||
|
//window.alert(n.tagName);
|
||||||
|
n = n.firstChild;
|
||||||
|
while (n) {
|
||||||
|
print_tree(n);
|
||||||
|
n = n.nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_tree(document.documentElement);
|
||||||
|
//window.alert(document.documentElement.tagName);
|
||||||
|
//window.alert(document.documentElement.firstChild.nodeType);
|
||||||
|
//window.alert(document.documentElement.firstChild.firstChild.nodeType);
|
||||||
|
}, 200);
|
Loading…
Add table
Add a link
Reference in a new issue