mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Add window.setTimeout. Convert all content node bindings to use RCU write pointer. Store a bundle of Node + NodeScope in each node JS object.
This commit is contained in:
parent
d4b2810af1
commit
4db345c3b3
9 changed files with 184 additions and 54 deletions
|
@ -4,7 +4,7 @@
|
||||||
"]
|
"]
|
||||||
|
|
||||||
export ContentTask;
|
export ContentTask;
|
||||||
export ControlMsg, ExecuteMsg, ParseMsg, ExitMsg;
|
export ControlMsg, ExecuteMsg, ParseMsg, ExitMsg, Timer;
|
||||||
export PingMsg, PongMsg;
|
export PingMsg, PongMsg;
|
||||||
|
|
||||||
import std::arc::{arc, clone};
|
import std::arc::{arc, clone};
|
||||||
|
@ -24,7 +24,7 @@ import layout::layout_task;
|
||||||
import layout_task::{LayoutTask, BuildMsg};
|
import layout_task::{LayoutTask, BuildMsg};
|
||||||
|
|
||||||
import jsrt = js::rust::rt;
|
import jsrt = js::rust::rt;
|
||||||
import js::rust::methods;
|
import js::rust::{cx, methods};
|
||||||
import js::global::{global_class, debug_fns};
|
import js::global::{global_class, debug_fns};
|
||||||
|
|
||||||
import either::{Either, Left, Right};
|
import either::{Either, Left, Right};
|
||||||
|
@ -40,9 +40,16 @@ import url_to_str = std::net::url::to_str;
|
||||||
import util::url::make_url;
|
import util::url::make_url;
|
||||||
import task::{task, SingleThreaded};
|
import task::{task, SingleThreaded};
|
||||||
|
|
||||||
|
import js::glue::bindgen::RUST_JSVAL_TO_OBJECT;
|
||||||
|
import js::JSVAL_NULL;
|
||||||
|
import js::jsapi::jsval;
|
||||||
|
import js::jsapi::bindgen::JS_CallFunctionValue;
|
||||||
|
import ptr::null;
|
||||||
|
|
||||||
enum ControlMsg {
|
enum ControlMsg {
|
||||||
ParseMsg(url),
|
ParseMsg(url),
|
||||||
ExecuteMsg(url),
|
ExecuteMsg(url),
|
||||||
|
Timer(~dom::bindings::window::TimerData),
|
||||||
ExitMsg
|
ExitMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +86,7 @@ struct Content<C:Compositor> {
|
||||||
|
|
||||||
let scope: NodeScope;
|
let scope: NodeScope;
|
||||||
let jsrt: jsrt;
|
let jsrt: jsrt;
|
||||||
|
let cx: cx;
|
||||||
|
|
||||||
let mut document: option<@Document>;
|
let mut document: option<@Document>;
|
||||||
let mut window: option<@Window>;
|
let mut window: option<@Window>;
|
||||||
|
@ -86,6 +94,8 @@ struct Content<C:Compositor> {
|
||||||
|
|
||||||
let resource_task: ResourceTask;
|
let resource_task: ResourceTask;
|
||||||
|
|
||||||
|
let compartment: option<compartment>;
|
||||||
|
|
||||||
new(layout_task: LayoutTask, +compositor: C, from_master: Port<ControlMsg>,
|
new(layout_task: LayoutTask, +compositor: C, from_master: Port<ControlMsg>,
|
||||||
resource_task: ResourceTask) {
|
resource_task: ResourceTask) {
|
||||||
self.layout_task = layout_task;
|
self.layout_task = layout_task;
|
||||||
|
@ -95,6 +105,7 @@ struct Content<C:Compositor> {
|
||||||
|
|
||||||
self.scope = NodeScope();
|
self.scope = NodeScope();
|
||||||
self.jsrt = jsrt();
|
self.jsrt = jsrt();
|
||||||
|
self.cx = self.jsrt.cx();
|
||||||
|
|
||||||
self.document = none;
|
self.document = none;
|
||||||
self.window = none;
|
self.window = none;
|
||||||
|
@ -103,6 +114,13 @@ struct Content<C:Compositor> {
|
||||||
self.compositor.add_event_listener(self.event_port.chan());
|
self.compositor.add_event_listener(self.event_port.chan());
|
||||||
|
|
||||||
self.resource_task = resource_task;
|
self.resource_task = resource_task;
|
||||||
|
|
||||||
|
self.cx.set_default_options_and_version();
|
||||||
|
self.cx.set_logging_error_reporter();
|
||||||
|
self.compartment = match self.cx.new_compartment(global_class) {
|
||||||
|
ok(c) => some(c),
|
||||||
|
err(()) => none
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start() {
|
fn start() {
|
||||||
|
@ -140,30 +158,42 @@ struct Content<C:Compositor> {
|
||||||
|
|
||||||
#debug["js_scripts: %?", js_scripts];
|
#debug["js_scripts: %?", js_scripts];
|
||||||
|
|
||||||
let document = Document(root, css_rules);
|
let document = Document(root, self.scope, css_rules);
|
||||||
let window = Window();
|
let window = Window(self.from_master);
|
||||||
self.relayout(document, &url);
|
self.relayout(document, &url);
|
||||||
self.document = some(@document);
|
self.document = some(@document);
|
||||||
self.window = some(@window);
|
self.window = some(@window);
|
||||||
self.doc_url = some(copy url);
|
self.doc_url = some(copy url);
|
||||||
|
|
||||||
//XXXjdm it was easier to duplicate the relevant ExecuteMsg code;
|
let compartment = option::expect(self.compartment, ~"TODO error checking");
|
||||||
// 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);
|
compartment.define_functions(debug_fns);
|
||||||
define_bindings(*compartment, option::get(self.document),
|
define_bindings(*compartment,
|
||||||
|
option::get(self.document),
|
||||||
option::get(self.window));
|
option::get(self.window));
|
||||||
cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u)
|
|
||||||
});
|
for vec::each(js_scripts) |bytes| {
|
||||||
|
self.cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer(timerData) => {
|
||||||
|
let compartment = option::expect(self.compartment, ~"TODO error checking");
|
||||||
|
let thisValue = if timerData.args.len() > 0 {
|
||||||
|
RUST_JSVAL_TO_OBJECT(unsafe { timerData.args.shift() })
|
||||||
|
} else {
|
||||||
|
compartment.global_obj.ptr
|
||||||
|
};
|
||||||
|
let _rval = JSVAL_NULL;
|
||||||
|
//TODO: support extra args. requires passing a *jsval argv
|
||||||
|
JS_CallFunctionValue(self.cx.ptr, thisValue, timerData.funval,
|
||||||
|
0, null(), ptr::addr_of(_rval));
|
||||||
|
self.relayout(*option::get(self.document), &option::get(self.doc_url));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ExecuteMsg(url) => {
|
ExecuteMsg(url) => {
|
||||||
#debug["content: Received url `%s` to execute", url_to_str(url)];
|
#debug["content: Received url `%s` to execute", url_to_str(url)];
|
||||||
|
|
||||||
|
@ -172,13 +202,9 @@ struct Content<C:Compositor> {
|
||||||
println(#fmt["Error opening %s: %s", url_to_str(url), msg]);
|
println(#fmt["Error opening %s: %s", url_to_str(url), msg]);
|
||||||
}
|
}
|
||||||
ok(bytes) => {
|
ok(bytes) => {
|
||||||
let cx = self.jsrt.cx();
|
let compartment = option::expect(self.compartment, ~"TODO error checking");
|
||||||
cx.set_default_options_and_version();
|
|
||||||
cx.set_logging_error_reporter();
|
|
||||||
cx.new_compartment(global_class).chain(|compartment| {
|
|
||||||
compartment.define_functions(debug_fns);
|
compartment.define_functions(debug_fns);
|
||||||
cx.evaluate_script(compartment.global_obj, bytes, url.path, 1u)
|
self.cx.evaluate_script(compartment.global_obj, bytes, url.path, 1u);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -14,20 +14,44 @@ import ptr::null;
|
||||||
import bindings;
|
import bindings;
|
||||||
import std::arc::arc;
|
import std::arc::arc;
|
||||||
import style::Stylesheet;
|
import style::Stylesheet;
|
||||||
|
import comm::{Port, Chan};
|
||||||
|
import content::content_task::{ControlMsg, Timer};
|
||||||
|
|
||||||
|
enum TimerControlMsg {
|
||||||
|
Fire(~dom::bindings::window::TimerData),
|
||||||
|
Close
|
||||||
|
}
|
||||||
|
|
||||||
struct Window {
|
struct Window {
|
||||||
let unused: int;
|
let timer_chan: Chan<TimerControlMsg>;
|
||||||
new() {
|
|
||||||
self.unused = 0;
|
new(content_port: Port<ControlMsg>) {
|
||||||
|
let content_chan = chan(content_port);
|
||||||
|
|
||||||
|
self.timer_chan = do task::spawn_listener |timer_port: Port<TimerControlMsg>| {
|
||||||
|
loop {
|
||||||
|
match timer_port.recv() {
|
||||||
|
Close => break,
|
||||||
|
Fire(td) => {
|
||||||
|
content_chan.send(Timer(td));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
drop {
|
||||||
|
self.timer_chan.send(Close);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Document {
|
struct Document {
|
||||||
let root: Node;
|
let root: Node;
|
||||||
|
let scope: NodeScope;
|
||||||
let css_rules: arc<Stylesheet>;
|
let css_rules: arc<Stylesheet>;
|
||||||
|
|
||||||
new(root: Node, -css_rules: Stylesheet) {
|
new(root: Node, scope: NodeScope, -css_rules: Stylesheet) {
|
||||||
self.root = root;
|
self.root = root;
|
||||||
|
self.scope = scope;
|
||||||
self.css_rules = arc(css_rules);
|
self.css_rules = arc(css_rules);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,8 +61,10 @@ enum Element = int;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
extern fn getDocumentElement(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool unsafe {
|
extern fn getDocumentElement(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool unsafe {
|
||||||
let node = (*unwrap(obj)).payload.root;
|
let box = unwrap(obj);
|
||||||
*rval = RUST_OBJECT_TO_JSVAL(node::create(cx, node).ptr);
|
let node = (*box).payload.root;
|
||||||
|
let scope = (*box).payload.scope;
|
||||||
|
*rval = RUST_OBJECT_TO_JSVAL(node::create(cx, node, scope).ptr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@ import js::jsapi::bindgen::*;
|
||||||
import js::glue::bindgen::*;
|
import js::glue::bindgen::*;
|
||||||
import js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub};
|
import js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub};
|
||||||
|
|
||||||
import dom::base::{Node, Element};
|
import dom::base::{Node, NodeScope, Element};
|
||||||
|
import node::NodeBundle;
|
||||||
import utils::{rust_box, squirrel_away_unique, get_compartment, domstring_to_jsval, str};
|
import utils::{rust_box, squirrel_away_unique, get_compartment, domstring_to_jsval, str};
|
||||||
import libc::c_uint;
|
import libc::c_uint;
|
||||||
import ptr::null;
|
import ptr::null;
|
||||||
|
@ -22,7 +23,7 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
#debug("element finalize!");
|
#debug("element finalize!");
|
||||||
unsafe {
|
unsafe {
|
||||||
let val = JS_GetReservedSlot(obj, 0);
|
let val = JS_GetReservedSlot(obj, 0);
|
||||||
let _node: ~Node = unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val));
|
let _node: ~NodeBundle = unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +63,8 @@ fn init(compartment: bare_compartment) {
|
||||||
|
|
||||||
extern fn HTMLImageElement_getWidth(_cx: *JSContext, obj: *JSObject, _id: jsid,
|
extern fn HTMLImageElement_getWidth(_cx: *JSContext, obj: *JSObject, _id: jsid,
|
||||||
rval: *mut jsval) -> JSBool unsafe {
|
rval: *mut jsval) -> JSBool unsafe {
|
||||||
let width = (*unwrap(obj)).payload.read(|nd| {
|
let bundle = unwrap(obj);
|
||||||
|
let width = (*bundle).payload.scope.write((*bundle).payload.node, |nd| {
|
||||||
match nd.kind {
|
match nd.kind {
|
||||||
~Element(ed) => {
|
~Element(ed) => {
|
||||||
match ed.kind {
|
match ed.kind {
|
||||||
|
@ -80,7 +82,8 @@ extern fn HTMLImageElement_getWidth(_cx: *JSContext, obj: *JSObject, _id: jsid,
|
||||||
|
|
||||||
extern fn HTMLImageElement_setWidth(_cx: *JSContext, obj: *JSObject, _id: jsid,
|
extern fn HTMLImageElement_setWidth(_cx: *JSContext, obj: *JSObject, _id: jsid,
|
||||||
_strict: JSBool, vp: *jsval) -> JSBool unsafe {
|
_strict: JSBool, vp: *jsval) -> JSBool unsafe {
|
||||||
let width = (*unwrap(obj)).payload.read(|nd| {
|
let bundle = unwrap(obj);
|
||||||
|
do (*bundle).payload.scope.write((*bundle).payload.node) |nd| {
|
||||||
match nd.kind {
|
match nd.kind {
|
||||||
~Element(ed) => {
|
~Element(ed) => {
|
||||||
match ed.kind {
|
match ed.kind {
|
||||||
|
@ -91,14 +94,15 @@ extern fn HTMLImageElement_setWidth(_cx: *JSContext, obj: *JSObject, _id: jsid,
|
||||||
}
|
}
|
||||||
_ => fail ~"why is this not an element?"
|
_ => fail ~"why is this not an element?"
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn getTagName(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval)
|
extern fn getTagName(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval)
|
||||||
-> JSBool {
|
-> JSBool {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*unwrap(obj)).payload.read(|nd| {
|
let bundle = unwrap(obj);
|
||||||
|
do (*bundle).payload.scope.write((*bundle).payload.node) |nd| {
|
||||||
match nd.kind {
|
match nd.kind {
|
||||||
~Element(ed) => {
|
~Element(ed) => {
|
||||||
let s = str(copy ed.tag_name);
|
let s = str(copy ed.tag_name);
|
||||||
|
@ -109,13 +113,13 @@ extern fn getTagName(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval
|
||||||
*rval = JSVAL_NULL;
|
*rval = JSVAL_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(cx: *JSContext, node: Node) -> jsobj unsafe {
|
fn create(cx: *JSContext, node: Node, scope: NodeScope) -> jsobj unsafe {
|
||||||
let proto = node.read(|nd| {
|
let proto = scope.write(node, |nd| {
|
||||||
match nd.kind {
|
match nd.kind {
|
||||||
~Element(ed) => {
|
~Element(ed) => {
|
||||||
match ed.kind {
|
match ed.kind {
|
||||||
|
@ -138,7 +142,8 @@ fn create(cx: *JSContext, node: Node) -> jsobj unsafe {
|
||||||
(*compartment).global_obj.ptr));
|
(*compartment).global_obj.ptr));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let raw_ptr: *libc::c_void = unsafe::reinterpret_cast(squirrel_away_unique(~node));
|
let raw_ptr: *libc::c_void =
|
||||||
|
unsafe::reinterpret_cast(squirrel_away_unique(~NodeBundle(node, scope)));
|
||||||
JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import js::jsapi::bindgen::*;
|
||||||
import js::glue::bindgen::*;
|
import js::glue::bindgen::*;
|
||||||
import js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub};
|
import js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub};
|
||||||
|
|
||||||
import dom::base::{Node, Element, Text};
|
import dom::base::{Node, NodeScope, Element, Text};
|
||||||
import utils::{rust_box, squirrel_away_unique, get_compartment, domstring_to_jsval, str};
|
import utils::{rust_box, squirrel_away_unique, get_compartment, domstring_to_jsval, str};
|
||||||
import libc::c_uint;
|
import libc::c_uint;
|
||||||
import ptr::null;
|
import ptr::null;
|
||||||
|
@ -35,11 +35,11 @@ fn init(compartment: bare_compartment) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(cx: *JSContext, node: Node) -> jsobj unsafe {
|
fn create(cx: *JSContext, node: Node, scope: NodeScope) -> jsobj unsafe {
|
||||||
do node.read |nd| {
|
do scope.write(node) |nd| {
|
||||||
match nd.kind {
|
match nd.kind {
|
||||||
~Element(ed) => {
|
~Element(ed) => {
|
||||||
element::create(cx, node)
|
element::create(cx, node, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
~Text(s) => {
|
~Text(s) => {
|
||||||
|
@ -49,41 +49,53 @@ fn create(cx: *JSContext, node: Node) -> jsobj unsafe {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unwrap(obj: *JSObject) -> *rust_box<Node> {
|
struct NodeBundle {
|
||||||
|
let node: Node;
|
||||||
|
let scope: NodeScope;
|
||||||
|
|
||||||
|
new(n: Node, s: NodeScope) {
|
||||||
|
self.node = n;
|
||||||
|
self.scope = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn unwrap(obj: *JSObject) -> *rust_box<NodeBundle> {
|
||||||
let val = JS_GetReservedSlot(obj, 0);
|
let val = JS_GetReservedSlot(obj, 0);
|
||||||
unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val))
|
unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn getFirstChild(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool {
|
extern fn getFirstChild(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*unwrap(obj)).payload.read(|nd| {
|
let bundle = unwrap(obj);
|
||||||
|
do (*bundle).payload.scope.write((*bundle).payload.node) |nd| {
|
||||||
match nd.tree.first_child {
|
match nd.tree.first_child {
|
||||||
some(n) => {
|
some(n) => {
|
||||||
let obj = create(cx, n).ptr;
|
let obj = create(cx, n, (*bundle).payload.scope).ptr;
|
||||||
*rval = RUST_OBJECT_TO_JSVAL(obj);
|
*rval = RUST_OBJECT_TO_JSVAL(obj);
|
||||||
}
|
}
|
||||||
none => {
|
none => {
|
||||||
*rval = JSVAL_NULL;
|
*rval = JSVAL_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn getNextSibling(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool {
|
extern fn getNextSibling(cx: *JSContext, obj: *JSObject, _id: jsid, rval: *mut jsval) -> JSBool {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*unwrap(obj)).payload.read(|nd| {
|
let bundle = unwrap(obj);
|
||||||
|
do (*bundle).payload.scope.write((*bundle).payload.node) |nd| {
|
||||||
match nd.tree.next_sibling {
|
match nd.tree.next_sibling {
|
||||||
some(n) => {
|
some(n) => {
|
||||||
let obj = create(cx, n).ptr;
|
let obj = create(cx, n, (*bundle).payload.scope).ptr;
|
||||||
*rval = RUST_OBJECT_TO_JSVAL(obj);
|
*rval = RUST_OBJECT_TO_JSVAL(obj);
|
||||||
}
|
}
|
||||||
none => {
|
none => {
|
||||||
*rval = JSVAL_NULL;
|
*rval = JSVAL_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import js::rust::{bare_compartment, methods};
|
import js::rust::{bare_compartment, methods};
|
||||||
import js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL, JS_THIS_OBJECT,
|
import js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL,
|
||||||
JS_SET_RVAL};
|
JS_THIS_OBJECT, JS_SET_RVAL};
|
||||||
import js::jsapi::{JSContext, jsval, JSObject, JSBool, jsid, JSClass, JSFreeOp};
|
import js::jsapi::{JSContext, jsval, JSObject, JSBool, jsid, JSClass, JSFreeOp};
|
||||||
import js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError,
|
import js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError,
|
||||||
JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN,
|
JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN,
|
||||||
|
@ -8,12 +8,14 @@ import js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_Re
|
||||||
import js::glue::bindgen::*;
|
import js::glue::bindgen::*;
|
||||||
import js::global::jsval_to_rust_str;
|
import js::global::jsval_to_rust_str;
|
||||||
import js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub, JS_ResolveStub};
|
import js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub, JS_ResolveStub};
|
||||||
|
import js::glue::bindgen::RUST_JSVAL_TO_INT;
|
||||||
import result::{result, ok, err};
|
import result::{result, ok, err};
|
||||||
import ptr::null;
|
import ptr::null;
|
||||||
import libc::c_uint;
|
import libc::c_uint;
|
||||||
import utils::{rust_box, squirrel_away, jsval_to_str};
|
import utils::{rust_box, squirrel_away, jsval_to_str};
|
||||||
import bindings::node::create;
|
import bindings::node::create;
|
||||||
import base::{Node, Window};
|
import base::{Node, Window};
|
||||||
|
import dvec::{DVec, dvec};
|
||||||
|
|
||||||
extern fn alert(cx: *JSContext, argc: c_uint, vp: *jsval) -> JSBool {
|
extern fn alert(cx: *JSContext, argc: c_uint, vp: *jsval) -> JSBool {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -28,6 +30,40 @@ extern fn alert(cx: *JSContext, argc: c_uint, vp: *jsval) -> JSBool {
|
||||||
1_i32
|
1_i32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Holder for the various JS values associated with setTimeout
|
||||||
|
// (ie. function value to invoke and all arguments to pass
|
||||||
|
// to the function when calling it)
|
||||||
|
struct TimerData {
|
||||||
|
let funval: jsval;
|
||||||
|
let args: DVec<jsval>;
|
||||||
|
new(argc: c_uint, argv: *jsval) unsafe {
|
||||||
|
self.funval = *argv;
|
||||||
|
self.args = dvec();
|
||||||
|
let mut i = 2;
|
||||||
|
while i < argc as uint {
|
||||||
|
self.args.push(*ptr::offset(argv, i));
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn setTimeout(cx: *JSContext, argc: c_uint, vp: *jsval) -> JSBool unsafe {
|
||||||
|
let argv = JS_ARGV(cx, vp);
|
||||||
|
assert (argc >= 2);
|
||||||
|
|
||||||
|
//TODO: don't crash when passed a non-integer value for the timeout
|
||||||
|
|
||||||
|
// Post a delayed message to the per-window timer task; it will dispatch it
|
||||||
|
// to the relevant content handler that will deal with it.
|
||||||
|
std::timer::delayed_send(std::uv_global_loop::get(),
|
||||||
|
RUST_JSVAL_TO_INT(*ptr::offset(argv, 1)) as uint,
|
||||||
|
(*unwrap(JS_THIS_OBJECT(cx, vp))).payload.timer_chan,
|
||||||
|
base::Fire(~TimerData(argc, argv)));
|
||||||
|
|
||||||
|
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn unwrap(obj: *JSObject) -> *rust_box<Window> {
|
unsafe fn unwrap(obj: *JSObject) -> *rust_box<Window> {
|
||||||
let val = JS_GetReservedSlot(obj, 0);
|
let val = JS_GetReservedSlot(obj, 0);
|
||||||
unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val))
|
unsafe::reinterpret_cast(RUST_JSVAL_TO_PRIVATE(val))
|
||||||
|
@ -53,6 +89,10 @@ fn init(compartment: bare_compartment, win: @Window) {
|
||||||
let methods = ~[{name: compartment.add_name(~"alert"),
|
let methods = ~[{name: compartment.add_name(~"alert"),
|
||||||
call: alert,
|
call: alert,
|
||||||
nargs: 1,
|
nargs: 1,
|
||||||
|
flags: 0},
|
||||||
|
{name: compartment.add_name(~"setTimeout"),
|
||||||
|
call: setTimeout,
|
||||||
|
nargs: 2,
|
||||||
flags: 0}];
|
flags: 0}];
|
||||||
|
|
||||||
vec::as_buf(methods, |fns, _len| {
|
vec::as_buf(methods, |fns, _len| {
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
|
function setWidth(w, i) {
|
||||||
|
var elem = document.documentElement.firstChild;
|
||||||
|
elem.width = w;
|
||||||
|
debug(elem.width);
|
||||||
|
w += i;
|
||||||
|
if (w == 0 || w == 1000)
|
||||||
|
i *= -1;
|
||||||
|
window.setTimeout(function() { setWidth(w, i); }, 50);
|
||||||
|
}
|
||||||
|
|
||||||
var elem = document.documentElement.firstChild;
|
var elem = document.documentElement.firstChild;
|
||||||
debug(elem.tagName);
|
debug(elem.tagName);
|
||||||
debug(elem instanceof HTMLImageElement);
|
debug(elem instanceof HTMLImageElement);
|
||||||
debug(elem.width);
|
debug(elem.width);
|
||||||
elem.width = 1000;
|
setWidth(1000, -10);
|
||||||
debug(elem.width);
|
|
1
src/test/test_timeout.html
Normal file
1
src/test/test_timeout.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<div></div><script src="test_timeout.js"></script>
|
11
src/test/test_timeout.js
Normal file
11
src/test/test_timeout.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
function foo(i) {
|
||||||
|
window.alert("timeout " + i);
|
||||||
|
if (i == 10)
|
||||||
|
window.alert("timeouts finished");
|
||||||
|
else
|
||||||
|
window.setTimeout(function() { foo(i + 1); }, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.alert("beginning timeouts");
|
||||||
|
window.setTimeout(function() { foo(0); }, 1000);
|
||||||
|
window.alert("timeouts begun");
|
Loading…
Add table
Add a link
Reference in a new issue