Add primitive binding example for Document (documentElement), and Node (firstChild, nextSibling, tagName).

This commit is contained in:
Josh Matthews 2012-07-12 19:12:20 -04:00
parent 82790f2bb1
commit 4a1c8cc2ec
16 changed files with 501 additions and 22 deletions

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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="

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

View 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;
}

View 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
}
}

View file

@ -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);
} }

View file

@ -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 {

View file

@ -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()
) )
}); });

View file

@ -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

View file

@ -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
View 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
View 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);