mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Add primitive binding example for Document (documentElement), and Node (firstChild, nextSibling, tagName).
This commit is contained in:
parent
82790f2bb1
commit
4a1c8cc2ec
16 changed files with 501 additions and 22 deletions
|
@ -87,6 +87,7 @@ CLEAN_DEPS += \
|
||||||
clean-ragel \
|
clean-ragel \
|
||||||
clean-harfbuzz \
|
clean-harfbuzz \
|
||||||
clean-rust-harfbuzz \
|
clean-rust-harfbuzz \
|
||||||
|
clean-mozjs \
|
||||||
clean-rust-mozjs \
|
clean-rust-mozjs \
|
||||||
clean-rust-sdl \
|
clean-rust-sdl \
|
||||||
clean-rust-azure \
|
clean-rust-azure \
|
||||||
|
@ -213,6 +214,10 @@ clean-harfbuzz:
|
||||||
clean-rust-harfbuzz:
|
clean-rust-harfbuzz:
|
||||||
$(MAKE) clean -C src/rust-harfbuzz
|
$(MAKE) clean -C src/rust-harfbuzz
|
||||||
|
|
||||||
|
.PHONY: clean-mozjs
|
||||||
|
clean-mozjs:
|
||||||
|
$(MAKE) clean -C src/mozjs
|
||||||
|
|
||||||
.PHONY: clean-rust-mozjs
|
.PHONY: clean-rust-mozjs
|
||||||
clean-rust-mozjs:
|
clean-rust-mozjs:
|
||||||
$(MAKE) clean -C src/rust-mozjs
|
$(MAKE) clean -C src/rust-mozjs
|
||||||
|
|
|
@ -19,7 +19,7 @@ mkdir -p src/rust-layers || exit $?
|
||||||
|
|
||||||
(cd src/ragel && sh ${SRCDIR}/src/ragel/configure) || exit $?
|
(cd src/ragel && sh ${SRCDIR}/src/ragel/configure) || exit $?
|
||||||
(cd src/harfbuzz && sh ${SRCDIR}/src/harfbuzz/configure --enable-static) || exit $?
|
(cd src/harfbuzz && sh ${SRCDIR}/src/harfbuzz/configure --enable-static) || exit $?
|
||||||
(cd src/mozjs && sh ${SRCDIR}/src/mozjs/js/src/configure) || exit $?
|
(cd src/mozjs && sh ${SRCDIR}/src/mozjs/js/src/configure --enable-debug --disable-optimize) || exit $?
|
||||||
(cd src/rust-opengles && sh ${SRCDIR}/src/rust-opengles/configure) || exit $?
|
(cd src/rust-opengles && sh ${SRCDIR}/src/rust-opengles/configure) || exit $?
|
||||||
(cd src/rust-harfbuzz && sh ${SRCDIR}/src/rust-harfbuzz/configure) || exit $?
|
(cd src/rust-harfbuzz && sh ${SRCDIR}/src/rust-harfbuzz/configure) || exit $?
|
||||||
(cd src/rust-mozjs && sh ${SRCDIR}/src/rust-mozjs/configure) || exit $?
|
(cd src/rust-mozjs && sh ${SRCDIR}/src/rust-mozjs/configure) || exit $?
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 8e60882ebf2c68766747b1d673a94c77b75f2b78
|
Subproject commit 9dca4b316e36c85f8b165b32c87e0a74635f61ac
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0f3d130e46b1314f1c98b99ce91f443805a9efa6
|
Subproject commit af4cb2481c60688d6b10dd8d5e2ffd6842a28384
|
|
@ -7,13 +7,14 @@ export Content;
|
||||||
export ControlMsg, ExecuteMsg, ParseMsg, ExitMsg;
|
export ControlMsg, ExecuteMsg, ParseMsg, ExitMsg;
|
||||||
export PingMsg, PongMsg;
|
export PingMsg, PongMsg;
|
||||||
export create_content;
|
export create_content;
|
||||||
|
export Document;
|
||||||
|
|
||||||
import comm::{port, chan, listen, select2};
|
import comm::{port, chan, listen, select2};
|
||||||
import task::{spawn, spawn_listener};
|
import task::{spawn, spawn_listener};
|
||||||
import io::{read_whole_file, println};
|
import io::{read_whole_file, println};
|
||||||
import result::{ok, err};
|
import result::{ok, err};
|
||||||
|
|
||||||
import dom::base::{Node, NodeScope};
|
import dom::base::{Node, NodeScope, define_bindings};
|
||||||
import dom::event::{Event, ResizeEvent};
|
import dom::event::{Event, ResizeEvent};
|
||||||
import dom::rcu::WriterMethods;
|
import dom::rcu::WriterMethods;
|
||||||
import dom::style;
|
import dom::style;
|
||||||
|
@ -31,6 +32,9 @@ import js::global::{global_class, debug_fns};
|
||||||
import either::{either, left, right};
|
import either::{either, left, right};
|
||||||
import result::extensions;
|
import result::extensions;
|
||||||
|
|
||||||
|
import dom::bindings::utils::rust_box;
|
||||||
|
import js::rust::compartment;
|
||||||
|
|
||||||
type Content = chan<ControlMsg>;
|
type Content = chan<ControlMsg>;
|
||||||
|
|
||||||
enum ControlMsg {
|
enum ControlMsg {
|
||||||
|
@ -75,7 +79,7 @@ class Content<S:Sink send copy> {
|
||||||
let scope: NodeScope;
|
let scope: NodeScope;
|
||||||
let jsrt: jsrt;
|
let jsrt: jsrt;
|
||||||
|
|
||||||
let mut document: option<Document>;
|
let mut document: option<@Document>;
|
||||||
|
|
||||||
new(layout: Layout, sink: S, from_master: port<ControlMsg>) {
|
new(layout: Layout, sink: S, from_master: port<ControlMsg>) {
|
||||||
self.layout = layout;
|
self.layout = layout;
|
||||||
|
@ -116,15 +120,31 @@ class Content<S:Sink send copy> {
|
||||||
// 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.
|
||||||
let stream = spawn_html_lexer_task(copy filename);
|
let stream = spawn_html_lexer_task(copy filename);
|
||||||
let (root, style_port) = build_dom(self.scope, stream);
|
let (root, style_port, js_port) = build_dom(self.scope, stream);
|
||||||
let css_rules = style_port.recv();
|
let css_rules = style_port.recv();
|
||||||
|
let js_scripts = js_port.recv();
|
||||||
|
|
||||||
// Apply the css rules to the dom tree:
|
// Apply the css rules to the dom tree:
|
||||||
#debug["%?", css_rules];
|
#debug["%?", css_rules];
|
||||||
|
|
||||||
|
#debug["%?", js_scripts];
|
||||||
|
|
||||||
let document = Document(root, css_rules);
|
let document = Document(root, css_rules);
|
||||||
self.relayout(document);
|
self.relayout(document);
|
||||||
self.document = some(document);
|
self.document = some(@document);
|
||||||
|
|
||||||
|
//XXXjdm it was easier to duplicate the relevant ExecuteMsg code;
|
||||||
|
// they should be merged somehow in the future.
|
||||||
|
for vec::each(js_scripts) |bytes| {
|
||||||
|
let cx = self.jsrt.cx();
|
||||||
|
cx.set_default_options_and_version();
|
||||||
|
cx.set_logging_error_reporter();
|
||||||
|
cx.new_compartment(global_class).chain(|compartment| {
|
||||||
|
compartment.define_functions(debug_fns);
|
||||||
|
define_bindings(*compartment, option::get(self.document));
|
||||||
|
cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ret true;
|
ret true;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +201,7 @@ class Content<S:Sink send copy> {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
some(document) {
|
some(document) {
|
||||||
self.relayout(document);
|
self.relayout(*document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret true;
|
ret true;
|
||||||
|
|
|
@ -5,6 +5,14 @@ import gfx::geometry::au;
|
||||||
import geom::size::Size2D;
|
import geom::size::Size2D;
|
||||||
import layout::base::LayoutData;
|
import layout::base::LayoutData;
|
||||||
import util::tree;
|
import util::tree;
|
||||||
|
import js::rust::{bare_compartment, compartment, methods};
|
||||||
|
import js::jsapi::{JSClass, JSObject, JSPropertySpec, JSContext, jsid, jsval, JSBool};
|
||||||
|
import js::{JSPROP_ENUMERATE, JSPROP_SHARED};
|
||||||
|
import js::crust::*;
|
||||||
|
import js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
|
||||||
|
import ptr::null;
|
||||||
|
import content::Document;
|
||||||
|
import bindings;
|
||||||
|
|
||||||
import dvec::{dvec, extensions};
|
import dvec::{dvec, extensions};
|
||||||
|
|
||||||
|
@ -52,11 +60,17 @@ class Attr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn define_bindings(compartment: bare_compartment, doc: @Document) {
|
||||||
|
//bindings::window::init(compartment);
|
||||||
|
bindings::document::init(compartment, doc);
|
||||||
|
}
|
||||||
|
|
||||||
enum ElementKind {
|
enum ElementKind {
|
||||||
UnknownElement,
|
UnknownElement,
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
HTMLHeadElement,
|
HTMLHeadElement,
|
||||||
HTMLImageElement({mut size: Size2D<au>})
|
HTMLImageElement({mut size: Size2D<au>}),
|
||||||
|
HTMLScriptElement
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc="
|
#[doc="
|
||||||
|
|
139
src/servo/dom/bindings/document.rs
Normal file
139
src/servo/dom/bindings/document.rs
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
import js::rust::{bare_compartment, methods};
|
||||||
|
import js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL, JS_THIS_OBJECT,
|
||||||
|
JS_SET_RVAL};
|
||||||
|
import js::jsapi::{JSContext, jsval, JSObject, JSBool, jsid, JSClass, JSFreeOp};
|
||||||
|
import js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError,
|
||||||
|
JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN,
|
||||||
|
JS_DefineFunctions, JS_DefineProperty, JS_DefineProperties};
|
||||||
|
import js::glue::bindgen::*;
|
||||||
|
import js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub, JS_ResolveStub};
|
||||||
|
import js::ptr_methods;
|
||||||
|
import result::{result, ok, err};
|
||||||
|
import ptr::null;
|
||||||
|
import libc::c_uint;
|
||||||
|
import utils::{DOMString, domstring_to_jsval, rust_box, squirrel_away, str};
|
||||||
|
import bindings::node::create;
|
||||||
|
import content::Document;
|
||||||
|
|
||||||
|
enum DOMException {
|
||||||
|
INVALID_CHARACTER_ERR
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Element = int;
|
||||||
|
|
||||||
|
/*extern fn getElementById(cx: *JSContext, argc: c_uint, vp: *jsval) -> JSBool {
|
||||||
|
//XXX check if actually document object
|
||||||
|
if argc != 1 {
|
||||||
|
//XXX throw proper DOM exception
|
||||||
|
str::as_c_str("Not enough arguments", |s| {
|
||||||
|
JS_ReportError(cx, s);
|
||||||
|
});
|
||||||
|
ret 0;
|
||||||
|
}
|
||||||
|
let id;
|
||||||
|
unsafe {
|
||||||
|
id = JS_ARGV(cx, vp)[0];
|
||||||
|
}
|
||||||
|
alt jsval_to_str(cx, id) {
|
||||||
|
ok(s) {
|
||||||
|
unsafe {
|
||||||
|
let doc: *Document = unsafe::reinterpret_cast(JS_GetContextPrivate(cx));
|
||||||
|
let elem = (*doc).getElementById(s);
|
||||||
|
}
|
||||||
|
//XXX wrap result
|
||||||
|
ret 1;
|
||||||
|
}
|
||||||
|
err(_) {
|
||||||
|
str::as_c_str("???", |s| {
|
||||||
|
JS_ReportError(cx, s);
|
||||||
|
});
|
||||||
|
ret 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*extern fn getDocumentURI(cx: *JSContext, _argc: c_uint, vp: *jsval) -> JSBool {
|
||||||
|
unsafe {
|
||||||
|
let uri = (*unwrap(JS_THIS_OBJECT(cx, vp))).payload.getDocumentURI();
|
||||||
|
JS_SET_RVAL(cx, vp, domstring_to_jsval(cx, uri));
|
||||||
|
}
|
||||||
|
ret 1;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
extern fn getDocumentElement(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool unsafe {
|
||||||
|
let node = (*unwrap(obj)).payload.root;
|
||||||
|
*rval = RUST_OBJECT_TO_JSVAL(node::create(cx, node).ptr);
|
||||||
|
ret 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn unwrap(obj: *JSObject) -> *rust_box<Document> {
|
||||||
|
let val = JS_GetReservedSlot(obj, 0);
|
||||||
|
unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
|
#debug("document finalize!");
|
||||||
|
unsafe {
|
||||||
|
let val = JS_GetReservedSlot(obj, 0);
|
||||||
|
let _doc: @Document = unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(compartment: bare_compartment, doc: @Document) {
|
||||||
|
fn Document_class(compartment: bare_compartment) -> JSClass {
|
||||||
|
{name: compartment.add_name(~"DOMDocument"),
|
||||||
|
flags: JSCLASS_HAS_RESERVED_SLOTS(1),
|
||||||
|
addProperty: JS_PropertyStub,
|
||||||
|
delProperty: JS_PropertyStub,
|
||||||
|
getProperty: JS_PropertyStub,
|
||||||
|
setProperty: JS_StrictPropertyStub,
|
||||||
|
enumerate: JS_EnumerateStub,
|
||||||
|
resolve: JS_ResolveStub,
|
||||||
|
convert: JS_ConvertStub,
|
||||||
|
finalize: finalize,
|
||||||
|
checkAccess: null(),
|
||||||
|
call: null(),
|
||||||
|
construct: null(),
|
||||||
|
hasInstance: null(),
|
||||||
|
trace: null(),
|
||||||
|
reserved: (null(), null(), null(), null(), null(), // 05
|
||||||
|
null(), null(), null(), null(), null(), // 10
|
||||||
|
null(), null(), null(), null(), null(), // 15
|
||||||
|
null(), null(), null(), null(), null(), // 20
|
||||||
|
null(), null(), null(), null(), null(), // 25
|
||||||
|
null(), null(), null(), null(), null(), // 30
|
||||||
|
null(), null(), null(), null(), null(), // 35
|
||||||
|
null(), null(), null(), null(), null())} // 40
|
||||||
|
};
|
||||||
|
|
||||||
|
let obj = result::unwrap(
|
||||||
|
compartment.new_object(Document_class, null(), null()));
|
||||||
|
/*let methods = ~[
|
||||||
|
{name: compartment.add_name("getDocumentURI"),
|
||||||
|
call: getDocumentURI,
|
||||||
|
nargs: 0,
|
||||||
|
flags: 0}];
|
||||||
|
vec::as_buf(methods, |fns| {
|
||||||
|
JS_DefineFunctions(compartment.cx.ptr, obj.ptr, fns);
|
||||||
|
});*/
|
||||||
|
|
||||||
|
let attrs = @~[
|
||||||
|
{name: compartment.add_name(~"documentElement"),
|
||||||
|
tinyid: 0,
|
||||||
|
flags: 0,
|
||||||
|
getter: getDocumentElement,
|
||||||
|
setter: null()}];
|
||||||
|
vec::push(compartment.global_props, attrs);
|
||||||
|
vec::as_buf(*attrs, |specs, _len| {
|
||||||
|
JS_DefineProperties(compartment.cx.ptr, obj.ptr, specs);
|
||||||
|
});
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let raw_ptr: *libc::c_void = unsafe::reinterpret_cast(squirrel_away(doc));
|
||||||
|
JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
compartment.define_property(~"document", RUST_OBJECT_TO_JSVAL(obj.ptr),
|
||||||
|
JS_PropertyStub, JS_StrictPropertyStub,
|
||||||
|
JSPROP_ENUMERATE);
|
||||||
|
}
|
143
src/servo/dom/bindings/node.rs
Normal file
143
src/servo/dom/bindings/node.rs
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
import js::rust::{bare_compartment, methods, jsobj};
|
||||||
|
import js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL,
|
||||||
|
JS_THIS_OBJECT, JS_SET_RVAL};
|
||||||
|
import js::jsapi::{JSContext, jsval, JSObject, JSBool, jsid, JSClass, JSFreeOp, JSPropertySpec};
|
||||||
|
import js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError,
|
||||||
|
JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN,
|
||||||
|
JS_DefineFunctions, JS_DefineProperty, JS_GetContextPrivate};
|
||||||
|
import js::jsapi::bindgen::*;
|
||||||
|
import js::glue::bindgen::*;
|
||||||
|
import js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub};
|
||||||
|
|
||||||
|
import dom::base::{Node, Element};
|
||||||
|
import utils::{rust_box, squirrel_away_unique, get_compartment, domstring_to_jsval, str};
|
||||||
|
import libc::c_uint;
|
||||||
|
import ptr::null;
|
||||||
|
import rcu::ReaderMethods;
|
||||||
|
|
||||||
|
extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
|
#debug("node finalize!");
|
||||||
|
unsafe {
|
||||||
|
let val = JS_GetReservedSlot(obj, 0);
|
||||||
|
let _node: ~Node = unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(cx: *JSContext, node: Node) -> jsobj unsafe {
|
||||||
|
let compartment = get_compartment(cx);
|
||||||
|
fn Node_class(compartment: bare_compartment) -> JSClass {
|
||||||
|
{name: compartment.add_name(~"Node"),
|
||||||
|
flags: JSCLASS_HAS_RESERVED_SLOTS(1),
|
||||||
|
addProperty: JS_PropertyStub,
|
||||||
|
delProperty: JS_PropertyStub,
|
||||||
|
getProperty: JS_PropertyStub,
|
||||||
|
setProperty: JS_StrictPropertyStub,
|
||||||
|
enumerate: JS_EnumerateStub,
|
||||||
|
resolve: JS_PropertyStub,
|
||||||
|
convert: JS_ConvertStub,
|
||||||
|
finalize: finalize,
|
||||||
|
checkAccess: null(),
|
||||||
|
call: null(),
|
||||||
|
construct: null(),
|
||||||
|
hasInstance: null(),
|
||||||
|
trace: null(),
|
||||||
|
reserved: (null(), null(), null(), null(), null(), // 05
|
||||||
|
null(), null(), null(), null(), null(), // 10
|
||||||
|
null(), null(), null(), null(), null(), // 15
|
||||||
|
null(), null(), null(), null(), null(), // 20
|
||||||
|
null(), null(), null(), null(), null(), // 25
|
||||||
|
null(), null(), null(), null(), null(), // 30
|
||||||
|
null(), null(), null(), null(), null(), // 35
|
||||||
|
null(), null(), null(), null(), null())} // 40
|
||||||
|
};
|
||||||
|
|
||||||
|
let obj = result::unwrap(
|
||||||
|
(*compartment).new_object(Node_class, null(),
|
||||||
|
(*compartment).global_obj.ptr));
|
||||||
|
let attrs = @~[
|
||||||
|
{name: (*compartment).add_name(~"firstChild"),
|
||||||
|
tinyid: 0,
|
||||||
|
flags: 0,
|
||||||
|
getter: getFirstChild,
|
||||||
|
setter: null()},
|
||||||
|
|
||||||
|
{name: (*compartment).add_name(~"nextSibling"),
|
||||||
|
tinyid: 0,
|
||||||
|
flags: 0,
|
||||||
|
getter: getNextSibling,
|
||||||
|
setter: null()},
|
||||||
|
|
||||||
|
{name: (*compartment).add_name(~"tagName"),
|
||||||
|
tinyid: 0,
|
||||||
|
flags: 0,
|
||||||
|
getter: getTagName,
|
||||||
|
setter: null()}];
|
||||||
|
vec::push((*compartment).global_props, attrs);
|
||||||
|
vec::as_buf(*attrs, |specs, _len| {
|
||||||
|
JS_DefineProperties((*compartment).cx.ptr, obj.ptr, specs);
|
||||||
|
});
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let raw_ptr: *libc::c_void = unsafe::reinterpret_cast(squirrel_away_unique(~node));
|
||||||
|
JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn unwrap(obj: *JSObject) -> *rust_box<Node> {
|
||||||
|
let val = JS_GetReservedSlot(obj, 0);
|
||||||
|
unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn getFirstChild(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool {
|
||||||
|
unsafe {
|
||||||
|
(*unwrap(obj)).payload.read(|nd| {
|
||||||
|
alt nd.tree.first_child {
|
||||||
|
some(n) {
|
||||||
|
let obj = create(cx, n).ptr;
|
||||||
|
*rval = RUST_OBJECT_TO_JSVAL(obj);
|
||||||
|
}
|
||||||
|
none {
|
||||||
|
*rval = JSVAL_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ret 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn getNextSibling(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool {
|
||||||
|
unsafe {
|
||||||
|
(*unwrap(obj)).payload.read(|nd| {
|
||||||
|
alt nd.tree.next_sibling {
|
||||||
|
some(n) {
|
||||||
|
let obj = create(cx, n).ptr;
|
||||||
|
*rval = RUST_OBJECT_TO_JSVAL(obj);
|
||||||
|
}
|
||||||
|
none {
|
||||||
|
*rval = JSVAL_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ret 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn getTagName(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool {
|
||||||
|
unsafe {
|
||||||
|
(*unwrap(obj)).payload.read(|nd| {
|
||||||
|
alt nd.kind {
|
||||||
|
~Element(ed) {
|
||||||
|
let s = str(ed.tag_name);
|
||||||
|
*rval = domstring_to_jsval(cx, s);
|
||||||
|
}
|
||||||
|
_ {
|
||||||
|
//XXXjdm should probably read the spec to figure out what to do here
|
||||||
|
*rval = JSVAL_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ret 1;
|
||||||
|
}
|
77
src/servo/dom/bindings/utils.rs
Normal file
77
src/servo/dom/bindings/utils.rs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import js::rust::{compartment, bare_compartment};
|
||||||
|
import js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL,
|
||||||
|
JS_THIS_OBJECT, JS_SET_RVAL};
|
||||||
|
import js::jsapi::{JSContext, jsval, JSObject, JSBool, jsid, JSClass, JSFreeOp};
|
||||||
|
import js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError,
|
||||||
|
JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN,
|
||||||
|
JS_DefineFunctions, JS_DefineProperty, JS_GetContextPrivate};
|
||||||
|
import js::glue::bindgen::*;
|
||||||
|
import result::{result, ok, err};
|
||||||
|
|
||||||
|
enum DOMString {
|
||||||
|
str(~str),
|
||||||
|
null_string
|
||||||
|
}
|
||||||
|
|
||||||
|
type rust_box<T> = {rc: uint, td: *sys::type_desc, next: *(), prev: *(), payload: T};
|
||||||
|
|
||||||
|
unsafe fn squirrel_away<T>(+x: @T) -> *rust_box<T> {
|
||||||
|
let y: *rust_box<T> = unsafe::reinterpret_cast(x);
|
||||||
|
unsafe::forget(x);
|
||||||
|
y
|
||||||
|
}
|
||||||
|
|
||||||
|
type rust_unique<T> = {payload: T};
|
||||||
|
|
||||||
|
unsafe fn squirrel_away_unique<T>(+x: ~T) -> *rust_box<T> {
|
||||||
|
let y: *rust_box<T> = unsafe::reinterpret_cast(x);
|
||||||
|
unsafe::forget(x);
|
||||||
|
y
|
||||||
|
}
|
||||||
|
|
||||||
|
//XXX very incomplete
|
||||||
|
fn jsval_to_str(cx: *JSContext, v: jsval) -> result<~str, ()> {
|
||||||
|
let jsstr;
|
||||||
|
if RUST_JSVAL_IS_STRING(v) == 1 {
|
||||||
|
jsstr = RUST_JSVAL_TO_STRING(v)
|
||||||
|
} else {
|
||||||
|
jsstr = JS_ValueToString(cx, v);
|
||||||
|
if jsstr.is_null() {
|
||||||
|
ret err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = 0;
|
||||||
|
let chars = JS_GetStringCharsZAndLength(cx, jsstr, ptr::addr_of(len));
|
||||||
|
ret if chars.is_null() {
|
||||||
|
err(())
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let buf = vec::unsafe::from_buf(chars as *u8, len as uint);
|
||||||
|
ok(str::from_bytes(buf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn domstring_to_jsval(cx: *JSContext, str: DOMString) -> jsval {
|
||||||
|
alt str {
|
||||||
|
null_string {
|
||||||
|
JSVAL_NULL
|
||||||
|
}
|
||||||
|
str(s) {
|
||||||
|
str::as_buf(s, |buf, len| {
|
||||||
|
let cbuf = unsafe::reinterpret_cast(buf);
|
||||||
|
RUST_STRING_TO_JSVAL(JS_NewStringCopyN(cx, cbuf, len as libc::size_t))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_compartment(cx: *JSContext) -> *bare_compartment {
|
||||||
|
unsafe {
|
||||||
|
let priv: *libc::c_void = JS_GetContextPrivate(cx);
|
||||||
|
let compartment: *bare_compartment = unsafe::reinterpret_cast(priv);
|
||||||
|
assert cx == (*compartment).cx.ptr;
|
||||||
|
compartment
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#[doc="Constructs a DOM tree from an incoming token stream."]
|
#[doc="Constructs a DOM tree from an incoming token stream."]
|
||||||
|
|
||||||
import dom::base::{Attr, Element, ElementData, ElementKind, HTMLDivElement, HTMLHeadElement};
|
import dom::base::{Attr, Element, ElementData, ElementKind, HTMLDivElement, HTMLHeadElement,
|
||||||
|
HTMLScriptElement};
|
||||||
import dom::base::{HTMLImageElement, Node, NodeScope, Text, TreeReadMethods, TreeWriteMethods};
|
import dom::base::{HTMLImageElement, Node, NodeScope, Text, TreeReadMethods, TreeWriteMethods};
|
||||||
import dom::base::{UnknownElement};
|
import dom::base::{UnknownElement};
|
||||||
import dom::rcu::WriterMethods;
|
import dom::rcu::WriterMethods;
|
||||||
|
@ -19,6 +20,11 @@ enum CSSMessage {
|
||||||
Exit
|
Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum js_message {
|
||||||
|
js_file(~str),
|
||||||
|
js_exit
|
||||||
|
}
|
||||||
|
|
||||||
#[warn(no_non_implicitly_copyable_typarams)]
|
#[warn(no_non_implicitly_copyable_typarams)]
|
||||||
fn link_up_attribute(scope: NodeScope, node: Node, -key: ~str, -value: ~str) {
|
fn link_up_attribute(scope: NodeScope, node: Node, -key: ~str, -value: ~str) {
|
||||||
// TODO: Implement atoms so that we don't always perform string comparisons.
|
// TODO: Implement atoms so that we don't always perform string comparisons.
|
||||||
|
@ -45,7 +51,8 @@ fn link_up_attribute(scope: NodeScope, node: Node, -key: ~str, -value: ~str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HTMLDivElement | HTMLImageElement(*) | HTMLHeadElement | UnknownElement {
|
HTMLDivElement | HTMLImageElement(*) | HTMLHeadElement |
|
||||||
|
HTMLScriptElement | UnknownElement {
|
||||||
// Drop on the floor.
|
// Drop on the floor.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +74,7 @@ fn build_element_kind(tag_name: ~str) -> ~ElementKind {
|
||||||
geometry::px_to_au(100))
|
geometry::px_to_au(100))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
~"script" { ~HTMLScriptElement }
|
||||||
~"head" { ~HTMLHeadElement }
|
~"head" { ~HTMLHeadElement }
|
||||||
_ { ~UnknownElement }
|
_ { ~UnknownElement }
|
||||||
}
|
}
|
||||||
|
@ -116,8 +124,38 @@ fn css_link_listener(to_parent : chan<Stylesheet>, from_parent : port<CSSMessage
|
||||||
to_parent.send(css_rules);
|
to_parent.send(css_rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn js_script_listener(to_parent : chan<~[~[u8]]>, from_parent : port<js_message>) {
|
||||||
|
let mut result_vec = ~[];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
alt from_parent.recv() {
|
||||||
|
js_file(filename) {
|
||||||
|
let result_port = comm::port();
|
||||||
|
let result_chan = comm::chan(result_port);
|
||||||
|
let filename = copy filename;
|
||||||
|
do task::spawn {
|
||||||
|
let filename <- copy filename;
|
||||||
|
let file_try = io::read_whole_file(filename);
|
||||||
|
if (file_try.is_ok()) {
|
||||||
|
result_chan.send(file_try.get());
|
||||||
|
} else {
|
||||||
|
#error("error loading script %s", filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push(result_vec, result_port);
|
||||||
|
}
|
||||||
|
js_exit {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let js_scripts = vec::map(result_vec, |result_port| result_port.recv());
|
||||||
|
to_parent.send(js_scripts);
|
||||||
|
}
|
||||||
|
|
||||||
#[warn(no_non_implicitly_copyable_typarams)]
|
#[warn(no_non_implicitly_copyable_typarams)]
|
||||||
fn build_dom(scope: NodeScope, stream: port<Token>) -> (Node, port<Stylesheet>) {
|
fn build_dom(scope: NodeScope, stream: port<Token>) -> (Node, port<Stylesheet>, port<~[~[u8]]>) {
|
||||||
// The current reference node.
|
// The current reference node.
|
||||||
let mut cur_node = scope.new_node(Element(ElementData(~"html", ~HTMLDivElement)));
|
let mut cur_node = scope.new_node(Element(ElementData(~"html", ~HTMLDivElement)));
|
||||||
// We will spawn a separate task to parse any css that is
|
// We will spawn a separate task to parse any css that is
|
||||||
|
@ -131,6 +169,12 @@ fn build_dom(scope: NodeScope, stream: port<Token>) -> (Node, port<Stylesheet>)
|
||||||
css_link_listener(child_chan, child_port);
|
css_link_listener(child_chan, child_port);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let js_port = comm::port();
|
||||||
|
let child_chan = comm::chan(js_port);
|
||||||
|
let js_chan = task::spawn_listener(|child_port| {
|
||||||
|
js_script_listener(child_chan, child_port);
|
||||||
|
});
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let token = stream.recv();
|
let token = stream.recv();
|
||||||
alt token {
|
alt token {
|
||||||
|
@ -174,8 +218,22 @@ fn build_dom(scope: NodeScope, stream: port<Token>) -> (Node, port<Stylesheet>)
|
||||||
});
|
});
|
||||||
cur_node = scope.get_parent(cur_node).get();
|
cur_node = scope.get_parent(cur_node).get();
|
||||||
}
|
}
|
||||||
parser::EndTag(_) {
|
parser::EndTag(tag_name) {
|
||||||
// TODO: Assert that the closing tag has the right name.
|
// TODO: Assert that the closing tag has the right name.
|
||||||
|
scope.read(cur_node, |n| {
|
||||||
|
alt *n.kind {
|
||||||
|
Element(elmt) if elmt.tag_name == ~"script" {
|
||||||
|
alt elmt.get_attr(~"src") {
|
||||||
|
some(filename) {
|
||||||
|
#debug["Linking to a js script named: %s", filename];
|
||||||
|
js_chan.send(js_file(copy filename));
|
||||||
|
}
|
||||||
|
none { /* fall through */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ { /* fall though */ }
|
||||||
|
}
|
||||||
|
});
|
||||||
cur_node = scope.get_parent(cur_node).get();
|
cur_node = scope.get_parent(cur_node).get();
|
||||||
}
|
}
|
||||||
parser::Text(s) if !s.is_whitespace() {
|
parser::Text(s) if !s.is_whitespace() {
|
||||||
|
@ -192,6 +250,7 @@ fn build_dom(scope: NodeScope, stream: port<Token>) -> (Node, port<Stylesheet>)
|
||||||
}
|
}
|
||||||
|
|
||||||
style_chan.send(Exit);
|
style_chan.send(Exit);
|
||||||
|
js_chan.send(js_exit);
|
||||||
|
|
||||||
ret (cur_node, style_port);
|
ret (cur_node, style_port, js_port);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,11 @@ mod dom {
|
||||||
mod event;
|
mod event;
|
||||||
mod rcu;
|
mod rcu;
|
||||||
mod style;
|
mod style;
|
||||||
|
mod bindings {
|
||||||
|
mod document;
|
||||||
|
mod utils;
|
||||||
|
mod node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod gfx {
|
mod gfx {
|
||||||
|
|
|
@ -200,8 +200,8 @@ fn get_cairo_face(buf: &~[u8]) -> (*cairo_font_face_t, fn@()) {
|
||||||
dtor = fn@(move dtor) { FT_Done_FreeType(library).for_sure(); dtor() };
|
dtor = fn@(move dtor) { FT_Done_FreeType(library).for_sure(); dtor() };
|
||||||
|
|
||||||
let face: FT_Face = null();
|
let face: FT_Face = null();
|
||||||
vec::as_buf(*buf, |cbuf| {
|
vec::as_buf(*buf, |cbuf, len| {
|
||||||
if FT_New_Memory_Face(library, cbuf, (*buf).len() as FT_Long,
|
if FT_New_Memory_Face(library, cbuf, len as FT_Long,
|
||||||
0 as FT_Long, addr_of(face)).failed() {
|
0 as FT_Long, addr_of(face)).failed() {
|
||||||
dtor();
|
dtor();
|
||||||
fail ~"unable to create FreeType face";
|
fail ~"unable to create FreeType face";
|
||||||
|
@ -241,11 +241,11 @@ fn get_cairo_face(buf: &~[u8]) -> (*cairo_font_face_t, fn@()) {
|
||||||
|
|
||||||
let mut dtor = fn@() { };
|
let mut dtor = fn@() { };
|
||||||
|
|
||||||
let fontprov = vec::as_buf(*buf, |cbuf| {
|
let fontprov = vec::as_buf(*buf, |cbuf, len| {
|
||||||
CGDataProviderCreateWithData(
|
CGDataProviderCreateWithData(
|
||||||
null(),
|
null(),
|
||||||
unsafe { reinterpret_cast(cbuf) },
|
unsafe { reinterpret_cast(cbuf) },
|
||||||
(*buf).len() as size_t,
|
len as size_t,
|
||||||
null()
|
null()
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,11 +49,11 @@ class QuartzNativeFont/& {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(buf: ~[u8]) -> result<QuartzNativeFont, ()> {
|
fn create(buf: ~[u8]) -> result<QuartzNativeFont, ()> {
|
||||||
let fontprov = vec::as_buf(buf, |cbuf| {
|
let fontprov = vec::as_buf(buf, |cbuf, len| {
|
||||||
CGDataProviderCreateWithData(
|
CGDataProviderCreateWithData(
|
||||||
null(),
|
null(),
|
||||||
unsafe { reinterpret_cast(cbuf) },
|
unsafe { reinterpret_cast(cbuf) },
|
||||||
buf.len() as size_t,
|
len as size_t,
|
||||||
null())
|
null())
|
||||||
});
|
});
|
||||||
// FIXME: Error handling
|
// FIXME: Error handling
|
||||||
|
|
|
@ -38,9 +38,9 @@ when rendered in a specific font.
|
||||||
fn shape_text(font: &Font, text: ~str) -> ~[Glyph] unsafe {
|
fn shape_text(font: &Font, text: ~str) -> ~[Glyph] unsafe {
|
||||||
#debug("shaping text '%s'", text);
|
#debug("shaping text '%s'", text);
|
||||||
|
|
||||||
let face_blob = vec::as_buf(*(*font).buf(), |buf| {
|
let face_blob = vec::as_buf(*(*font).buf(), |buf, len| {
|
||||||
hb_blob_create(reinterpret_cast(buf),
|
hb_blob_create(reinterpret_cast(buf),
|
||||||
(*(*font).buf()).len() as c_uint,
|
len as c_uint,
|
||||||
HB_MEMORY_MODE_READONLY,
|
HB_MEMORY_MODE_READONLY,
|
||||||
null(),
|
null(),
|
||||||
null())
|
null())
|
||||||
|
|
7
src/test/test-js.html
Normal file
7
src/test/test-js.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<div>
|
||||||
|
<img></img>
|
||||||
|
<div>
|
||||||
|
<img></img><img></img><img></img>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="../src/test/test_docelem.js"></script>
|
10
src/test/test_docelem.js
Normal file
10
src/test/test_docelem.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
debug("hi");
|
||||||
|
var elem = document.documentElement;
|
||||||
|
debug(elem);
|
||||||
|
debug(elem.tagName);
|
||||||
|
debug(elem.firstChild);
|
||||||
|
debug(elem.firstChild.tagName);
|
||||||
|
debug(elem.firstChild.nextSibling);
|
||||||
|
debug(elem.firstChild.nextSibling.tagName);
|
||||||
|
debug(elem.nextSibling);
|
||||||
|
debug(elem.nextSibling.tagName);
|
Loading…
Add table
Add a link
Reference in a new issue