Generate DOMParser bindings.

This commit is contained in:
Josh Matthews 2013-04-01 15:14:31 -04:00
parent de7e26d173
commit 886eb35dfd
20 changed files with 417 additions and 144 deletions

@ -1 +1 @@
Subproject commit aefcf146400a42e7302243db2844f4022f938fc0
Subproject commit fe2f31f7f33150615e0cc5385cf869053e64a65a

View file

@ -3,9 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use content::content_task::task_from_context;
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, OpaqueBindingReference};
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
use dom::bindings::codegen::ClientRectBinding;
use js::jsapi::{JSObject, JSContext};
use js::jsapi::{JSObject, JSContext, JSVal};
use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
pub trait ClientRect {
fn Top(&self) -> f32;
@ -62,19 +63,35 @@ impl CacheableWrapper for ClientRectImpl {
unsafe { cast::transmute(&self.wrapper) }
}
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
let mut unused = false;
ClientRectBinding::Wrap(cx, scope, self, &mut unused)
fn wrap_object_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"nyi")
}
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"nyi")
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
let mut unused = false;
ClientRectBinding::Wrap(cx, scope, self, &mut unused)
}
}
impl BindingObject for ClientRectImpl {
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
let content = task_from_context(cx);
unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
unsafe { (*content).window.get() as @mut CacheableWrapper }
}
}
}
impl DerivedWrapper for ClientRectImpl {
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;
}
}
}

View file

@ -5,13 +5,13 @@
use content::content_task::task_from_context;
use dom::bindings::clientrect::{ClientRect, ClientRectImpl};
use dom::bindings::codegen::ClientRectListBinding;
use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject, OpaqueBindingReference};
use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject};
use js::jsapi::{JSObject, JSContext};
pub trait ClientRectList {
fn Length(&self) -> u32;
fn Item(&self, index: u32) -> Option<~ClientRectImpl>;
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<~ClientRectImpl>;
fn Item(&self, index: u32) -> Option<@mut ClientRectImpl>;
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRectImpl>;
}
pub struct ClientRectListImpl {
@ -24,16 +24,16 @@ impl ClientRectList for ClientRectListImpl {
self.rects.len() as u32
}
fn Item(&self, index: u32) -> Option<~ClientRectImpl> {
fn Item(&self, index: u32) -> Option<@mut ClientRectImpl> {
if index < self.rects.len() as u32 {
let (top, bottom, left, right) = self.rects[index];
Some(~ClientRect(top, bottom, left, right))
Some(@mut ClientRect(top, bottom, left, right))
} else {
None
}
}
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<~ClientRectImpl> {
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<@mut ClientRectImpl> {
*found = index < self.rects.len() as u32;
self.Item(index)
}
@ -53,19 +53,19 @@ impl CacheableWrapper for ClientRectListImpl {
unsafe { cast::transmute(&self.wrapper) }
}
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
let mut unused = false;
ClientRectListBinding::Wrap(cx, scope, self, &mut unused)
fn wrap_object_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"nyi")
}
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"nyi")
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
let mut unused = false;
ClientRectListBinding::Wrap(cx, scope, self, &mut unused)
}
}
impl BindingObject for ClientRectListImpl {
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
let content = task_from_context(cx);
unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
unsafe { (*content).window.get() as @mut CacheableWrapper }
}
}
}

View file

