mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
commit
8931d17a6f
39 changed files with 1284 additions and 469 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit 19a4939e13f2387cb7831623480d91301092c202
|
Subproject commit bfe6b9544ff0df852bdca16a68770b9381e5f35c
|
7
src/patches/README
Normal file
7
src/patches/README
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Patches live here for submodules that should remain as pristine as possible.
|
||||||
|
This will allow us to unconditionally update them, then apply necessary
|
||||||
|
patches as needed.
|
||||||
|
|
||||||
|
* mozjs-stack-bounds.diff:
|
||||||
|
add a public API to overwrite the engine's computed stack bounds for
|
||||||
|
GC scanning.
|
77
src/patches/mozjs-stack-bounds.diff
Normal file
77
src/patches/mozjs-stack-bounds.diff
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
|
||||||
|
index 5571fc0..7e1e30d 100644
|
||||||
|
--- a/js/src/jsapi.cpp
|
||||||
|
+++ b/js/src/jsapi.cpp
|
||||||
|
@@ -735,6 +735,7 @@ JSRuntime::JSRuntime()
|
||||||
|
#endif
|
||||||
|
selfHostedGlobal_(NULL),
|
||||||
|
nativeStackBase(0),
|
||||||
|
+ nativeStackEnd(0),
|
||||||
|
nativeStackQuota(0),
|
||||||
|
interpreterFrames(NULL),
|
||||||
|
cxCallback(NULL),
|
||||||
|
@@ -7084,6 +7085,18 @@ JS_SetRuntimeThread(JSRuntime *rt)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
+extern JS_PUBLIC_API(void)
|
||||||
|
+JS_SetNativeStackBounds(JSRuntime *rt, uintptr_t minValue, uintptr_t maxValue)
|
||||||
|
+{
|
||||||
|
+#if JS_STACK_GROWTH_DIRECTION < 0
|
||||||
|
+ rt->nativeStackBase = maxValue;
|
||||||
|
+ rt->nativeStackEnd = minValue;
|
||||||
|
+#else
|
||||||
|
+ rt->nativeStackBase = minValue;
|
||||||
|
+ rt->nativeStackEnd = maxValue;
|
||||||
|
+#endif
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
extern JS_NEVER_INLINE JS_PUBLIC_API(void)
|
||||||
|
JS_AbortIfWrongThread(JSRuntime *rt)
|
||||||
|
{
|
||||||
|
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
|
||||||
|
index c8ab0f0..9ac582e 100644
|
||||||
|
--- a/js/src/jsapi.h
|
||||||
|
+++ b/js/src/jsapi.h
|
||||||
|
@@ -6248,6 +6248,9 @@ JS_ClearRuntimeThread(JSRuntime *rt);
|
||||||
|
extern JS_PUBLIC_API(void)
|
||||||
|
JS_SetRuntimeThread(JSRuntime *rt);
|
||||||
|
|
||||||
|
+extern JS_PUBLIC_API(void)
|
||||||
|
+JS_SetNativeStackBounds(JSRuntime *rt, uintptr_t minValue, uintptr_t maxValue);
|
||||||
|
+
|
||||||
|
#ifdef __cplusplus
|
||||||
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
|
diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h
|
||||||
|
index 0bb6d1c..32e016e 100644
|
||||||
|
--- a/js/src/jscntxt.h
|
||||||
|
+++ b/js/src/jscntxt.h
|
||||||
|
@@ -439,6 +439,9 @@ struct JSRuntime : js::RuntimeFriendFields
|
||||||
|
/* Base address of the native stack for the current thread. */
|
||||||
|
uintptr_t nativeStackBase;
|
||||||
|
|
||||||
|
+ /* Base address of the native stack for the current thread. */
|
||||||
|
+ uintptr_t nativeStackEnd;
|
||||||
|
+
|
||||||
|
/* The native stack size limit that runtime should not exceed. */
|
||||||
|
size_t nativeStackQuota;
|
||||||
|
|
||||||
|
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
|
||||||
|
index f5cbc62..eae29da 100644
|
||||||
|
--- a/js/src/jsgc.cpp
|
||||||
|
+++ b/js/src/jsgc.cpp
|
||||||
|
@@ -1177,9 +1177,11 @@ MarkConservativeStackRoots(JSTracer *trc, bool useSavedRoots)
|
||||||
|
uintptr_t *stackMin, *stackEnd;
|
||||||
|
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||||
|
stackMin = rt->nativeStackBase;
|
||||||
|
- stackEnd = cgcd->nativeStackTop;
|
||||||
|
+ stackEnd = rt->nativeStackEnd ? reinterpret_cast<uintptr_t*>(rt->nativeStackEnd)
|
||||||
|
+ : cgcd->nativeStackTop;
|
||||||
|
#else
|
||||||
|
- stackMin = cgcd->nativeStackTop + 1;
|
||||||
|
+ stackMin = rt->nativeStackEnd ? reinterpret_cast<uintptr_t*>(rt->nativeStackEnd)
|
||||||
|
+ : cgcd->nativeStackTop + 1;
|
||||||
|
stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase);
|
||||||
|
#endif
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit aefcf146400a42e7302243db2844f4022f938fc0
|
Subproject commit fe2f31f7f33150615e0cc5385cf869053e64a65a
|
|
@ -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,14 @@ 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(),
|
||||||
|
ptr::to_mut_unsafe_ptr(&mut *self)); //FIXME store this safely
|
||||||
|
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 +245,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);
|
||||||
|
@ -322,7 +345,7 @@ pub impl Content {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_layout(&mut self, query: layout_task::LayoutQuery) -> layout_task::LayoutQueryResponse {
|
fn query_layout(&mut self, query: layout_task::LayoutQuery) -> layout_task::LayoutQueryResponse {
|
||||||
self.relayout(self.document.get(), &(copy self.doc_url).get());
|
//self.relayout(self.document.get(), &(copy self.doc_url).get());
|
||||||
self.join_layout();
|
self.join_layout();
|
||||||
|
|
||||||
let (response_port, response_chan) = comm::stream();
|
let (response_port, response_chan) = comm::stream();
|
||||||
|
|
|
@ -2,79 +2,54 @@
|
||||||
* 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, OpaqueBindingReference};
|
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
|
||||||
use dom::bindings::codegen::ClientRectBinding;
|
use dom::bindings::codegen::ClientRectBinding;
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use dom::clientrect::ClientRect;
|
||||||
|
use js::jsapi::{JSObject, JSContext, 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) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||||
let mut unused = false;
|
let mut unused = false;
|
||||||
ClientRectBinding::Wrap(cx, scope, self, &mut unused)
|
ClientRectBinding::Wrap(cx, scope, self, &mut unused)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
impl BindingObject for ClientRect {
|
||||||
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
|
let content = task_from_context(cx);
|
||||||
|
unsafe { (*content).window.get() as @mut CacheableWrapper }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerivedWrapper for ClientRect {
|
||||||
|
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
|
||||||
fail!(~"nyi")
|
fail!(~"nyi")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl BindingObject for ClientRectImpl {
|
fn wrap_shared(@mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
|
let obj = self.wrap_object_shared(cx, scope);
|
||||||
let content = task_from_context(cx);
|
if obj.is_null() {
|
||||||
unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
|
return 0;
|
||||||
|
} else {
|
||||||
|
unsafe { *vp = RUST_OBJECT_TO_JSVAL(obj) };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,70 +2,37 @@
|
||||||
* 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, OpaqueBindingReference};
|
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<~ClientRectImpl>;
|
let content = global_content();
|
||||||
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<~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<~ClientRectImpl> {
|
|
||||||
if index < self.rects.len() as u32 {
|
|
||||||
let (top, bottom, left, right) = self.rects[index];
|
|
||||||
Some(~ClientRect(top, bottom, left, right))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<~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) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||||
let mut unused = false;
|
let mut unused = false;
|
||||||
ClientRectListBinding::Wrap(cx, scope, self, &mut unused)
|
ClientRectListBinding::Wrap(cx, scope, self, &mut unused)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
|
||||||
fail!(~"nyi")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindingObject for ClientRectListImpl {
|
impl BindingObject for ClientRectList {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let content = task_from_context(cx);
|
let content = task_from_context(cx);
|
||||||
unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
|
unsafe { (*content).window.get() as @mut CacheableWrapper }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -115,15 +115,14 @@ DOMInterfaces = {
|
||||||
|
|
||||||
'ClientRect': [
|
'ClientRect': [
|
||||||
{
|
{
|
||||||
'nativeType': 'ClientRectImpl',
|
'nativeType': 'ClientRect',
|
||||||
|
'pointerType': '@mut '
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'ClientRectList': [
|
'ClientRectList': [
|
||||||
{
|
{
|
||||||
'nativeType': 'ClientRectListImpl',
|
'nativeType': 'ClientRectList',
|
||||||
#'headerFile': 'nsClientRect.h',
|
'pointerType': '@mut '
|
||||||
#'prefable': True,
|
|
||||||
#'resultNotAddRefed': [ 'item' ]
|
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'CSS2Properties': {
|
'CSS2Properties': {
|
||||||
|
@ -136,13 +135,10 @@ DOMInterfaces = {
|
||||||
'prefable': True
|
'prefable': True
|
||||||
},
|
},
|
||||||
|
|
||||||
'Document': [
|
'DOMParser': {
|
||||||
{
|
'nativeType': 'DOMParser',
|
||||||
'nativeType': 'nsIDocument',
|
'pointerType': '@mut '
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'workers': True,
|
|
||||||
}],
|
|
||||||
|
|
||||||
'DOMSettableTokenList': [
|
'DOMSettableTokenList': [
|
||||||
{
|
{
|
||||||
|
@ -213,8 +209,7 @@ DOMInterfaces = {
|
||||||
'HTMLCollection': [
|
'HTMLCollection': [
|
||||||
{
|
{
|
||||||
'nativeType': 'HTMLCollection',
|
'nativeType': 'HTMLCollection',
|
||||||
#'prefable': True,
|
'pointerType': '@mut '
|
||||||
#'resultNotAddRefed': [ 'item' ]
|
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'HTMLOptionsCollection': [
|
'HTMLOptionsCollection': [
|
||||||
|
@ -516,9 +511,9 @@ addExternalHTMLElement('HTMLOptGroupElement')
|
||||||
addExternalHTMLElement('HTMLVideoElement')
|
addExternalHTMLElement('HTMLVideoElement')
|
||||||
addExternalIface('CanvasGradient', headerFile='nsIDOMCanvasRenderingContext2D.h')
|
addExternalIface('CanvasGradient', headerFile='nsIDOMCanvasRenderingContext2D.h')
|
||||||
addExternalIface('CanvasPattern', headerFile='nsIDOMCanvasRenderingContext2D.h')
|
addExternalIface('CanvasPattern', headerFile='nsIDOMCanvasRenderingContext2D.h')
|
||||||
#addExternalIface('ClientRect')
|
|
||||||
addExternalIface('CSSRule')
|
addExternalIface('CSSRule')
|
||||||
addExternalIface('CSSValue')
|
addExternalIface('CSSValue')
|
||||||
|
addExternalIface('Document', nativeType='Document', pointerType='@mut ')
|
||||||
addExternalIface('DOMStringList', nativeType='nsDOMStringList',
|
addExternalIface('DOMStringList', nativeType='nsDOMStringList',
|
||||||
headerFile='nsDOMLists.h')
|
headerFile='nsDOMLists.h')
|
||||||
addExternalIface('Element', nativeType='AbstractNode', pointerType='')
|
addExternalIface('Element', nativeType='AbstractNode', pointerType='')
|
||||||
|
|
|
@ -1098,22 +1098,19 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
"yet")
|
"yet")
|
||||||
enum = type.inner.identifier.name
|
enum = type.inner.identifier.name
|
||||||
if invalidEnumValueFatal:
|
if invalidEnumValueFatal:
|
||||||
handleInvalidEnumValueCode = " MOZ_ASSERT(index >= 0);\n"
|
handleInvalidEnumValueCode = " return 0;\n"
|
||||||
else:
|
else:
|
||||||
handleInvalidEnumValueCode = (
|
handleInvalidEnumValueCode = " return 1;\n"
|
||||||
" if (index < 0) {\n"
|
|
||||||
" return true;\n"
|
|
||||||
" }\n")
|
|
||||||
|
|
||||||
template = (
|
template = (
|
||||||
"{\n"
|
"{\n"
|
||||||
" bool ok;\n"
|
#" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
|
||||||
" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
|
" let result = FindEnumStringIndex(cx, ${val}, %(values)s);\n"
|
||||||
" if (!ok) {\n"
|
" if result.is_err() {\n"
|
||||||
" return false;\n"
|
|
||||||
" }\n"
|
|
||||||
"%(handleInvalidEnumValueCode)s"
|
"%(handleInvalidEnumValueCode)s"
|
||||||
" ${declName} = static_cast<%(enumtype)s>(index);\n"
|
" }\n"
|
||||||
|
" let index = result.get();\n"
|
||||||
|
" ${declName} = cast::transmute(index); //XXXjdm need some range checks up in here\n"
|
||||||
"}" % { "enumtype" : enum,
|
"}" % { "enumtype" : enum,
|
||||||
"values" : enum + "Values::strings",
|
"values" : enum + "Values::strings",
|
||||||
"invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
|
"invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
|
||||||
|
@ -1529,7 +1526,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
if not isCreator:
|
if not isCreator:
|
||||||
raise MethodNotCreatorError(descriptor.interface.identifier.name)
|
raise MethodNotCreatorError(descriptor.interface.identifier.name)
|
||||||
wrapMethod = "WrapNewBindingNonWrapperCachedObject"
|
wrapMethod = "WrapNewBindingNonWrapperCachedObject"
|
||||||
wrap = "%s(cx, ${obj}, %s, ${jsvalPtr})" % (wrapMethod, result)
|
wrap = "%s(cx, ${obj}, %s as @mut CacheableWrapper, ${jsvalPtr})" % (wrapMethod, result)
|
||||||
# We don't support prefable stuff in workers.
|
# We don't support prefable stuff in workers.
|
||||||
assert(not descriptor.prefable or not descriptor.workers)
|
assert(not descriptor.prefable or not descriptor.workers)
|
||||||
if not descriptor.prefable:
|
if not descriptor.prefable:
|
||||||
|
@ -1547,12 +1544,11 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalPtr})" % result)
|
failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalPtr})" % result)
|
||||||
wrappingCode += wrapAndSetPtr(wrap, failed)
|
wrappingCode += wrapAndSetPtr(wrap, failed)
|
||||||
else:
|
else:
|
||||||
if descriptor.notflattened:
|
|
||||||
getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
|
|
||||||
else:
|
|
||||||
getIID = ""
|
|
||||||
#wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID)
|
#wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID)
|
||||||
wrap = "%s.wrap(cx, ${obj}, %s${jsvalPtr})" % (result, getIID)
|
if descriptor.pointerType == '':
|
||||||
|
wrap = "%s.wrap(cx, ${obj}, ${jsvalPtr})" % result
|
||||||
|
else:
|
||||||
|
wrap = "if WrapNewBindingObject(cx, ${obj}, %s as @mut CacheableWrapper, ${jsvalPtr}) { 1 } else { 0 };" % result
|
||||||
wrappingCode += wrapAndSetPtr(wrap)
|
wrappingCode += wrapAndSetPtr(wrap)
|
||||||
return (wrappingCode, False)
|
return (wrappingCode, False)
|
||||||
|
|
||||||
|
@ -1701,10 +1697,10 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
|
||||||
descriptor = descriptorProvider.getDescriptor(
|
descriptor = descriptorProvider.getDescriptor(
|
||||||
returnType.unroll().inner.identifier.name)
|
returnType.unroll().inner.identifier.name)
|
||||||
result = CGGeneric(descriptor.nativeType)
|
result = CGGeneric(descriptor.nativeType)
|
||||||
if resultAlreadyAddRefed:
|
if returnType.nullable():
|
||||||
result = CGWrapper(result, pre=("Option<" + descriptor.pointerType), post=">")
|
result = CGWrapper(result, pre=("Option<" + descriptor.pointerType), post=">")
|
||||||
else:
|
else:
|
||||||
result = CGWrapper(result, post="*")
|
result = CGWrapper(result, pre=descriptor.pointerType)
|
||||||
return result, False
|
return result, False
|
||||||
if returnType.isCallback():
|
if returnType.isCallback():
|
||||||
# XXXbz we're going to assume that callback types are always
|
# XXXbz we're going to assume that callback types are always
|
||||||
|
@ -2154,20 +2150,23 @@ class CGIfWrapper(CGWrapper):
|
||||||
post="\n}")
|
post="\n}")
|
||||||
|
|
||||||
class CGNamespace(CGWrapper):
|
class CGNamespace(CGWrapper):
|
||||||
def __init__(self, namespace, child, declareOnly=False):
|
def __init__(self, namespace, child, declareOnly=False, public=False):
|
||||||
pre = "mod %s {\n" % namespace
|
pre = "%smod %s {\n" % ("pub " if public else "", namespace)
|
||||||
post = "} // mod %s\n" % namespace
|
post = "} // mod %s\n" % namespace
|
||||||
CGWrapper.__init__(self, child, pre=pre, post=post,
|
CGWrapper.__init__(self, child, pre=pre, post=post,
|
||||||
declareOnly=declareOnly)
|
declareOnly=declareOnly)
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def build(namespaces, child, declareOnly=False):
|
def build(namespaces, child, declareOnly=False, public=False):
|
||||||
"""
|
"""
|
||||||
Static helper method to build multiple wrapped namespaces.
|
Static helper method to build multiple wrapped namespaces.
|
||||||
"""
|
"""
|
||||||
if not namespaces:
|
if not namespaces:
|
||||||
return CGWrapper(child, declareOnly=declareOnly)
|
return CGWrapper(child, declareOnly=declareOnly)
|
||||||
inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly)
|
inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly, public=public)
|
||||||
return CGNamespace(namespaces[0], inner, declareOnly=declareOnly)
|
return CGNamespace(namespaces[0], inner, declareOnly=declareOnly, public=public)
|
||||||
|
|
||||||
|
def declare(self):
|
||||||
|
return ""
|
||||||
|
|
||||||
def DOMClass(descriptor):
|
def DOMClass(descriptor):
|
||||||
protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
|
protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
|
||||||
|
@ -2440,7 +2439,7 @@ def CreateBindingJSObject(descriptor, parent):
|
||||||
let handler = (*content).dom_static.proxy_handlers.get(&(prototypes::id::%s as uint));
|
let handler = (*content).dom_static.proxy_handlers.get(&(prototypes::id::%s as uint));
|
||||||
""" % descriptor.name
|
""" % descriptor.name
|
||||||
create = handler + """ let obj = NewProxyObject(aCx, *handler,
|
create = handler + """ let obj = NewProxyObject(aCx, *handler,
|
||||||
ptr::addr_of(&RUST_PRIVATE_TO_JSVAL(squirrel_away_ref(aObject) as *libc::c_void)),
|
ptr::addr_of(&RUST_PRIVATE_TO_JSVAL(squirrel_away(aObject) as *libc::c_void)),
|
||||||
proto, %s,
|
proto, %s,
|
||||||
ptr::null(), ptr::null());
|
ptr::null(), ptr::null());
|
||||||
if obj.is_null() {
|
if obj.is_null() {
|
||||||
|
@ -2455,7 +2454,7 @@ def CreateBindingJSObject(descriptor, parent):
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_SetReservedSlot(obj, DOM_OBJECT_SLOT as u32,
|
JS_SetReservedSlot(obj, DOM_OBJECT_SLOT as u32,
|
||||||
RUST_PRIVATE_TO_JSVAL(squirrel_away_ref(aObject) as *libc::c_void));
|
RUST_PRIVATE_TO_JSVAL(squirrel_away(aObject) as *libc::c_void));
|
||||||
"""
|
"""
|
||||||
return create % parent
|
return create % parent
|
||||||
|
|
||||||
|
@ -2463,7 +2462,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
assert descriptor.interface.hasInterfacePrototypeObject()
|
assert descriptor.interface.hasInterfacePrototypeObject()
|
||||||
args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'),
|
args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'),
|
||||||
Argument('&mut BindingReference<' + descriptor.nativeType + '>', 'aObject'),
|
Argument('@mut ' + descriptor.nativeType, 'aObject'),
|
||||||
Argument('*mut bool', 'aTriedToWrap')]
|
Argument('*mut bool', 'aTriedToWrap')]
|
||||||
CGAbstractMethod.__init__(self, descriptor, 'Wrap_', '*JSObject', args)
|
CGAbstractMethod.__init__(self, descriptor, 'Wrap_', '*JSObject', args)
|
||||||
|
|
||||||
|
@ -2474,7 +2473,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
|
||||||
|
|
||||||
return """ *aTriedToWrap = true;
|
return """ *aTriedToWrap = true;
|
||||||
let mut parent = aObject.GetParentObject(aCx);
|
let mut parent = aObject.GetParentObject(aCx);
|
||||||
let parent = WrapNativeParent(aCx, aScope, &mut parent);
|
let parent = WrapNativeParent(aCx, aScope, parent);
|
||||||
if parent.is_null() {
|
if parent.is_null() {
|
||||||
return ptr::null();
|
return ptr::null();
|
||||||
}
|
}
|
||||||
|
@ -2502,12 +2501,11 @@ class CGWrapMethod(CGAbstractMethod):
|
||||||
# XXX can we wrap if we don't have an interface prototype object?
|
# XXX can we wrap if we don't have an interface prototype object?
|
||||||
assert descriptor.interface.hasInterfacePrototypeObject()
|
assert descriptor.interface.hasInterfacePrototypeObject()
|
||||||
args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'),
|
args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'),
|
||||||
Argument('~' + descriptor.nativeType, 'aObject'), Argument('*mut bool', 'aTriedToWrap')]
|
Argument(descriptor.pointerType + descriptor.nativeType, 'aObject'), Argument('*mut bool', 'aTriedToWrap')]
|
||||||
CGAbstractMethod.__init__(self, descriptor, 'Wrap', '*JSObject', args, inline=True, pub=True)
|
CGAbstractMethod.__init__(self, descriptor, 'Wrap', '*JSObject', args, inline=True, pub=True)
|
||||||
|
|
||||||
def definition_body(self):
|
def definition_body(self):
|
||||||
return " let mut binding = BindingReference(Left(aObject)); \
|
return "return Wrap_(aCx, aScope, aObject, aTriedToWrap);"
|
||||||
return Wrap_(aCx, aScope, &mut binding, aTriedToWrap);"
|
|
||||||
|
|
||||||
class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
|
class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
|
@ -3167,7 +3165,7 @@ class CGGenericGetter(CGAbstractBindingMethod):
|
||||||
A class for generating the C++ code for an IDL attribute getter.
|
A class for generating the C++ code for an IDL attribute getter.
|
||||||
"""
|
"""
|
||||||
def __init__(self, descriptor, lenientThis=False):
|
def __init__(self, descriptor, lenientThis=False):
|
||||||
args = [Argument('*JSContext', 'cx'), Argument('uint', 'argc'),
|
args = [Argument('*JSContext', 'cx'), Argument('uint', '_argc'),
|
||||||
Argument('*JSVal', 'vp')]
|
Argument('*JSVal', 'vp')]
|
||||||
if lenientThis:
|
if lenientThis:
|
||||||
name = "genericLenientGetter"
|
name = "genericLenientGetter"
|
||||||
|
@ -3194,8 +3192,8 @@ class CGSpecializedGetter(CGAbstractExternMethod):
|
||||||
def __init__(self, descriptor, attr):
|
def __init__(self, descriptor, attr):
|
||||||
self.attr = attr
|
self.attr = attr
|
||||||
name = 'get_' + attr.identifier.name
|
name = 'get_' + attr.identifier.name
|
||||||
args = [ Argument('*JSContext', 'cx'),
|
args = [ Argument('*JSContext', '_cx'),
|
||||||
Argument('JSHandleObject', 'obj'),
|
Argument('JSHandleObject', '_obj'),
|
||||||
Argument('*%s' % descriptor.nativeType, 'self'),
|
Argument('*%s' % descriptor.nativeType, 'self'),
|
||||||
Argument('*mut JSVal', 'vp') ]
|
Argument('*mut JSVal', 'vp') ]
|
||||||
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
|
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
|
||||||
|
@ -3289,6 +3287,46 @@ class CGMemberJITInfo(CGThing):
|
||||||
return result
|
return result
|
||||||
raise TypeError("Illegal member type to CGPropertyJITInfo")
|
raise TypeError("Illegal member type to CGPropertyJITInfo")
|
||||||
|
|
||||||
|
def getEnumValueName(value):
|
||||||
|
# Some enum values can be empty strings. Others might have weird
|
||||||
|
# characters in them. Deal with the former by returning "_empty",
|
||||||
|
# deal with possible name collisions from that by throwing if the
|
||||||
|
# enum value is actually "_empty", and throw on any value
|
||||||
|
# containing non-ASCII chars for now. Replace all chars other than
|
||||||
|
# [0-9A-Za-z_] with '_'.
|
||||||
|
if re.match("[^\x20-\x7E]", value):
|
||||||
|
raise SyntaxError('Enum value "' + value + '" contains non-ASCII characters')
|
||||||
|
if re.match("^[0-9]", value):
|
||||||
|
raise SyntaxError('Enum value "' + value + '" starts with a digit')
|
||||||
|
value = re.sub(r'[^0-9A-Za-z_]', '_', value)
|
||||||
|
if re.match("^_[A-Z]|__", value):
|
||||||
|
raise SyntaxError('Enum value "' + value + '" is reserved by the C++ spec')
|
||||||
|
if value == "_empty":
|
||||||
|
raise SyntaxError('"_empty" is not an IDL enum value we support yet')
|
||||||
|
if value == "":
|
||||||
|
return "_empty"
|
||||||
|
return MakeNativeName(value)
|
||||||
|
|
||||||
|
class CGEnum(CGThing):
|
||||||
|
def __init__(self, enum):
|
||||||
|
CGThing.__init__(self)
|
||||||
|
self.enum = enum
|
||||||
|
|
||||||
|
def declare(self):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def define(self):
|
||||||
|
return """
|
||||||
|
pub enum valuelist {
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static strings: &'static [EnumEntry] = &[
|
||||||
|
%s,
|
||||||
|
];
|
||||||
|
""" % (",\n ".join(map(getEnumValueName, self.enum.values())),
|
||||||
|
",\n ".join(['EnumEntry {value: &"' + val + '", length: ' + str(len(val)) + '}' for val in self.enum.values()]))
|
||||||
|
|
||||||
class CGXrayHelper(CGAbstractExternMethod):
|
class CGXrayHelper(CGAbstractExternMethod):
|
||||||
def __init__(self, descriptor, name, args, properties):
|
def __init__(self, descriptor, name, args, properties):
|
||||||
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
|
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
|
||||||
|
@ -3334,7 +3372,7 @@ class CGXrayHelper(CGAbstractExternMethod):
|
||||||
class CGResolveProperty(CGXrayHelper):
|
class CGResolveProperty(CGXrayHelper):
|
||||||
def __init__(self, descriptor, properties):
|
def __init__(self, descriptor, properties):
|
||||||
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'wrapper'),
|
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'wrapper'),
|
||||||
Argument('jsid', 'id'), Argument('bool', 'set'),
|
Argument('jsid', 'id'), Argument('bool', '_set'),
|
||||||
Argument('*mut JSPropertyDescriptor', 'desc')]
|
Argument('*mut JSPropertyDescriptor', 'desc')]
|
||||||
CGXrayHelper.__init__(self, descriptor, "ResolveProperty", args,
|
CGXrayHelper.__init__(self, descriptor, "ResolveProperty", args,
|
||||||
properties)
|
properties)
|
||||||
|
@ -3431,7 +3469,7 @@ class CGProxyUnwrap(CGAbstractMethod):
|
||||||
class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
|
class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy'),
|
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy'),
|
||||||
Argument('*JSObject', 'receiver'), Argument('jsid', 'id'),
|
Argument('*JSObject', '_receiver'), Argument('jsid', 'id'),
|
||||||
Argument('*mut JSVal', 'vp')]
|
Argument('*mut JSVal', 'vp')]
|
||||||
CGAbstractExternMethod.__init__(self, descriptor, "get", "JSBool", args)
|
CGAbstractExternMethod.__init__(self, descriptor, "get", "JSBool", args)
|
||||||
self.descriptor = descriptor
|
self.descriptor = descriptor
|
||||||
|
@ -3504,7 +3542,7 @@ return 1;""" % (getIndexedOrExpando, getNamed)
|
||||||
|
|
||||||
class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
|
class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy')]
|
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', '_proxy')]
|
||||||
CGAbstractExternMethod.__init__(self, descriptor, "obj_toString", "*JSString", args)
|
CGAbstractExternMethod.__init__(self, descriptor, "obj_toString", "*JSString", args)
|
||||||
self.descriptor = descriptor
|
self.descriptor = descriptor
|
||||||
def getBody(self):
|
def getBody(self):
|
||||||
|
@ -3574,42 +3612,38 @@ let _: %s = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
|
||||||
#return clearWrapper + release
|
#return clearWrapper + release
|
||||||
return release
|
return release
|
||||||
|
|
||||||
class CGClassConstructHook(CGAbstractStaticMethod):
|
class CGClassConstructHook(CGAbstractExternMethod):
|
||||||
"""
|
"""
|
||||||
JS-visible constructor for our objects
|
JS-visible constructor for our objects
|
||||||
"""
|
"""
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
args = [Argument('*JSContext', 'cx'), Argument('unsigned', 'argc'), Argument('*jsval', 'vp')]
|
args = [Argument('*JSContext', 'cx'), Argument('u32', '_argc'), Argument('*mut JSVal', 'vp')]
|
||||||
CGAbstractStaticMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
|
CGAbstractExternMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
|
||||||
'JSBool', args)
|
'JSBool', args)
|
||||||
self._ctor = self.descriptor.interface.ctor()
|
self._ctor = self.descriptor.interface.ctor()
|
||||||
|
|
||||||
def define(self):
|
def define(self):
|
||||||
if not self._ctor:
|
if not self._ctor:
|
||||||
return ""
|
return ""
|
||||||
return CGAbstractStaticMethod.define(self)
|
return CGAbstractExternMethod.define(self)
|
||||||
|
|
||||||
def definition_body(self):
|
def definition_body(self):
|
||||||
return self.generate_code()
|
return self.generate_code()
|
||||||
|
|
||||||
def generate_code(self):
|
def generate_code(self):
|
||||||
preamble = """
|
preamble = """
|
||||||
JSObject* obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
|
//JSObject* obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
|
||||||
"""
|
"""
|
||||||
if self.descriptor.workers:
|
if self.descriptor.workers:
|
||||||
preArgs = ["cx", "obj"]
|
preArgs = ["cx", "obj"]
|
||||||
else:
|
else:
|
||||||
preamble += """
|
preamble += """
|
||||||
nsISupports* global;
|
//XXXjdm Gecko obtains a GlobalObject from the global (maybe from the private value,
|
||||||
xpc_qsSelfRef globalRef;
|
// or through unwrapping a slot or something). We'll punt and get the Window
|
||||||
{
|
// from the context for now.
|
||||||
nsresult rv;
|
let content = task_from_context(cx);
|
||||||
JS::Value val = OBJECT_TO_JSVAL(obj);
|
let global = (*content).window.get();
|
||||||
rv = xpc_qsUnwrapArg<nsISupports>(cx, val, &global, &globalRef.ptr, &val);
|
let obj = global.get_wrappercache().get_wrapper();
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
"""
|
||||||
preArgs = ["global"]
|
preArgs = ["global"]
|
||||||
|
|
||||||
|
@ -3675,7 +3709,7 @@ class CGClassFinalizeHook(CGAbstractClassHook):
|
||||||
A hook for finalize, used to release our native object.
|
A hook for finalize, used to release our native object.
|
||||||
"""
|
"""
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
args = [Argument('*JSFreeOp', 'fop'), Argument('*JSObject', 'obj')]
|
args = [Argument('*JSFreeOp', '_fop'), Argument('*JSObject', 'obj')]
|
||||||
CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
|
CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
|
||||||
'void', args)
|
'void', args)
|
||||||
|
|
||||||
|
@ -3835,6 +3869,17 @@ class CGBindingRoot(CGThing):
|
||||||
|
|
||||||
cgthings = []
|
cgthings = []
|
||||||
|
|
||||||
|
# Do codegen for all the enums
|
||||||
|
def makeEnum(e):
|
||||||
|
return CGNamespace.build([e.identifier.name + "Values"],
|
||||||
|
CGList([CGGeneric(" use dom::bindings::utils::EnumEntry;"),
|
||||||
|
CGEnum(e)]), public=True)
|
||||||
|
def makeEnumTypedef(e):
|
||||||
|
return CGGeneric(declare=("pub type %s = self::%sValues::valuelist;\n" %
|
||||||
|
(e.identifier.name, e.identifier.name)))
|
||||||
|
cgthings = [ fun(e) for e in config.getEnums(webIDLFile)
|
||||||
|
for fun in [makeEnum, makeEnumTypedef] ]
|
||||||
|
|
||||||
# Do codegen for all the descriptors
|
# Do codegen for all the descriptors
|
||||||
cgthings.extend([CGDescriptor(x) for x in descriptors])
|
cgthings.extend([CGDescriptor(x) for x in descriptors])
|
||||||
|
|
||||||
|
@ -3846,6 +3891,8 @@ class CGBindingRoot(CGThing):
|
||||||
# CGWrapper(curr, pre="\n"))
|
# CGWrapper(curr, pre="\n"))
|
||||||
|
|
||||||
# Add imports
|
# Add imports
|
||||||
|
#XXXjdm This should only import the namespace for the current binding,
|
||||||
|
# not every binding ever.
|
||||||
curr = CGImports(descriptors,
|
curr = CGImports(descriptors,
|
||||||
dictionaries,
|
dictionaries,
|
||||||
['js::*',
|
['js::*',
|
||||||
|
@ -3854,14 +3901,17 @@ class CGBindingRoot(CGThing):
|
||||||
'js::jsfriendapi::bindgen::*',
|
'js::jsfriendapi::bindgen::*',
|
||||||
'js::glue::bindgen::*',
|
'js::glue::bindgen::*',
|
||||||
'js::glue::*',
|
'js::glue::*',
|
||||||
'dom::node::AbstractNode',
|
'dom::node::AbstractNode', #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::*',
|
||||||
'content::content_task::task_from_context'
|
'dom::domparser::*', #XXXjdm
|
||||||
|
'content::content_task::task_from_context',
|
||||||
|
'dom::bindings::utils::EnumEntry',
|
||||||
],
|
],
|
||||||
[],
|
[],
|
||||||
curr)
|
curr)
|
||||||
|
|
48
src/servo/dom/bindings/codegen/DOMParser.webidl
Normal file
48
src/servo/dom/bindings/codegen/DOMParser.webidl
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/.
|
||||||
|
*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* http://domparsing.spec.whatwg.org/#the-domparser-interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*interface Principal;
|
||||||
|
interface URI;
|
||||||
|
interface InputStream;*/
|
||||||
|
interface Document;
|
||||||
|
|
||||||
|
enum SupportedType {
|
||||||
|
"text/html",
|
||||||
|
"text/xml",
|
||||||
|
"application/xml",
|
||||||
|
"application/xhtml+xml",
|
||||||
|
"image/svg+xml"
|
||||||
|
};
|
||||||
|
|
||||||
|
// the latter is Mozilla-specific
|
||||||
|
/*[Constructor,
|
||||||
|
Constructor(Principal? prin, optional URI? documentURI = null,
|
||||||
|
optional URI? baseURI = null)]*/
|
||||||
|
[Constructor]
|
||||||
|
interface DOMParser {
|
||||||
|
[Creator, Throws]
|
||||||
|
Document parseFromString(DOMString str, SupportedType type);
|
||||||
|
|
||||||
|
/* // Mozilla-specific stuff
|
||||||
|
// Throws if the passed-in length is greater than the actual sequence length
|
||||||
|
[Creator, Throws, ChromeOnly]
|
||||||
|
Document parseFromBuffer(sequence<octet> buf, unsigned long bufLen,
|
||||||
|
SupportedType type);
|
||||||
|
// Throws if the passed-in length is greater than the actual typed array length
|
||||||
|
[Creator, Throws, ChromeOnly]
|
||||||
|
Document parseFromBuffer(Uint8Array buf, unsigned long bufLen,
|
||||||
|
SupportedType type);
|
||||||
|
[Creator, Throws, ChromeOnly]
|
||||||
|
Document parseFromStream(InputStream stream, DOMString? charset,
|
||||||
|
long contentLength, SupportedType type);
|
||||||
|
[Throws, ChromeOnly]
|
||||||
|
void init(optional Principal? principal = null,
|
||||||
|
optional URI? documentURI = null,
|
||||||
|
optional URI? baseURI = null);*/
|
||||||
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "ClientRectBinding.h"
|
#include "ClientRectBinding.h"
|
||||||
#include "ClientRectListBinding.h"
|
#include "ClientRectListBinding.h"
|
||||||
|
#include "DOMParserBinding.h"
|
||||||
#include "HTMLCollectionBinding.h"
|
#include "HTMLCollectionBinding.h"
|
||||||
#include "nsScriptNameSpaceManager.h"
|
#include "nsScriptNameSpaceManager.h"
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ Register(nsScriptNameSpaceManager* aNameSpaceManager)
|
||||||
|
|
||||||
REGISTER_PROTO(ClientRect, nullptr);
|
REGISTER_PROTO(ClientRect, nullptr);
|
||||||
REGISTER_PROTO(ClientRectList, nullptr);
|
REGISTER_PROTO(ClientRectList, nullptr);
|
||||||
|
REGISTER_PROTO(DOMParser, nullptr);
|
||||||
REGISTER_PROTO(HTMLCollection, nullptr);
|
REGISTER_PROTO(HTMLCollection, nullptr);
|
||||||
|
|
||||||
#undef REGISTER_PROTO
|
#undef REGISTER_PROTO
|
||||||
|
|
|
@ -14,13 +14,13 @@ use js::glue::bindgen::*;
|
||||||
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB};
|
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB};
|
||||||
use core::ptr::null;
|
use core::ptr::null;
|
||||||
use core::libc::c_uint;
|
use core::libc::c_uint;
|
||||||
|
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 {
|
||||||
|
@ -31,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,15 +52,16 @@ extern fn getElementsByTagName(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSB
|
||||||
arg0 = str(strval.get());
|
arg0 = str(strval.get());
|
||||||
|
|
||||||
let doc = &mut (*unwrap(obj)).payload;
|
let doc = &mut (*unwrap(obj)).payload;
|
||||||
let rval: Option<~HTMLCollection>;
|
let rval: Option<@mut HTMLCollection>;
|
||||||
rval = doc.getElementsByTagName(arg0);
|
rval = doc.getElementsByTagName(arg0);
|
||||||
if rval.is_none() {
|
if rval.is_none() {
|
||||||
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||||
} else {
|
} else {
|
||||||
let cache = doc.get_wrappercache();
|
let cache = doc.get_wrappercache();
|
||||||
|
let rval = rval.get() as @mut CacheableWrapper;
|
||||||
assert!(WrapNewBindingObject(cx, cache.get_wrapper(),
|
assert!(WrapNewBindingObject(cx, cache.get_wrapper(),
|
||||||
rval.get(),
|
rval,
|
||||||
cast::transmute(vp)));
|
cast::transmute(vp)));
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -78,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 = @~[
|
||||||
|
@ -113,8 +116,12 @@ 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,
|
||||||
|
ptr::null()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(compartment: @mut Compartment, doc: @mut Document) -> *JSObject {
|
||||||
let instance : jsobj = result::unwrap(
|
let instance : jsobj = result::unwrap(
|
||||||
compartment.new_object_with_proto(~"DocumentInstance", ~"Document",
|
compartment.new_object_with_proto(~"DocumentInstance", ~"Document",
|
||||||
compartment.global_obj.ptr));
|
compartment.global_obj.ptr));
|
||||||
|
@ -129,6 +136,8 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) {
|
||||||
GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
|
GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
|
||||||
GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8,
|
GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8,
|
||||||
JSPROP_ENUMERATE);
|
JSPROP_ENUMERATE);
|
||||||
|
|
||||||
|
instance.ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CacheableWrapper for Document {
|
impl CacheableWrapper for Document {
|
||||||
|
@ -136,11 +145,8 @@ impl CacheableWrapper for Document {
|
||||||
unsafe { cast::transmute(&self.wrapper) }
|
unsafe { cast::transmute(&self.wrapper) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
fn wrap_object_shared(@mut self, cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
||||||
fail!(~"need to implement wrapping");
|
let content = task_from_context(cx);
|
||||||
}
|
unsafe { create((*content).compartment.get(), self) }
|
||||||
|
|
||||||
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
|
||||||
fail!(~"need to implement wrapping");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
40
src/servo/dom/bindings/domparser.rs
Normal file
40
src/servo/dom/bindings/domparser.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use dom::bindings::codegen::DOMParserBinding;
|
||||||
|
use dom::bindings::utils::{CacheableWrapper, WrapperCache};
|
||||||
|
use dom::bindings::utils::{BindingObject, DerivedWrapper};
|
||||||
|
use dom::domparser::DOMParser;
|
||||||
|
|
||||||
|
use js::jsapi::{JSContext, JSObject, JSVal};
|
||||||
|
use js::glue::bindgen::{RUST_OBJECT_TO_JSVAL};
|
||||||
|
|
||||||
|
impl CacheableWrapper for DOMParser {
|
||||||
|
fn get_wrappercache(&mut self) -> &mut WrapperCache {
|
||||||
|
unsafe { cast::transmute(&self.wrapper) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||||
|
let mut unused = false;
|
||||||
|
DOMParserBinding::Wrap(cx, scope, self, &mut unused)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BindingObject for DOMParser {
|
||||||
|
fn GetParentObject(&self, _cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
|
return self.owner as @mut CacheableWrapper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerivedWrapper for DOMParser {
|
||||||
|
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
|
||||||
|
fail!(~"nyi")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_shared(@mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
|
||||||
|
let obj = self.wrap_object_shared(cx, scope);
|
||||||
|
if obj.is_null() {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
unsafe { *vp = RUST_OBJECT_TO_JSVAL(obj) };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,49 @@ 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: *mut JSTracer, obj: *JSObject) {
|
||||||
|
let node = unsafe { unwrap(obj) };
|
||||||
|
|
||||||
|
fn trace_node(tracer: *mut 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 {
|
||||||
|
(*tracer).debugPrinter = ptr::null();
|
||||||
|
(*tracer).debugPrintIndex = -1;
|
||||||
|
do str::as_c_str(name) |name| {
|
||||||
|
(*tracer).debugPrintArg = name as *libc::c_void;
|
||||||
|
JS_CallTracer(cast::transmute(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 +86,16 @@ pub fn init(compartment: @mut Compartment) {
|
||||||
nargs: 0,
|
nargs: 0,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
selfHostedName: null()},
|
selfHostedName: null()},
|
||||||
|
JSFunctionSpec {name: compartment.add_name(~"getBoundingClientRect"),
|
||||||
|
call: JSNativeWrapper {op: getBoundingClientRect, info: null()},
|
||||||
|
nargs: 0,
|
||||||
|
flags: 0,
|
||||||
|
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 +106,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 +134,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()
|
||||||
};
|
};
|
||||||
|
@ -102,14 +142,68 @@ extern fn getClientRects(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool {
|
||||||
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||||
} else {
|
} else {
|
||||||
let cache = node.get_wrappercache();
|
let cache = node.get_wrappercache();
|
||||||
|
let rval = rval.get() as @mut CacheableWrapper;
|
||||||
assert!(WrapNewBindingObject(cx, cache.get_wrapper(),
|
assert!(WrapNewBindingObject(cx, cache.get_wrapper(),
|
||||||
rval.get(),
|
rval,
|
||||||
cast::transmute(vp)));
|
cast::transmute(vp)));
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern fn getBoundingClientRect(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool {
|
||||||
|
unsafe {
|
||||||
|
let obj = JS_THIS_OBJECT(cx, vp);
|
||||||
|
let mut node = unwrap(obj);
|
||||||
|
let rval = do node.with_imm_element |elem| {
|
||||||
|
elem.getBoundingClientRect()
|
||||||
|
};
|
||||||
|
if rval.is_none() {
|
||||||
|
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||||
|
} else {
|
||||||
|
let cache = node.get_wrappercache();
|
||||||
|
let rval = rval.get() as @mut CacheableWrapper;
|
||||||
|
assert!(WrapNewBindingObject(cx, cache.get_wrapper(),
|
||||||
|
rval,
|
||||||
|
cast::transmute(vp)));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
@ -118,13 +212,17 @@ 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) => {
|
||||||
|
match rect {
|
||||||
|
layout_task::ContentRect(rect) => rect.size.width.to_px(),
|
||||||
|
_ => fail!(~"unexpected layout reply")
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(()) => 0
|
Err(()) => 0
|
||||||
}
|
}
|
||||||
// TODO: if nothing is being rendered(?), return zero dimensions
|
// TODO: if nothing is being rendered(?), return zero dimensions
|
||||||
|
@ -147,13 +245,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?"),
|
||||||
|
@ -164,7 +262,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));
|
||||||
|
@ -172,8 +269,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);
|
||||||
|
@ -182,7 +278,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",
|
||||||
|
@ -200,9 +295,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,53 +2,27 @@
|
||||||
* 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, OpaqueBindingReference};
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindingObject for HTMLCollection {
|
impl BindingObject for HTMLCollection {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let content = task_from_context(cx);
|
let content = task_from_context(cx);
|
||||||
unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
|
unsafe { (*content).window.get() as @mut CacheableWrapper }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,12 +31,8 @@ impl CacheableWrapper for HTMLCollection {
|
||||||
unsafe { cast::transmute(&self.wrapper) }
|
unsafe { cast::transmute(&self.wrapper) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||||
let mut unused = false;
|
let mut unused = false;
|
||||||
HTMLCollectionBinding::Wrap(cx, scope, self, &mut unused)
|
HTMLCollectionBinding::Wrap(cx, scope, self, &mut unused)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
|
||||||
fail!(~"nyi")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
};
|
};
|
||||||
|
@ -171,11 +167,7 @@ impl CacheableWrapper for AbstractNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
||||||
fail!(~"need to implement wrapping");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
|
||||||
fail!(~"need to implement wrapping");
|
fail!(~"need to implement wrapping");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
|
||||||
unsafe {
|
unsafe {
|
||||||
let name = str::raw::from_buf(className as *u8);
|
let name = str::raw::from_buf(className as *u8);
|
||||||
let nchars = "[object ]".len() + name.len();
|
let nchars = "[object ]".len() + name.len();
|
||||||
let chars: *mut jschar = cast::transmute(JS_malloc(cx, nchars as u64 * (size_of::<jschar>() as u64)));
|
let chars: *mut jschar = cast::transmute(JS_malloc(cx, (nchars + 1) as u64 * (size_of::<jschar>() as u64)));
|
||||||
if chars.is_null() {
|
if chars.is_null() {
|
||||||
return ptr::null();
|
return ptr::null();
|
||||||
}
|
}
|
||||||
|
|
86
src/servo/dom/bindings/text.rs
Normal file
86
src/servo/dom/bindings/text.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
use dom::bindings::element;
|
||||||
|
use dom::bindings::node::unwrap;
|
||||||
|
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_SetReservedSlot};
|
||||||
|
use js::glue::bindgen::{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 node: AbstractNode = unwrap(obj);
|
||||||
|
let _elem: ~Text = cast::transmute(node.raw_object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn finalize_comment(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
|
debug!("comment finalize: %?!", obj as uint);
|
||||||
|
unsafe {
|
||||||
|
let node: AbstractNode = unwrap(obj);
|
||||||
|
let _elem: ~Comment = cast::transmute(node.raw_object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn finalize_doctype(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
|
debug!("doctype finalize: %?!", obj as uint);
|
||||||
|
unsafe {
|
||||||
|
let node: AbstractNode = unwrap(obj);
|
||||||
|
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);
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ use js::jsapi::bindgen::{JS_ValueToString,
|
||||||
JS_DefineProperties,
|
JS_DefineProperties,
|
||||||
JS_WrapValue, JS_ForwardGetPropertyTo,
|
JS_WrapValue, JS_ForwardGetPropertyTo,
|
||||||
JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject,
|
JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject,
|
||||||
JS_EncodeString, JS_free};
|
JS_EncodeString, JS_free, JS_GetStringCharsAndLength};
|
||||||
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
||||||
use js::glue::bindgen::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL};
|
use js::glue::bindgen::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL};
|
||||||
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB,
|
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB,
|
||||||
|
@ -91,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,
|
||||||
|
@ -121,12 +130,6 @@ pub unsafe fn squirrel_away<T>(x: @mut T) -> *rust_box<T> {
|
||||||
y
|
y
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn squirrel_away_unique<T>(x: ~T) -> *rust_box<T> {
|
|
||||||
let y: *rust_box<T> = cast::reinterpret_cast(&x);
|
|
||||||
cast::forget(x);
|
|
||||||
y
|
|
||||||
}
|
|
||||||
|
|
||||||
//XXX very incomplete
|
//XXX very incomplete
|
||||||
pub fn jsval_to_str(cx: *JSContext, v: JSVal) -> Result<~str, ()> {
|
pub fn jsval_to_str(cx: *JSContext, v: JSVal) -> Result<~str, ()> {
|
||||||
let jsstr;
|
let jsstr;
|
||||||
|
@ -217,7 +220,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 {
|
||||||
|
@ -235,7 +238,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
|
||||||
|
@ -281,10 +284,8 @@ static DOM_PROXY_OBJECT_SLOT: uint = js::JSSLOT_PROXY_PRIVATE as uint;
|
||||||
// changes.
|
// changes.
|
||||||
static DOM_PROTO_INSTANCE_CLASS_SLOT: u32 = 0;
|
static DOM_PROTO_INSTANCE_CLASS_SLOT: u32 = 0;
|
||||||
|
|
||||||
// All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. We have to
|
// All DOM globals must have a slot at DOM_PROTOTYPE_SLOT.
|
||||||
// start at 1 past JSCLASS_GLOBAL_SLOT_COUNT because XPConnect uses
|
pub static DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
|
||||||
// that one.
|
|
||||||
pub static DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT + 1;
|
|
||||||
|
|
||||||
// NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
|
// NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
|
||||||
// LSetDOMProperty. Those constants need to be changed accordingly if this value
|
// LSetDOMProperty. Those constants need to be changed accordingly if this value
|
||||||
|
@ -356,6 +357,7 @@ pub mod prototypes {
|
||||||
pub enum Prototype {
|
pub enum Prototype {
|
||||||
ClientRect,
|
ClientRect,
|
||||||
ClientRectList,
|
ClientRectList,
|
||||||
|
DOMParser,
|
||||||
HTMLCollection,
|
HTMLCollection,
|
||||||
_ID_Count
|
_ID_Count
|
||||||
}
|
}
|
||||||
|
@ -540,7 +542,7 @@ pub extern fn ThrowingConstructor(_cx: *JSContext, _argc: uint, _vp: *JSVal) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize_global(global: *JSObject) {
|
pub fn initialize_global(global: *JSObject) {
|
||||||
let protoArray = @mut ([0 as *JSObject, ..3]); //XXXjdm prototypes::_ID_COUNT
|
let protoArray = @mut ([0 as *JSObject, ..4]); //XXXjdm prototypes::_ID_COUNT
|
||||||
unsafe {
|
unsafe {
|
||||||
//XXXjdm we should be storing the box pointer instead of the inner
|
//XXXjdm we should be storing the box pointer instead of the inner
|
||||||
let box = squirrel_away(protoArray);
|
let box = squirrel_away(protoArray);
|
||||||
|
@ -553,8 +555,7 @@ pub fn initialize_global(global: *JSObject) {
|
||||||
|
|
||||||
pub trait CacheableWrapper {
|
pub trait CacheableWrapper {
|
||||||
fn get_wrappercache(&mut self) -> &mut WrapperCache;
|
fn get_wrappercache(&mut self) -> &mut WrapperCache;
|
||||||
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject;
|
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject;
|
||||||
fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WrapperCache {
|
pub struct WrapperCache {
|
||||||
|
@ -570,6 +571,10 @@ pub impl WrapperCache {
|
||||||
self.wrapper = wrapper;
|
self.wrapper = wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_rootable(&self) -> **JSObject {
|
||||||
|
return ptr::addr_of(&self.wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
fn new() -> WrapperCache {
|
fn new() -> WrapperCache {
|
||||||
WrapperCache {
|
WrapperCache {
|
||||||
wrapper: ptr::null()
|
wrapper: ptr::null()
|
||||||
|
@ -577,87 +582,42 @@ pub impl WrapperCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn WrapNewBindingObject<T: CacheableWrapper>(cx: *JSContext, scope: *JSObject,
|
pub fn WrapNewBindingObject(cx: *JSContext, scope: *JSObject,
|
||||||
mut value: ~T, vp: *mut JSVal) -> bool {
|
mut value: @mut CacheableWrapper,
|
||||||
|
vp: *mut JSVal) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let obj = value.get_wrappercache().get_wrapper();
|
let mut cache = value.get_wrappercache();
|
||||||
|
let mut obj = cache.get_wrapper();
|
||||||
if obj.is_not_null() /*&& js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)*/ {
|
if obj.is_not_null() /*&& js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)*/ {
|
||||||
*vp = RUST_OBJECT_TO_JSVAL(obj);
|
*vp = RUST_OBJECT_TO_JSVAL(obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let obj = if obj.is_not_null() {
|
let obj = value.wrap_object_shared(cx, scope);
|
||||||
obj
|
|
||||||
} else {
|
|
||||||
value.wrap_object_unique(cx, scope)
|
|
||||||
};
|
|
||||||
|
|
||||||
if obj.is_null() {
|
if obj.is_null() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
|
// MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
|
||||||
|
cache.set_wrapper(obj);
|
||||||
*vp = RUST_OBJECT_TO_JSVAL(obj);
|
*vp = RUST_OBJECT_TO_JSVAL(obj);
|
||||||
return JS_WrapValue(cx, cast::transmute(vp)) != 0;
|
return JS_WrapValue(cx, cast::transmute(vp)) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OpaqueBindingReference(Either<~CacheableWrapper, @CacheableWrapper>);
|
pub fn WrapNativeParent(cx: *JSContext, scope: *JSObject, mut p: @mut CacheableWrapper) -> *JSObject {
|
||||||
|
let cache = p.get_wrappercache();
|
||||||
pub fn WrapNativeParent(cx: *JSContext, scope: *JSObject, p: &mut OpaqueBindingReference) -> *JSObject {
|
let wrapper = cache.get_wrapper();
|
||||||
match p {
|
if wrapper.is_not_null() {
|
||||||
&OpaqueBindingReference(Left(ref mut p)) => {
|
return wrapper;
|
||||||
let cache = p.get_wrappercache();
|
|
||||||
let obj = cache.get_wrapper();
|
|
||||||
if obj.is_not_null() {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
let mut tmp: ~CacheableWrapper = unstable::intrinsics::init();
|
|
||||||
tmp <-> *p;
|
|
||||||
tmp.wrap_object_unique(cx, scope)
|
|
||||||
}
|
|
||||||
&OpaqueBindingReference(Right(ref mut p)) => {
|
|
||||||
let cache = p.get_wrappercache();
|
|
||||||
let obj = cache.get_wrapper();
|
|
||||||
if obj.is_not_null() {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
p.wrap_object_shared(cx, scope)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let wrapper = p.wrap_object_shared(cx, scope);
|
||||||
|
cache.set_wrapper(wrapper);
|
||||||
|
wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BindingReference<T>(Either<~T, @mut T>);
|
|
||||||
|
|
||||||
pub trait BindingObject {
|
pub trait BindingObject {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference;
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper;
|
||||||
}
|
|
||||||
|
|
||||||
pub impl<T: BindingObject + CacheableWrapper> BindingReference<T> {
|
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
|
|
||||||
match **self {
|
|
||||||
Left(ref obj) => obj.GetParentObject(cx),
|
|
||||||
Right(ref obj) => obj.GetParentObject(cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_wrappercache(&mut self) -> &mut WrapperCache {
|
|
||||||
match **self {
|
|
||||||
Left(ref mut obj) => obj.get_wrappercache(),
|
|
||||||
Right(ref mut obj) => obj.get_wrappercache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn squirrel_away_ref<R>(obj: &mut BindingReference<R>) -> *rust_box<R> {
|
|
||||||
let mut tmp: BindingReference<R> = unstable::intrinsics::init();
|
|
||||||
tmp <-> *obj;
|
|
||||||
unsafe {
|
|
||||||
match tmp {
|
|
||||||
BindingReference(Left(obj)) => squirrel_away_unique(obj),
|
|
||||||
BindingReference(Right(obj)) => squirrel_away(obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found: *mut bool,
|
pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found: *mut bool,
|
||||||
|
@ -781,6 +741,7 @@ pub fn InitIds(cx: *JSContext, specs: &[JSPropertySpec], ids: &mut [jsid]) -> bo
|
||||||
|
|
||||||
pub trait DerivedWrapper {
|
pub trait DerivedWrapper {
|
||||||
fn wrap(&mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32;
|
fn wrap(&mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32;
|
||||||
|
fn wrap_shared(@mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerivedWrapper for AbstractNode {
|
impl DerivedWrapper for AbstractNode {
|
||||||
|
@ -794,6 +755,10 @@ impl DerivedWrapper for AbstractNode {
|
||||||
unsafe { *vp = RUST_OBJECT_TO_JSVAL(node::create(cx, self).ptr) };
|
unsafe { *vp = RUST_OBJECT_TO_JSVAL(node::create(cx, self).ptr) };
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wrap_shared(@mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
|
||||||
|
fail!(~"nyi")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -801,3 +766,42 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ErrorResult = Result<(), Error>;
|
pub type ErrorResult = Result<(), Error>;
|
||||||
|
|
||||||
|
pub struct EnumEntry {
|
||||||
|
value: &'static str,
|
||||||
|
length: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn FindEnumStringIndex(cx: *JSContext,
|
||||||
|
v: JSVal,
|
||||||
|
values: &[EnumEntry]) -> Result<uint, ()> {
|
||||||
|
unsafe {
|
||||||
|
let jsstr = JS_ValueToString(cx, v);
|
||||||
|
if jsstr.is_null() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
let length = 0;
|
||||||
|
let chars = JS_GetStringCharsAndLength(cx, jsstr, ptr::to_unsafe_ptr(&length));
|
||||||
|
if chars.is_null() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
for values.eachi |i, value| {
|
||||||
|
if value.length != length as uint {
|
||||||
|
loop;
|
||||||
|
}
|
||||||
|
let mut equal = true;
|
||||||
|
for uint::iterate(0, length as uint) |j| {
|
||||||
|
if value.value[j] as u16 != *chars.offset(j) {
|
||||||
|
equal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if equal {
|
||||||
|
return Ok(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(()); //XXX pass in behaviour for value not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use js::crust::{JS_PropertyStub, JS_StrictPropertyStub};
|
||||||
use js::global::jsval_to_rust_str;
|
use js::global::jsval_to_rust_str;
|
||||||
use js::glue::bindgen::*;
|
use js::glue::bindgen::*;
|
||||||
use js::glue::bindgen::RUST_JSVAL_TO_INT;
|
use js::glue::bindgen::RUST_JSVAL_TO_INT;
|
||||||
use js::jsapi::bindgen::{JS_DefineFunctions};
|
use js::jsapi::bindgen::{JS_DefineFunctions, JS_GC, JS_GetRuntime};
|
||||||
use js::jsapi::bindgen::{JS_GetReservedSlot, JS_SetReservedSlot};
|
use js::jsapi::bindgen::{JS_GetReservedSlot, JS_SetReservedSlot};
|
||||||
use js::jsapi::bindgen::{JS_ValueToString};
|
use js::jsapi::bindgen::{JS_ValueToString};
|
||||||
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSFreeOp, JSFunctionSpec};
|
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSFreeOp, JSFunctionSpec};
|
||||||
|
@ -31,12 +31,15 @@ extern fn alert(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
|
||||||
assert!(argc == 1);
|
assert!(argc == 1);
|
||||||
// Abstract this pattern and use it in debug, too?
|
// Abstract this pattern and use it in debug, too?
|
||||||
let jsstr = JS_ValueToString(cx, *ptr::offset(argv, 0));
|
let jsstr = JS_ValueToString(cx, *ptr::offset(argv, 0));
|
||||||
|
if jsstr.is_null() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
(*unwrap(JS_THIS_OBJECT(cx, vp))).payload.alert(jsval_to_rust_str(cx, jsstr));
|
(*unwrap(JS_THIS_OBJECT(cx, vp))).payload.alert(jsval_to_rust_str(cx, jsstr));
|
||||||
|
|
||||||
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
1_i32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn setTimeout(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
|
extern fn setTimeout(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
|
||||||
|
@ -63,6 +66,12 @@ extern fn close(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern fn gc(cx: *JSContext, _argc: c_uint, _vp: *JSVal) -> JSBool {
|
||||||
|
let runtime = JS_GetRuntime(cx);
|
||||||
|
JS_GC(runtime);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn unwrap(obj: *JSObject) -> *rust_box<Window> {
|
unsafe fn unwrap(obj: *JSObject) -> *rust_box<Window> {
|
||||||
let val = JS_GetReservedSlot(obj, 0);
|
let val = JS_GetReservedSlot(obj, 0);
|
||||||
cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val))
|
cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val))
|
||||||
|
@ -76,13 +85,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 = [
|
||||||
|
@ -103,7 +108,14 @@ pub fn init(compartment: @mut Compartment, win: @mut Window) {
|
||||||
JSFunctionSpec {
|
JSFunctionSpec {
|
||||||
name: compartment.add_name(~"close"),
|
name: compartment.add_name(~"close"),
|
||||||
call: JSNativeWrapper { op: close, info: null() },
|
call: JSNativeWrapper { op: close, info: null() },
|
||||||
nargs: 2,
|
nargs: 0,
|
||||||
|
flags: 0,
|
||||||
|
selfHostedName: null()
|
||||||
|
},
|
||||||
|
JSFunctionSpec {
|
||||||
|
name: compartment.add_name(~"_trigger_gc"),
|
||||||
|
call: JSNativeWrapper { op: gc, info: null() },
|
||||||
|
nargs: 0,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
selfHostedName: null()
|
selfHostedName: null()
|
||||||
},
|
},
|
||||||
|
@ -116,11 +128,17 @@ pub fn init(compartment: @mut Compartment, win: @mut Window) {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
@ -137,11 +155,7 @@ impl CacheableWrapper for Window {
|
||||||
unsafe { cast::transmute(&self.wrapper) }
|
unsafe { cast::transmute(&self.wrapper) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
||||||
fail!(~"should this be called?");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
|
||||||
fail!(~"should this be called?");
|
fail!(~"should this be called?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
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)
|
||||||
|
}
|
||||||
|
}
|
35
src/servo/dom/clientrectlist.rs
Normal file
35
src/servo/dom/clientrectlist.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use dom::clientrect::ClientRect;
|
||||||
|
use dom::bindings::utils::WrapperCache;
|
||||||
|
|
||||||
|
pub struct ClientRectList {
|
||||||
|
wrapper: WrapperCache,
|
||||||
|
rects: ~[@mut ClientRect]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl ClientRectList {
|
||||||
|
fn new(rects: ~[@mut ClientRect]) -> @mut ClientRectList {
|
||||||
|
let list = @mut ClientRectList {
|
||||||
|
wrapper: WrapperCache::new(),
|
||||||
|
rects: rects
|
||||||
|
};
|
||||||
|
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 {
|
||||||
|
Some(self.rects[index])
|
||||||
|
} 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| {
|
||||||
|
assert!(node.wrapper.get_wrapper().is_not_null());
|
||||||
|
let rootable = node.wrapper.get_rootable();
|
||||||
|
JS_AddObjectRoot(compartment.cx.ptr, rootable);
|
||||||
|
}
|
||||||
|
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| {
|
||||||
|
assert!(node.wrapper.get_wrapper().is_not_null());
|
||||||
|
let rootable = node.wrapper.get_rootable();
|
||||||
|
JS_RemoveObjectRoot(compartment.cx.ptr, rootable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Document {
|
pub impl Document {
|
||||||
fn getElementsByTagName(&self, tag: DOMString) -> Option<~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(~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)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
36
src/servo/dom/domparser.rs
Normal file
36
src/servo/dom/domparser.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use content::content_task::global_content;
|
||||||
|
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache, CacheableWrapper};
|
||||||
|
use dom::bindings::codegen::DOMParserBinding;
|
||||||
|
use dom::document::Document;
|
||||||
|
use dom::element::{Element, HTMLHtmlElement, HTMLHtmlElementTypeId};
|
||||||
|
use dom::node::Node;
|
||||||
|
use dom::window::Window;
|
||||||
|
|
||||||
|
pub struct DOMParser {
|
||||||
|
owner: @mut Window, //XXXjdm Document instead?
|
||||||
|
wrapper: WrapperCache
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl DOMParser {
|
||||||
|
fn new(owner: @mut Window) -> @mut DOMParser {
|
||||||
|
let parser = @mut DOMParser {
|
||||||
|
owner: owner,
|
||||||
|
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 {
|
||||||
|
DOMParser::new(owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ParseFromString(&self, _s: DOMString, _type_: DOMParserBinding::SupportedType, _rv: &mut ErrorResult) -> @mut Document {
|
||||||
|
let root = ~HTMLHtmlElement { parent: Element::new(HTMLHtmlElementTypeId, ~"html") };
|
||||||
|
let root = unsafe { Node::as_abstract_node(root) };
|
||||||
|
Document(root, None)
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,11 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
use dom::node::{ElementNodeTypeId, Node};
|
use dom::node::{ElementNodeTypeId, Node};
|
||||||
use dom::bindings::clientrectlist::ClientRectListImpl;
|
use dom::clientrect::ClientRect;
|
||||||
|
use dom::clientrectlist::ClientRectList;
|
||||||
|
use dom::bindings::utils::DOMString;
|
||||||
|
|
||||||
|
use layout::layout_task;
|
||||||
|
|
||||||
use core::str::eq_slice;
|
use core::str::eq_slice;
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
|
@ -132,20 +136,104 @@ 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<~ClientRectListImpl> {
|
fn getClientRects(&self) -> Option<@mut ClientRectList> {
|
||||||
Some(~ClientRectListImpl::new())
|
let rects = match self.parent.owner_doc {
|
||||||
|
Some(doc) => {
|
||||||
|
match doc.window {
|
||||||
|
Some(win) => {
|
||||||
|
let node = self.parent.abstract.get();
|
||||||
|
assert!(node.is_element());
|
||||||
|
let content = unsafe { &mut *win.content_task };
|
||||||
|
match content.query_layout(layout_task::ContentBoxes(node)) {
|
||||||
|
Ok(rects) => match rects {
|
||||||
|
layout_task::ContentRects(rects) =>
|
||||||
|
do rects.map |r| {
|
||||||
|
ClientRect::new(
|
||||||
|
r.origin.y.to_f32(),
|
||||||
|
(r.origin.y + r.size.height).to_f32(),
|
||||||
|
r.origin.x.to_f32(),
|
||||||
|
(r.origin.x + r.size.width).to_f32())
|
||||||
|
},
|
||||||
|
_ => fail!(~"unexpected layout reply")
|
||||||
|
},
|
||||||
|
Err(()) => {
|
||||||
|
debug!("layout query error");
|
||||||
|
~[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug!("no window");
|
||||||
|
~[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug!("no document");
|
||||||
|
~[]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(ClientRectList::new(rects))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getBoundingClientRect(&self) -> Option<@mut ClientRect> {
|
||||||
|
match self.parent.owner_doc {
|
||||||
|
Some(doc) => {
|
||||||
|
match doc.window {
|
||||||
|
Some(win) => {
|
||||||
|
let node = self.parent.abstract.get();
|
||||||
|
assert!(node.is_element());
|
||||||
|
let content = unsafe { &mut *win.content_task };
|
||||||
|
match content.query_layout(layout_task::ContentBox(node)) {
|
||||||
|
Ok(rect) => match rect {
|
||||||
|
layout_task::ContentRect(rect) =>
|
||||||
|
Some(ClientRect::new(
|
||||||
|
rect.origin.y.to_f32(),
|
||||||
|
(rect.origin.y + rect.size.height).to_f32(),
|
||||||
|
rect.origin.x.to_f32(),
|
||||||
|
(rect.origin.x + rect.size.width).to_f32())),
|
||||||
|
_ => fail!(~"unexpected layout result")
|
||||||
|
},
|
||||||
|
Err(()) => {
|
||||||
|
debug!("error querying layout");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug!("no window");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug!("no document");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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;
|
||||||
|
@ -41,12 +43,16 @@ pub struct Node {
|
||||||
wrapper: WrapperCache,
|
wrapper: WrapperCache,
|
||||||
type_id: NodeTypeId,
|
type_id: NodeTypeId,
|
||||||
|
|
||||||
|
abstract: Option<AbstractNode>,
|
||||||
|
|
||||||
parent_node: Option<AbstractNode>,
|
parent_node: Option<AbstractNode>,
|
||||||
first_child: Option<AbstractNode>,
|
first_child: Option<AbstractNode>,
|
||||||
last_child: Option<AbstractNode>,
|
last_child: Option<AbstractNode>,
|
||||||
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 +112,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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,15 +240,27 @@ pub impl AbstractNode {
|
||||||
|
|
||||||
fn transmute<T, R>(self, f: &fn(&T) -> R) -> R {
|
fn transmute<T, R>(self, f: &fn(&T) -> R) -> R {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let node_box: *mut bindings::utils::rust_box<Node> = transmute(self.obj);
|
||||||
|
let node = &mut (*node_box).payload;
|
||||||
|
let old = node.abstract;
|
||||||
|
node.abstract = Some(self);
|
||||||
let box: *bindings::utils::rust_box<T> = transmute(self.obj);
|
let box: *bindings::utils::rust_box<T> = transmute(self.obj);
|
||||||
f(&(*box).payload)
|
let rv = f(&(*box).payload);
|
||||||
|
node.abstract = old;
|
||||||
|
rv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transmute_mut<T, R>(self, f: &fn(&mut T) -> R) -> R {
|
fn transmute_mut<T, R>(self, f: &fn(&mut T) -> R) -> R {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let node_box: *mut bindings::utils::rust_box<Node> = transmute(self.obj);
|
||||||
|
let node = &mut (*node_box).payload;
|
||||||
|
let old = node.abstract;
|
||||||
|
node.abstract = Some(self);
|
||||||
let box: *bindings::utils::rust_box<T> = transmute(self.obj);
|
let box: *bindings::utils::rust_box<T> = transmute(self.obj);
|
||||||
f(cast::transmute(&(*box).payload))
|
let rv = f(cast::transmute(&(*box).payload));
|
||||||
|
node.abstract = old;
|
||||||
|
rv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,6 +330,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 +368,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,22 +395,27 @@ impl Node {
|
||||||
wrapper: WrapperCache::new(),
|
wrapper: WrapperCache::new(),
|
||||||
type_id: type_id,
|
type_id: type_id,
|
||||||
|
|
||||||
|
abstract: None,
|
||||||
|
|
||||||
parent_node: None,
|
parent_node: None,
|
||||||
first_child: None,
|
first_child: None,
|
||||||
last_child: None,
|
last_child: None,
|
||||||
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,
|
||||||
|
@ -385,4 +427,7 @@ pub fn define_bindings(compartment: @mut Compartment, doc: @mut Document, win: @
|
||||||
assert!(codegen::HTMLCollectionBinding::DefineDOMInterface(compartment.cx.ptr,
|
assert!(codegen::HTMLCollectionBinding::DefineDOMInterface(compartment.cx.ptr,
|
||||||
compartment.global_obj.ptr,
|
compartment.global_obj.ptr,
|
||||||
&mut unused));
|
&mut unused));
|
||||||
|
assert!(codegen::DOMParserBinding::DefineDOMInterface(compartment.cx.ptr,
|
||||||
|
compartment.global_obj.ptr,
|
||||||
|
&mut unused));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, 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;
|
||||||
|
|
||||||
|
@ -17,8 +19,12 @@ pub enum TimerControlMsg {
|
||||||
TimerMessage_TriggerExit //XXXjdm this is just a quick hack to talk to the content task
|
TimerMessage_TriggerExit //XXXjdm this is just a quick hack to talk to the content task
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FIXME If we're going to store the content task, find a way to do so safely. Currently it's
|
||||||
|
// only used for querying layout from arbitrary content.
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
timer_chan: Chan<TimerControlMsg>,
|
timer_chan: Chan<TimerControlMsg>,
|
||||||
|
dom_event_chan: SharedChan<Event>,
|
||||||
|
content_task: *mut Content,
|
||||||
wrapper: WrapperCache
|
wrapper: WrapperCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,10 +83,13 @@ 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>,
|
||||||
|
content_task: *mut Content) -> @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() {
|
||||||
|
@ -91,6 +100,10 @@ pub fn Window(content_chan: comm::SharedChan<ControlMsg>) -> Window {
|
||||||
TimerMessage_TriggerExit => content_chan.send(ExitMsg)
|
TimerMessage_TriggerExit => content_chan.send(ExitMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
content_task: content_task
|
||||||
|
};
|
||||||
|
let compartment = global_content().compartment.get();
|
||||||
|
window::create(compartment, win);
|
||||||
|
win
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,7 @@ pub fn parse_html(url: Url,
|
||||||
let url = url::from_str("http://example.com/"); // FIXME
|
let url = url::from_str("http://example.com/"); // FIXME
|
||||||
let url_cell = Cell(url);
|
let url_cell = Cell(url);
|
||||||
do child_node.with_imm_text |text_node| {
|
do child_node.with_imm_text |text_node| {
|
||||||
let data = text_node.text.to_str(); // FIXME: Bad copy.
|
let data = text_node.parent.data.to_str(); // FIXME: Bad copy.
|
||||||
let provenance = InlineProvenance(result::unwrap(url_cell.take()), data);
|
let provenance = InlineProvenance(result::unwrap(url_cell.take()), data);
|
||||||
css_chan2.send(CSSTaskNewFile(provenance));
|
css_chan2.send(CSSTaskNewFile(provenance));
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,16 +230,17 @@ impl BuilderContext {
|
||||||
|
|
||||||
priv fn create_child_flow_of_type(&self,
|
priv fn create_child_flow_of_type(&self,
|
||||||
flow_type: FlowContextType,
|
flow_type: FlowContextType,
|
||||||
builder: &mut LayoutTreeBuilder) -> BuilderContext {
|
builder: &mut LayoutTreeBuilder,
|
||||||
let new_flow = builder.make_flow(flow_type);
|
node: AbstractNode) -> BuilderContext {
|
||||||
|
let new_flow = builder.make_flow(flow_type, node);
|
||||||
self.attach_child_flow(new_flow);
|
self.attach_child_flow(new_flow);
|
||||||
|
|
||||||
BuilderContext::new(@mut BoxGenerator::new(new_flow))
|
BuilderContext::new(@mut BoxGenerator::new(new_flow))
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn make_inline_collector(&mut self, builder: &mut LayoutTreeBuilder) -> BuilderContext {
|
priv fn make_inline_collector(&mut self, builder: &mut LayoutTreeBuilder, node: AbstractNode) -> BuilderContext {
|
||||||
debug!("BuilderContext: making new inline collector flow");
|
debug!("BuilderContext: making new inline collector flow");
|
||||||
let new_flow = builder.make_flow(Flow_Inline);
|
let new_flow = builder.make_flow(Flow_Inline, node);
|
||||||
let new_generator = @mut BoxGenerator::new(new_flow);
|
let new_generator = @mut BoxGenerator::new(new_flow);
|
||||||
|
|
||||||
self.inline_collector = Some(new_generator);
|
self.inline_collector = Some(new_generator);
|
||||||
|
@ -248,10 +249,10 @@ impl BuilderContext {
|
||||||
BuilderContext::new(new_generator)
|
BuilderContext::new(new_generator)
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn get_inline_collector(&mut self, builder: &mut LayoutTreeBuilder) -> BuilderContext {
|
priv fn get_inline_collector(&mut self, builder: &mut LayoutTreeBuilder, node: AbstractNode) -> BuilderContext {
|
||||||
match copy self.inline_collector {
|
match copy self.inline_collector {
|
||||||
Some(collector) => BuilderContext::new(collector),
|
Some(collector) => BuilderContext::new(collector),
|
||||||
None => self.make_inline_collector(builder)
|
None => self.make_inline_collector(builder, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,18 +279,18 @@ impl BuilderContext {
|
||||||
// If this is the root node, then use the root flow's
|
// If this is the root node, then use the root flow's
|
||||||
// context. Otherwise, make a child block context.
|
// context. Otherwise, make a child block context.
|
||||||
match node.parent_node() {
|
match node.parent_node() {
|
||||||
Some(_) => { self.create_child_flow_of_type(Flow_Block, builder) }
|
Some(_) => { self.create_child_flow_of_type(Flow_Block, builder, node) }
|
||||||
None => { self.clone() },
|
None => { self.clone() },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(CSSDisplayBlock, @BlockFlow(*)) => {
|
(CSSDisplayBlock, @BlockFlow(*)) => {
|
||||||
self.clear_inline_collector();
|
self.clear_inline_collector();
|
||||||
self.create_child_flow_of_type(Flow_Block, builder)
|
self.create_child_flow_of_type(Flow_Block, builder, node)
|
||||||
},
|
},
|
||||||
(CSSDisplayInline, @InlineFlow(*)) => self.clone(),
|
(CSSDisplayInline, @InlineFlow(*)) => self.clone(),
|
||||||
(CSSDisplayInlineBlock, @InlineFlow(*)) => self.clone(),
|
(CSSDisplayInlineBlock, @InlineFlow(*)) => self.clone(),
|
||||||
(CSSDisplayInline, @BlockFlow(*)) => self.get_inline_collector(builder),
|
(CSSDisplayInline, @BlockFlow(*)) => self.get_inline_collector(builder, node),
|
||||||
(CSSDisplayInlineBlock, @BlockFlow(*)) => self.get_inline_collector(builder),
|
(CSSDisplayInlineBlock, @BlockFlow(*)) => self.get_inline_collector(builder, node),
|
||||||
_ => self.clone()
|
_ => self.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -332,10 +333,9 @@ pub impl LayoutTreeBuilder {
|
||||||
// nodes and FlowContexts should not change during layout.
|
// nodes and FlowContexts should not change during layout.
|
||||||
let flow = &mut this_ctx.default_collector.flow;
|
let flow = &mut this_ctx.default_collector.flow;
|
||||||
for tree::each_child(&FlowTree, flow) |child_flow: &@mut FlowContext| {
|
for tree::each_child(&FlowTree, flow) |child_flow: &@mut FlowContext| {
|
||||||
for (copy child_flow.d().node).each |node| {
|
let node = child_flow.d().node;
|
||||||
assert!(node.has_layout_data());
|
assert!(node.has_layout_data());
|
||||||
node.layout_data().flow = Some(*child_flow);
|
node.layout_data().flow = Some(*child_flow);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ pub impl LayoutTreeBuilder {
|
||||||
called on root DOM element. */
|
called on root DOM element. */
|
||||||
fn construct_trees(&mut self, layout_ctx: &LayoutContext, root: AbstractNode)
|
fn construct_trees(&mut self, layout_ctx: &LayoutContext, root: AbstractNode)
|
||||||
-> Result<@mut FlowContext, ()> {
|
-> Result<@mut FlowContext, ()> {
|
||||||
let new_flow = self.make_flow(Flow_Root);
|
let new_flow = self.make_flow(Flow_Root, root);
|
||||||
let new_generator = @mut BoxGenerator::new(new_flow);
|
let new_generator = @mut BoxGenerator::new(new_flow);
|
||||||
let mut root_ctx = BuilderContext::new(new_generator);
|
let mut root_ctx = BuilderContext::new(new_generator);
|
||||||
|
|
||||||
|
@ -415,8 +415,8 @@ pub impl LayoutTreeBuilder {
|
||||||
return Ok(new_flow)
|
return Ok(new_flow)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_flow(&mut self, ty: FlowContextType) -> @mut FlowContext {
|
fn make_flow(&mut self, ty: FlowContextType, node: AbstractNode) -> @mut FlowContext {
|
||||||
let data = FlowData(self.next_flow_id());
|
let data = FlowData(self.next_flow_id(), node);
|
||||||
let ret = match ty {
|
let ret = match ty {
|
||||||
Flow_Absolute => @mut AbsoluteFlow(data),
|
Flow_Absolute => @mut AbsoluteFlow(data),
|
||||||
Flow_Block => @mut BlockFlow(data, BlockFlowData()),
|
Flow_Block => @mut BlockFlow(data, BlockFlowData()),
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub enum FlowContextType {
|
||||||
/* A particular kind of layout context. It manages the positioning of
|
/* A particular kind of layout context. It manages the positioning of
|
||||||
render boxes within the context. */
|
render boxes within the context. */
|
||||||
pub struct FlowData {
|
pub struct FlowData {
|
||||||
node: Option<AbstractNode>,
|
node: AbstractNode,
|
||||||
/* reference to parent, children flow contexts */
|
/* reference to parent, children flow contexts */
|
||||||
tree: tree::Tree<@mut FlowContext>,
|
tree: tree::Tree<@mut FlowContext>,
|
||||||
/* TODO (Issue #87): debug only */
|
/* TODO (Issue #87): debug only */
|
||||||
|
@ -84,9 +84,9 @@ pub struct FlowData {
|
||||||
position: Rect<Au>,
|
position: Rect<Au>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn FlowData(id: int) -> FlowData {
|
pub fn FlowData(id: int, node: AbstractNode) -> FlowData {
|
||||||
FlowData {
|
FlowData {
|
||||||
node: None,
|
node: node,
|
||||||
tree: tree::empty(),
|
tree: tree::empty(),
|
||||||
id: id,
|
id: id,
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,15 @@ use std::net::url::Url;
|
||||||
pub type LayoutTask = SharedChan<Msg>;
|
pub type LayoutTask = SharedChan<Msg>;
|
||||||
|
|
||||||
pub enum LayoutQuery {
|
pub enum LayoutQuery {
|
||||||
ContentBox(AbstractNode)
|
ContentBox(AbstractNode),
|
||||||
|
ContentBoxes(AbstractNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type LayoutQueryResponse = Result<LayoutQueryResponse_, ()>;
|
pub type LayoutQueryResponse = Result<LayoutQueryResponse_, ()>;
|
||||||
|
|
||||||
enum LayoutQueryResponse_ {
|
pub enum LayoutQueryResponse_ {
|
||||||
ContentSize(Size2D<int>)
|
ContentRect(Rect<Au>),
|
||||||
|
ContentRects(~[Rect<Au>])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
|
@ -256,7 +258,10 @@ impl Layout {
|
||||||
match query {
|
match query {
|
||||||
ContentBox(node) => {
|
ContentBox(node) => {
|
||||||
let response = match node.layout_data().flow {
|
let response = match node.layout_data().flow {
|
||||||
None => Err(()),
|
None => {
|
||||||
|
error!("no flow present");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
Some(flow) => {
|
Some(flow) => {
|
||||||
let start_val: Option<Rect<Au>> = None;
|
let start_val: Option<Rect<Au>> = None;
|
||||||
let rect = do flow.foldl_boxes_for_node(node, start_val) |acc, box| {
|
let rect = do flow.foldl_boxes_for_node(node, start_val) |acc, box| {
|
||||||
|
@ -267,16 +272,30 @@ impl Layout {
|
||||||
};
|
};
|
||||||
|
|
||||||
match rect {
|
match rect {
|
||||||
None => Err(()),
|
None => {
|
||||||
Some(rect) => {
|
error!("no boxes for node");
|
||||||
let size = Size2D(rect.size.width.to_px(),
|
Err(())
|
||||||
rect.size.height.to_px());
|
|
||||||
Ok(ContentSize(size))
|
|
||||||
}
|
}
|
||||||
|
Some(rect) => Ok(ContentRect(rect))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
reply_chan.send(response)
|
||||||
|
}
|
||||||
|
ContentBoxes(node) => {
|
||||||
|
let response = match node.layout_data().flow {
|
||||||
|
None => Err(()),
|
||||||
|
Some(flow) => {
|
||||||
|
let mut boxes = ~[];
|
||||||
|
for flow.iter_boxes_for_node(node) |box| {
|
||||||
|
boxes.push(box.content_box());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ContentRects(boxes))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
reply_chan.send(response)
|
reply_chan.send(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,22 +62,30 @@ 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;
|
||||||
pub mod proxyhandler;
|
pub mod proxyhandler;
|
||||||
pub mod clientrect;
|
pub mod clientrect;
|
||||||
pub mod clientrectlist;
|
pub mod clientrectlist;
|
||||||
|
pub mod domparser;
|
||||||
pub mod htmlcollection;
|
pub mod htmlcollection;
|
||||||
pub mod codegen {
|
pub mod codegen {
|
||||||
pub mod ClientRectBinding;
|
pub mod ClientRectBinding;
|
||||||
pub mod ClientRectListBinding;
|
pub mod ClientRectListBinding;
|
||||||
|
pub mod DOMParserBinding;
|
||||||
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 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,9 +3,9 @@
|
||||||
<script src="test_bindings.js"></script>
|
<script src="test_bindings.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="first"></div>
|
<div id="first">fffff<br><br><br><br>fffffffffffffffff</div>
|
||||||
<div id="second"></div>
|
<div id="second">ggg</div>
|
||||||
<span id="third"></div>
|
<span id="third">hhhhhhhh</span>
|
||||||
<div id="fourth"></div>
|
<div id="fourth">iiiiiiiiiiiiiiiiiii</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
//window.alert(ClientRect);
|
//window.alert(ClientRect);
|
||||||
//window.alert(ClientRectList);
|
//window.alert(ClientRectList);
|
||||||
|
window.alert("==1==");
|
||||||
window.alert("1");
|
let elem = document.getElementsByTagName('div')[0];
|
||||||
let elem = document.documentElement;
|
window.alert(elem.nodeType);
|
||||||
window.alert(elem);
|
window.alert(elem);
|
||||||
window.alert("2");
|
window.alert("==1.5==");
|
||||||
|
var rect = elem.getBoundingClientRect();
|
||||||
|
window.alert(rect);
|
||||||
|
window.alert(rect.top);
|
||||||
|
window.alert(rect.bottom);
|
||||||
|
window.alert(rect.left);
|
||||||
|
window.alert(rect.right);
|
||||||
|
window.alert(rect.width);
|
||||||
|
window.alert(rect.height);
|
||||||
|
window.alert("==2==");
|
||||||
var rects = elem.getClientRects();
|
var rects = elem.getClientRects();
|
||||||
window.alert("3");
|
window.alert("==3==");
|
||||||
window.alert(rects);
|
window.alert(rects);
|
||||||
window.alert(rects.length);
|
window.alert(rects.length);
|
||||||
window.alert("4");
|
window.alert("==4==");
|
||||||
let rect = rects[0];
|
let rect = rects[0];
|
||||||
window.alert(rect);
|
window.alert(rect);
|
||||||
/*window.alert(Object.prototype.toString.call(rect.__proto__));
|
/*window.alert(Object.prototype.toString.call(rect.__proto__));
|
||||||
|
@ -24,11 +33,19 @@ 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]);
|
||||||
|
|
||||||
|
window.alert("DOMParser:");
|
||||||
|
window.alert(DOMParser);
|
||||||
|
let parser = new DOMParser();
|
||||||
|
window.alert(parser);
|
||||||
|
//window.alert(parser.parseFromString("<html></html>", "text/html"));
|
||||||
|
|
3
src/test/test_hammer_layout.css
Normal file
3
src/test/test_hammer_layout.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#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="">This text is unstyled.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
12
src/test/test_hammer_layout.js
Normal file
12
src/test/test_hammer_layout.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
var divs = document.getElementsByTagName("div");
|
||||||
|
var div = divs[0];
|
||||||
|
|
||||||
|
var count = 1000000;
|
||||||
|
var start = new Date();
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
div.setAttribute('id', 'styled');
|
||||||
|
div.getBoundingClientRect();
|
||||||
|
window.alert(i);
|
||||||
|
}
|
||||||
|
var stop = new Date();
|
||||||
|
window.alert((stop - start) / count * 1e6);
|
Loading…
Add table
Add a link
Reference in a new issue