From 4a1c8cc2ec2bf7ca1197a5404ef94e1509981c01 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 12 Jul 2012 19:12:20 -0400 Subject: [PATCH] Add primitive binding example for Document (documentElement), and Node (firstChild, nextSibling, tagName). --- Makefile.in | 5 + configure.in | 2 +- src/rust-mozjs | 2 +- src/rust-sdl | 2 +- src/servo/content.rs | 30 +++- src/servo/dom/base.rs | 16 +- src/servo/dom/bindings/document.rs | 139 +++++++++++++++++ src/servo/dom/bindings/node.rs | 143 ++++++++++++++++++ src/servo/dom/bindings/utils.rs | 77 ++++++++++ src/servo/parser/html_builder.rs | 69 ++++++++- src/servo/servo.rc | 5 + src/servo/text/font.rs | 8 +- .../text/native_font/quartz_native_font.rs | 4 +- src/servo/text/shaper.rs | 4 +- src/test/test-js.html | 7 + src/test/test_docelem.js | 10 ++ 16 files changed, 501 insertions(+), 22 deletions(-) create mode 100644 src/servo/dom/bindings/document.rs create mode 100644 src/servo/dom/bindings/node.rs create mode 100644 src/servo/dom/bindings/utils.rs create mode 100644 src/test/test-js.html create mode 100644 src/test/test_docelem.js diff --git a/Makefile.in b/Makefile.in index 8fcb0ffc97af..60ba7411e97b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -87,6 +87,7 @@ CLEAN_DEPS += \ clean-ragel \ clean-harfbuzz \ clean-rust-harfbuzz \ + clean-mozjs \ clean-rust-mozjs \ clean-rust-sdl \ clean-rust-azure \ @@ -213,6 +214,10 @@ clean-harfbuzz: clean-rust-harfbuzz: $(MAKE) clean -C src/rust-harfbuzz +.PHONY: clean-mozjs +clean-mozjs: + $(MAKE) clean -C src/mozjs + .PHONY: clean-rust-mozjs clean-rust-mozjs: $(MAKE) clean -C src/rust-mozjs diff --git a/configure.in b/configure.in index dc6c997be9d3..24911354be79 100755 --- a/configure.in +++ b/configure.in @@ -19,7 +19,7 @@ mkdir -p src/rust-layers || exit $? (cd src/ragel && sh ${SRCDIR}/src/ragel/configure) || 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-harfbuzz && sh ${SRCDIR}/src/rust-harfbuzz/configure) || exit $? (cd src/rust-mozjs && sh ${SRCDIR}/src/rust-mozjs/configure) || exit $? diff --git a/src/rust-mozjs b/src/rust-mozjs index 8e60882ebf2c..9dca4b316e36 160000 --- a/src/rust-mozjs +++ b/src/rust-mozjs @@ -1 +1 @@ -Subproject commit 8e60882ebf2c68766747b1d673a94c77b75f2b78 +Subproject commit 9dca4b316e36c85f8b165b32c87e0a74635f61ac diff --git a/src/rust-sdl b/src/rust-sdl index 0f3d130e46b1..af4cb2481c60 160000 --- a/src/rust-sdl +++ b/src/rust-sdl @@ -1 +1 @@ -Subproject commit 0f3d130e46b1314f1c98b99ce91f443805a9efa6 +Subproject commit af4cb2481c60688d6b10dd8d5e2ffd6842a28384 diff --git a/src/servo/content.rs b/src/servo/content.rs index 72200e804da8..82e163c15b8c 100644 --- a/src/servo/content.rs +++ b/src/servo/content.rs @@ -7,13 +7,14 @@ export Content; export ControlMsg, ExecuteMsg, ParseMsg, ExitMsg; export PingMsg, PongMsg; export create_content; +export Document; import comm::{port, chan, listen, select2}; import task::{spawn, spawn_listener}; import io::{read_whole_file, println}; import result::{ok, err}; -import dom::base::{Node, NodeScope}; +import dom::base::{Node, NodeScope, define_bindings}; import dom::event::{Event, ResizeEvent}; import dom::rcu::WriterMethods; import dom::style; @@ -31,6 +32,9 @@ import js::global::{global_class, debug_fns}; import either::{either, left, right}; import result::extensions; +import dom::bindings::utils::rust_box; +import js::rust::compartment; + type Content = chan; enum ControlMsg { @@ -75,7 +79,7 @@ class Content { let scope: NodeScope; let jsrt: jsrt; - let mut document: option; + let mut document: option<@Document>; new(layout: Layout, sink: S, from_master: port) { self.layout = layout; @@ -116,15 +120,31 @@ class Content { // Note: we can parse the next document in parallel // with any previous documents. 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 js_scripts = js_port.recv(); // Apply the css rules to the dom tree: #debug["%?", css_rules]; + #debug["%?", js_scripts]; + let document = Document(root, css_rules); 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; } @@ -181,7 +201,7 @@ class Content { // Nothing to do. } some(document) { - self.relayout(document); + self.relayout(*document); } } ret true; diff --git a/src/servo/dom/base.rs b/src/servo/dom/base.rs index b5955e87672a..36fe1f8501a2 100644 --- a/src/servo/dom/base.rs +++ b/src/servo/dom/base.rs @@ -5,6 +5,14 @@ import gfx::geometry::au; import geom::size::Size2D; import layout::base::LayoutData; 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}; @@ -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 { UnknownElement, HTMLDivElement, HTMLHeadElement, - HTMLImageElement({mut size: Size2D}) + HTMLImageElement({mut size: Size2D}), + HTMLScriptElement } #[doc=" diff --git a/src/servo/dom/bindings/document.rs b/src/servo/dom/bindings/document.rs new file mode 100644 index 000000000000..5f8d91d3f89d --- /dev/null +++ b/src/servo/dom/bindings/document.rs @@ -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 { + 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); +} diff --git a/src/servo/dom/bindings/node.rs b/src/servo/dom/bindings/node.rs new file mode 100644 index 000000000000..7c5d705b329b --- /dev/null +++ b/src/servo/dom/bindings/node.rs @@ -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 { + 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; +} diff --git a/src/servo/dom/bindings/utils.rs b/src/servo/dom/bindings/utils.rs new file mode 100644 index 000000000000..00b49f90ee03 --- /dev/null +++ b/src/servo/dom/bindings/utils.rs @@ -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 = {rc: uint, td: *sys::type_desc, next: *(), prev: *(), payload: T}; + +unsafe fn squirrel_away(+x: @T) -> *rust_box { + let y: *rust_box = unsafe::reinterpret_cast(x); + unsafe::forget(x); + y +} + +type rust_unique = {payload: T}; + +unsafe fn squirrel_away_unique(+x: ~T) -> *rust_box { + let y: *rust_box = 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 + } +} diff --git a/src/servo/parser/html_builder.rs b/src/servo/parser/html_builder.rs index c96bc17f593f..189952ccde62 100644 --- a/src/servo/parser/html_builder.rs +++ b/src/servo/parser/html_builder.rs @@ -1,6 +1,7 @@ #[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::{UnknownElement}; import dom::rcu::WriterMethods; @@ -19,6 +20,11 @@ enum CSSMessage { Exit } +enum js_message { + js_file(~str), + js_exit +} + #[warn(no_non_implicitly_copyable_typarams)] fn link_up_attribute(scope: NodeScope, node: Node, -key: ~str, -value: ~str) { // 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. } } @@ -67,6 +74,7 @@ fn build_element_kind(tag_name: ~str) -> ~ElementKind { geometry::px_to_au(100)) }) } + ~"script" { ~HTMLScriptElement } ~"head" { ~HTMLHeadElement } _ { ~UnknownElement } } @@ -116,8 +124,38 @@ fn css_link_listener(to_parent : chan, from_parent : port, from_parent : port) { + 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)] -fn build_dom(scope: NodeScope, stream: port) -> (Node, port) { +fn build_dom(scope: NodeScope, stream: port) -> (Node, port, port<~[~[u8]]>) { // The current reference node. let mut cur_node = scope.new_node(Element(ElementData(~"html", ~HTMLDivElement))); // We will spawn a separate task to parse any css that is @@ -131,6 +169,12 @@ fn build_dom(scope: NodeScope, stream: port) -> (Node, 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 { let token = stream.recv(); alt token { @@ -174,8 +218,22 @@ fn build_dom(scope: NodeScope, stream: port) -> (Node, port) }); cur_node = scope.get_parent(cur_node).get(); } - parser::EndTag(_) { + parser::EndTag(tag_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(); } parser::Text(s) if !s.is_whitespace() { @@ -192,6 +250,7 @@ fn build_dom(scope: NodeScope, stream: port) -> (Node, port) } style_chan.send(Exit); + js_chan.send(js_exit); - ret (cur_node, style_port); + ret (cur_node, style_port, js_port); } diff --git a/src/servo/servo.rc b/src/servo/servo.rc index 223bf9b7ccff..144cf8942979 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -22,6 +22,11 @@ mod dom { mod event; mod rcu; mod style; + mod bindings { + mod document; + mod utils; + mod node; + } } mod gfx { diff --git a/src/servo/text/font.rs b/src/servo/text/font.rs index 53dd1879fd17..e0304041c93c 100644 --- a/src/servo/text/font.rs +++ b/src/servo/text/font.rs @@ -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() }; let face: FT_Face = null(); - vec::as_buf(*buf, |cbuf| { - if FT_New_Memory_Face(library, cbuf, (*buf).len() as FT_Long, + vec::as_buf(*buf, |cbuf, len| { + if FT_New_Memory_Face(library, cbuf, len as FT_Long, 0 as FT_Long, addr_of(face)).failed() { dtor(); 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 fontprov = vec::as_buf(*buf, |cbuf| { + let fontprov = vec::as_buf(*buf, |cbuf, len| { CGDataProviderCreateWithData( null(), unsafe { reinterpret_cast(cbuf) }, - (*buf).len() as size_t, + len as size_t, null() ) }); diff --git a/src/servo/text/native_font/quartz_native_font.rs b/src/servo/text/native_font/quartz_native_font.rs index 4f80e4131519..a4adf5eb6bbe 100644 --- a/src/servo/text/native_font/quartz_native_font.rs +++ b/src/servo/text/native_font/quartz_native_font.rs @@ -49,11 +49,11 @@ class QuartzNativeFont/& { } fn create(buf: ~[u8]) -> result { - let fontprov = vec::as_buf(buf, |cbuf| { + let fontprov = vec::as_buf(buf, |cbuf, len| { CGDataProviderCreateWithData( null(), unsafe { reinterpret_cast(cbuf) }, - buf.len() as size_t, + len as size_t, null()) }); // FIXME: Error handling diff --git a/src/servo/text/shaper.rs b/src/servo/text/shaper.rs index 5a2bd426df9c..72277b4e9e21 100644 --- a/src/servo/text/shaper.rs +++ b/src/servo/text/shaper.rs @@ -38,9 +38,9 @@ when rendered in a specific font. fn shape_text(font: &Font, text: ~str) -> ~[Glyph] unsafe { #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), - (*(*font).buf()).len() as c_uint, + len as c_uint, HB_MEMORY_MODE_READONLY, null(), null()) diff --git a/src/test/test-js.html b/src/test/test-js.html new file mode 100644 index 000000000000..41617b9ca5a1 --- /dev/null +++ b/src/test/test-js.html @@ -0,0 +1,7 @@ +
+ +
+ +
+
+ diff --git a/src/test/test_docelem.js b/src/test/test_docelem.js new file mode 100644 index 000000000000..caa7058db316 --- /dev/null +++ b/src/test/test_docelem.js @@ -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); \ No newline at end of file