@ -116,14 +116,13 @@ DOMInterfaces = {
'ClientRect': [
{
'nativeType': 'ClientRectImpl',
'pointerType': '@mut '
}],
'ClientRectList': [
{
'nativeType': 'ClientRectListImpl',
#'headerFile': 'nsClientRect.h',
#'prefable': True,
#'resultNotAddRefed': [ 'item' ]
'pointerType': '@mut '
}],
'CSS2Properties': {
@ -136,13 +135,10 @@ DOMInterfaces = {
'prefable': True
},
'Document': [
{
'nativeType': 'nsIDocument',
'DOMParser': {
'nativeType': 'DOMParser',
'pointerType': '@mut '
},
{
'workers': True,
}],
'DOMSettableTokenList': [
{
@ -213,8 +209,7 @@ DOMInterfaces = {
'HTMLCollection': [
{
'nativeType': 'HTMLCollection',
#'prefable': True,
#'resultNotAddRefed': [ 'item' ]
'pointerType': '@mut '
}],
'HTMLOptionsCollection': [
@ -516,9 +511,9 @@ addExternalHTMLElement('HTMLOptGroupElement')
addExternalHTMLElement('HTMLVideoElement')
addExternalIface('CanvasGradient', headerFile='nsIDOMCanvasRenderingContext2D.h')
addExternalIface('CanvasPattern', headerFile='nsIDOMCanvasRenderingContext2D.h')
#addExternalIface('ClientRect')
addExternalIface('CSSRule')
addExternalIface('CSSValue')
addExternalIface('Document', nativeType='Document', pointerType='@mut ')
addExternalIface('DOMStringList', nativeType='nsDOMStringList',
headerFile='nsDOMLists.h')
addExternalIface('Element', nativeType='AbstractNode', pointerType='')

View file

@ -1098,22 +1098,19 @@ for (uint32_t i = 0; i < length; ++i) {
"yet")
enum = type.inner.identifier.name
if invalidEnumValueFatal:
handleInvalidEnumValueCode = " MOZ_ASSERT(index >= 0);\n"
handleInvalidEnumValueCode = " return 0;\n"
else:
handleInvalidEnumValueCode = (
" if (index < 0) {\n"
" return true;\n"
" }\n")
handleInvalidEnumValueCode = " return 1;\n"
template = (
"{\n"
" bool ok;\n"
" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
" if (!ok) {\n"
" return false;\n"
" }\n"
#" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
" let result = FindEnumStringIndex(cx, ${val}, %(values)s);\n"
" if result.is_err() {\n"
"%(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,
"values" : enum + "Values::strings",
"invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
@ -1529,7 +1526,7 @@ for (uint32_t i = 0; i < length; ++i) {
if not isCreator:
raise MethodNotCreatorError(descriptor.interface.identifier.name)
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.
assert(not descriptor.prefable or not descriptor.workers)
if not descriptor.prefable:
@ -1547,12 +1544,11 @@ for (uint32_t i = 0; i < length; ++i) {
failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalPtr})" % result)
wrappingCode += wrapAndSetPtr(wrap, failed)
else:
if descriptor.notflattened:
getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
else:
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)
return (wrappingCode, False)
@ -1701,10 +1697,10 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
descriptor = descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name)
result = CGGeneric(descriptor.nativeType)
if resultAlreadyAddRefed:
if returnType.nullable():
result = CGWrapper(result, pre=("Option<" + descriptor.pointerType), post=">")
else:
result = CGWrapper(result, post="*")
result = CGWrapper(result, pre=descriptor.pointerType)
return result, False
if returnType.isCallback():
# XXXbz we're going to assume that callback types are always
@ -2154,20 +2150,23 @@ class CGIfWrapper(CGWrapper):
post="\n}")
class CGNamespace(CGWrapper):
def __init__(self, namespace, child, declareOnly=False):
pre = "mod %s {\n" % namespace
def __init__(self, namespace, child, declareOnly=False, public=False):
pre = "%smod %s {\n" % ("pub " if public else "", namespace)
post = "} // mod %s\n" % namespace
CGWrapper.__init__(self, child, pre=pre, post=post,
declareOnly=declareOnly)
@staticmethod
def build(namespaces, child, declareOnly=False):
def build(namespaces, child, declareOnly=False, public=False):
"""
Static helper method to build multiple wrapped namespaces.
"""
if not namespaces:
return CGWrapper(child, declareOnly=declareOnly)
inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly)
return CGNamespace(namespaces[0], inner, declareOnly=declareOnly)
inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly, public=public)
return CGNamespace(namespaces[0], inner, declareOnly=declareOnly, public=public)
def declare(self):
return ""
def DOMClass(descriptor):
protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
@ -2474,7 +2473,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
return """ *aTriedToWrap = true;
let mut parent = aObject.GetParentObject(aCx);
let parent = WrapNativeParent(aCx, aScope, &mut parent);
let parent = WrapNativeParent(aCx, aScope, parent);
if parent.is_null() {
return ptr::null();
}
@ -2502,11 +2501,11 @@ class CGWrapMethod(CGAbstractMethod):
# XXX can we wrap if we don't have an interface prototype object?
assert descriptor.interface.hasInterfacePrototypeObject()
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)
def definition_body(self):
return " let mut binding = BindingReference(Left(aObject)); \
return " let mut binding = BindingReference(Right(aObject)); \
return Wrap_(aCx, aScope, &mut binding, aTriedToWrap);"
class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
@ -3289,6 +3288,46 @@ class CGMemberJITInfo(CGThing):
return result
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):
def __init__(self, descriptor, name, args, properties):
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
@ -3574,42 +3613,38 @@ let _: %s = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
#return clearWrapper + release
return release
class CGClassConstructHook(CGAbstractStaticMethod):
class CGClassConstructHook(CGAbstractExternMethod):
"""
JS-visible constructor for our objects
"""
def __init__(self, descriptor):
args = [Argument('*JSContext', 'cx'), Argument('unsigned', 'argc'), Argument('*jsval', 'vp')]
CGAbstractStaticMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
args = [Argument('*JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')]
CGAbstractExternMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
'JSBool', args)
self._ctor = self.descriptor.interface.ctor()
def define(self):
if not self._ctor:
return ""
return CGAbstractStaticMethod.define(self)
return CGAbstractExternMethod.define(self)
def definition_body(self):
return self.generate_code()
def generate_code(self):
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:
preArgs = ["cx", "obj"]
else:
preamble += """
nsISupports* global;
xpc_qsSelfRef globalRef;
{
nsresult rv;
JS::Value val = OBJECT_TO_JSVAL(obj);
rv = xpc_qsUnwrapArg<nsISupports>(cx, val, &global, &globalRef.ptr, &val);
if (NS_FAILED(rv)) {
return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
}
}
//XXXjdm Gecko obtains a GlobalObject from the global (maybe from the private value,
// or through unwrapping a slot or something). We'll punt and get the Window
// from the context for now.
let content = task_from_context(cx);
let global = (*content).window.get();
let obj = global.get_wrappercache().get_wrapper();
"""
preArgs = ["global"]
@ -3835,6 +3870,17 @@ class CGBindingRoot(CGThing):
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
cgthings.extend([CGDescriptor(x) for x in descriptors])
@ -3846,6 +3892,8 @@ class CGBindingRoot(CGThing):
# CGWrapper(curr, pre="\n"))
# Add imports
#XXXjdm This should only import the namespace for the current binding,
# not every binding ever.
curr = CGImports(descriptors,
dictionaries,
['js::*',
@ -3854,14 +3902,17 @@ class CGBindingRoot(CGThing):
'js::jsfriendapi::bindgen::*',
'js::glue::bindgen::*',
'js::glue::*',
'dom::node::AbstractNode',
'dom::node::AbstractNode', #XXXjdm
'dom::document::Document', #XXXjdm
'dom::bindings::utils::*',
'dom::bindings::conversions::*',
'dom::bindings::clientrect::*', #XXXjdm
'dom::bindings::clientrectlist::*', #XXXjdm
'dom::bindings::htmlcollection::*', #XXXjdm
'dom::bindings::proxyhandler::*',
'content::content_task::task_from_context'
'dom::domparser::*', #XXXjdm
'content::content_task::task_from_context',
'dom::bindings::utils::EnumEntry',
],
[],
curr)

View 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);*/
};

View file

@ -1,5 +1,6 @@
#include "ClientRectBinding.h"
#include "ClientRectListBinding.h"
#include "DOMParserBinding.h"
#include "HTMLCollectionBinding.h"
#include "nsScriptNameSpaceManager.h"
@ -14,6 +15,7 @@ Register(nsScriptNameSpaceManager* aNameSpaceManager)
REGISTER_PROTO(ClientRect, nullptr);
REGISTER_PROTO(ClientRectList, nullptr);
REGISTER_PROTO(DOMParser, nullptr);
REGISTER_PROTO(HTMLCollection, nullptr);
#undef REGISTER_PROTO

View file

@ -14,6 +14,7 @@ use js::glue::bindgen::*;
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB};
use core::ptr::null;
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::{jsval_to_str, WrapNewBindingObject, CacheableWrapper};
use dom::bindings::utils::WrapperCache;
@ -50,15 +51,16 @@ extern fn getElementsByTagName(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSB
arg0 = str(strval.get());
let doc = &mut (*unwrap(obj)).payload;
let rval: Option<~HTMLCollection>;
let rval: Option<@mut HTMLCollection>;
rval = doc.getElementsByTagName(arg0);
if rval.is_none() {
JS_SET_RVAL(cx, vp, JSVAL_NULL);
} else {
let cache = doc.get_wrappercache();
let rval = rval.get() as @mut CacheableWrapper;
assert!(WrapNewBindingObject(cx, cache.get_wrapper(),
rval.get(),
cast::transmute(vp)));
rval,
cast::transmute(vp)));
}
return 1;
}
@ -115,6 +117,15 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) {
compartment.register_class(utils::instance_jsclass(~"DocumentInstance", finalize));
let ptr = create(compartment, doc);
compartment.define_property(~"document", RUST_OBJECT_TO_JSVAL(ptr),
GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8,
JSPROP_ENUMERATE);
}
pub fn create(compartment: @mut Compartment, doc: @mut Document) -> *JSObject {
let instance : jsobj = result::unwrap(
compartment.new_object_with_proto(~"DocumentInstance", ~"Document",
compartment.global_obj.ptr));
@ -124,11 +135,7 @@ pub fn init(compartment: @mut Compartment, doc: @mut Document) {
let raw_ptr: *libc::c_void = cast::reinterpret_cast(&squirrel_away(doc));
JS_SetReservedSlot(instance.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
}
compartment.define_property(~"document", RUST_OBJECT_TO_JSVAL(instance.ptr),
GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as *u8,
JSPROP_ENUMERATE);
instance.ptr
}
impl CacheableWrapper for Document {
@ -140,7 +147,8 @@ impl CacheableWrapper for Document {
fail!(~"need to implement wrapping");
}
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"need to implement wrapping");
fn wrap_object_shared(@mut self, cx: *JSContext, _scope: *JSObject) -> *JSObject {
let content = task_from_context(cx);
unsafe { create((*content).compartment.get(), self) }
}
}

View file

@ -0,0 +1,44 @@
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_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"need to implement wrapping");
}
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;
}
}
}

View file

@ -102,9 +102,10 @@ extern fn getClientRects(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool {
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.get(),
cast::transmute(vp)));
rval,
cast::transmute(vp)));
}
return 1;
}

View file

@ -5,7 +5,7 @@
use content::content_task::task_from_context;
use dom::node::AbstractNode;
use dom::bindings::codegen::HTMLCollectionBinding;
use dom::bindings::utils::{DOMString, ErrorResult, OpaqueBindingReference};
use dom::bindings::utils::{DOMString, ErrorResult};
use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache};
use js::jsapi::{JSObject, JSContext};
@ -46,9 +46,9 @@ pub impl HTMLCollection {
}
impl BindingObject for HTMLCollection {
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
let content = task_from_context(cx);
unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
unsafe { (*content).window.get() as @mut CacheableWrapper }
}
}
@ -57,12 +57,12 @@ impl CacheableWrapper for HTMLCollection {
unsafe { cast::transmute(&self.wrapper) }
}
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
fn wrap_object_unique(~self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"nyi")
}
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
let mut unused = false;
HTMLCollectionBinding::Wrap(cx, scope, self, &mut unused)
}
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"nyi")
}
}

View file

@ -175,7 +175,7 @@ impl CacheableWrapper for AbstractNode {
fail!(~"need to implement wrapping");
}
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"need to implement wrapping");
}
}

View file

@ -18,7 +18,7 @@ use js::jsapi::bindgen::{JS_ValueToString,
JS_DefineProperties,
JS_WrapValue, JS_ForwardGetPropertyTo,
JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject,
JS_EncodeString, JS_free};
JS_EncodeString, JS_free, JS_GetStringCharsAndLength};
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
use js::glue::bindgen::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL};
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB,
@ -30,7 +30,9 @@ use content::content_task::task_from_context;
use core::hashmap::HashMap;
use dom::bindings::document;
use dom::bindings::node;
use dom::document::Document;
use dom::node::AbstractNode;
static TOSTRING_CLASS_RESERVED_SLOT: u64 = 0;
@ -356,6 +358,7 @@ pub mod prototypes {
pub enum Prototype {
ClientRect,
ClientRectList,
DOMParser,
HTMLCollection,
_ID_Count
}
@ -540,7 +543,7 @@ pub extern fn ThrowingConstructor(_cx: *JSContext, _argc: uint, _vp: *JSVal) ->
}
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 {
//XXXjdm we should be storing the box pointer instead of the inner
let box = squirrel_away(protoArray);
@ -554,7 +557,7 @@ pub fn initialize_global(global: *JSObject) {
pub trait CacheableWrapper {
fn get_wrappercache(&mut self) -> &mut WrapperCache;
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject;
fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject;
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject;
}
pub struct WrapperCache {
@ -577,64 +580,48 @@ pub impl WrapperCache {
}
}
pub fn WrapNewBindingObject<T: CacheableWrapper>(cx: *JSContext, scope: *JSObject,
mut value: ~T, vp: *mut JSVal) -> bool {
pub fn WrapNewBindingObject(cx: *JSContext, scope: *JSObject,
mut value: @mut CacheableWrapper,
vp: *mut JSVal) -> bool {
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)*/ {
*vp = RUST_OBJECT_TO_JSVAL(obj);
return true;
}
let obj = if obj.is_not_null() {
obj
} else {
value.wrap_object_unique(cx, scope)
};
let obj = value.wrap_object_shared(cx, scope);
if obj.is_null() {
return false;
}
// MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
cache.set_wrapper(obj);
*vp = RUST_OBJECT_TO_JSVAL(obj);
return JS_WrapValue(cx, cast::transmute(vp)) != 0;
}
}
pub struct OpaqueBindingReference(Either<~CacheableWrapper, @CacheableWrapper>);
pub fn WrapNativeParent(cx: *JSContext, scope: *JSObject, p: &mut OpaqueBindingReference) -> *JSObject {
match p {
&OpaqueBindingReference(Left(ref mut p)) => {
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)
}
pub fn WrapNativeParent(cx: *JSContext, scope: *JSObject, mut p: @mut CacheableWrapper) -> *JSObject {
let cache = p.get_wrappercache();
let wrapper = cache.get_wrapper();
if wrapper.is_not_null() {
return wrapper;
}
let wrapper = p.wrap_object_shared(cx, scope);
cache.set_wrapper(wrapper);
wrapper
}
pub struct BindingReference<T>(Either<~T, @mut T>);
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 {
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
match **self {
Left(ref obj) => obj.GetParentObject(cx),
Right(ref obj) => obj.GetParentObject(cx)
@ -781,6 +768,7 @@ pub fn InitIds(cx: *JSContext, specs: &[JSPropertySpec], ids: &mut [jsid]) -> bo
pub trait DerivedWrapper {
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 {
@ -794,10 +782,87 @@ impl DerivedWrapper for AbstractNode {
unsafe { *vp = RUST_OBJECT_TO_JSVAL(node::create(cx, self).ptr) };
return 1;
}
fn wrap_shared(@mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
fail!(~"nyi")
}
}
/*impl DerivedWrapper for Document {
fn wrap(&mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
let cache = self.get_wrappercache();
let wrapper = cache.get_wrapper();
if wrapper.is_not_null() {
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
return 1;
}
let content = task_from_context(cx);
unsafe {
let compartment = (*content).compartment.get();
*vp = RUST_OBJECT_TO_JSVAL(document::create(compartment, self));
}
return 1;
}
}*/
pub impl Document {
fn wrap(@mut self, cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 {
let cache = self.get_wrappercache();
let wrapper = cache.get_wrapper();
if wrapper.is_not_null() {
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
return 1;
}
let content = task_from_context(cx);
unsafe {
let compartment = (*content).compartment.get();
*vp = RUST_OBJECT_TO_JSVAL(document::create(compartment, self));
}
return 1;
}
}
pub enum Error {
FailureUnknown
}
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
}
}

View file

@ -141,7 +141,7 @@ impl CacheableWrapper for Window {
fail!(~"should this be called?");
}
fn wrap_object_shared(@self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!(~"should this be called?");
}
}

View file

@ -20,7 +20,7 @@ pub fn Document(root: AbstractNode) -> Document {
}
pub impl Document {
fn getElementsByTagName(&self, tag: DOMString) -> Option<~HTMLCollection> {
fn getElementsByTagName(&self, tag: DOMString) -> Option<@mut HTMLCollection> {
let mut elements = ~[];
let tag = match tag {
str(s) => s,
@ -35,6 +35,6 @@ pub impl Document {
}
}
};
Some(~HTMLCollection::new(elements))
Some(@mut HTMLCollection::new(elements))
}
}

View file

@ -0,0 +1,30 @@
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
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) -> DOMParser {
DOMParser {
owner: owner,
wrapper: WrapperCache::new()
}
}
fn Constructor(owner: @mut Window, _rv: &mut ErrorResult) -> @mut DOMParser {
@mut 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) };
@mut Document(root)
}
}

View file

@ -144,8 +144,8 @@ pub impl<'self> Element {
self.attrs.push(Attr::new(name.to_str(), value_cell.take()));
}
fn getClientRects(&self) -> Option<~ClientRectListImpl> {
Some(~ClientRectListImpl::new())
fn getClientRects(&self) -> Option<@mut ClientRectListImpl> {
Some(@mut ClientRectListImpl::new())
}
}

View file

@ -385,4 +385,7 @@ pub fn define_bindings(compartment: @mut Compartment, doc: @mut Document, win: @
assert!(codegen::HTMLCollectionBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
assert!(codegen::DOMParserBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
}

View file

@ -68,14 +68,17 @@ pub mod dom {
pub mod proxyhandler;
pub mod clientrect;
pub mod clientrectlist;
pub mod domparser;
pub mod htmlcollection;
pub mod codegen {
pub mod ClientRectBinding;
pub mod ClientRectListBinding;
pub mod DOMParserBinding;
pub mod HTMLCollectionBinding;
}
}
pub mod document;
pub mod domparser;
pub mod element;
pub mod event;
pub mod node;

View file

@ -32,3 +32,9 @@ window.alert(tags[0]);
window.alert(tags[1]);
window.alert(tags[2]);
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"));