mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Make servo build again
This commit is contained in:
parent
56bf2aaafe
commit
00cd6f8909
50 changed files with 746 additions and 593 deletions
|
@ -7,14 +7,13 @@ export ContentTask;
|
||||||
export ControlMsg, ExecuteMsg, ParseMsg, ExitMsg, Timer;
|
export ControlMsg, ExecuteMsg, ParseMsg, ExitMsg, Timer;
|
||||||
export PingMsg, PongMsg;
|
export PingMsg, PongMsg;
|
||||||
|
|
||||||
import std::arc::{arc, clone};
|
import std::arc::{ARC, clone};
|
||||||
import comm::{Port, Chan, 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 dom::base::{Document, Node, NodeScope, Window, define_bindings};
|
import dom::base::{Document, Node, NodeScope, Window, define_bindings};
|
||||||
import dom::event::{Event, ResizeEvent};
|
import dom::event::{Event, ResizeEvent, ReflowEvent};
|
||||||
import dom::style;
|
import dom::style;
|
||||||
import dom::style::Stylesheet;
|
import dom::style::Stylesheet;
|
||||||
import gfx::compositor::Compositor;
|
import gfx::compositor::Compositor;
|
||||||
|
@ -88,28 +87,28 @@ struct Content<C:Compositor> {
|
||||||
let jsrt: jsrt;
|
let jsrt: jsrt;
|
||||||
let cx: cx;
|
let cx: cx;
|
||||||
|
|
||||||
let mut document: option<@Document>;
|
let mut document: Option<@Document>;
|
||||||
let mut window: option<@Window>;
|
let mut window: Option<@Window>;
|
||||||
let mut doc_url: option<url>;
|
let mut doc_url: Option<url>;
|
||||||
|
|
||||||
let resource_task: ResourceTask;
|
let resource_task: ResourceTask;
|
||||||
|
|
||||||
let compartment: option<compartment>;
|
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;
|
||||||
self.compositor = compositor;
|
self.compositor = compositor;
|
||||||
self.from_master = from_master;
|
self.from_master = from_master;
|
||||||
self.event_port = port();
|
self.event_port = Port();
|
||||||
|
|
||||||
self.scope = NodeScope();
|
self.scope = NodeScope();
|
||||||
self.jsrt = jsrt();
|
self.jsrt = jsrt();
|
||||||
self.cx = self.jsrt.cx();
|
self.cx = self.jsrt.cx();
|
||||||
|
|
||||||
self.document = none;
|
self.document = None;
|
||||||
self.window = none;
|
self.window = None;
|
||||||
self.doc_url = none;
|
self.doc_url = None;
|
||||||
|
|
||||||
self.compositor.add_event_listener(self.event_port.chan());
|
self.compositor.add_event_listener(self.event_port.chan());
|
||||||
|
|
||||||
|
@ -118,8 +117,8 @@ struct Content<C:Compositor> {
|
||||||
self.cx.set_default_options_and_version();
|
self.cx.set_default_options_and_version();
|
||||||
self.cx.set_logging_error_reporter();
|
self.cx.set_logging_error_reporter();
|
||||||
self.compartment = match self.cx.new_compartment(global_class) {
|
self.compartment = match self.cx.new_compartment(global_class) {
|
||||||
ok(c) => some(c),
|
Ok(c) => Some(c),
|
||||||
err(()) => none
|
Err(()) => None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,9 +165,9 @@ struct Content<C:Compositor> {
|
||||||
let document = Document(root, self.scope, css_rules);
|
let document = Document(root, self.scope, css_rules);
|
||||||
let window = Window(self.from_master);
|
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);
|
||||||
|
|
||||||
let compartment = option::expect(self.compartment, ~"TODO error checking");
|
let compartment = option::expect(self.compartment, ~"TODO error checking");
|
||||||
compartment.define_functions(debug_fns);
|
compartment.define_functions(debug_fns);
|
||||||
|
@ -202,11 +201,11 @@ struct Content<C:Compositor> {
|
||||||
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)];
|
||||||
|
|
||||||
match read_whole_file(url.path) {
|
match read_whole_file(&Path(url.path)) {
|
||||||
err(msg) => {
|
Err(msg) => {
|
||||||
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 compartment = option::expect(self.compartment, ~"TODO error checking");
|
let compartment = option::expect(self.compartment, ~"TODO error checking");
|
||||||
compartment.define_functions(debug_fns);
|
compartment.define_functions(debug_fns);
|
||||||
self.cx.evaluate_script(compartment.global_obj, bytes, url.path, 1u);
|
self.cx.evaluate_script(compartment.global_obj, bytes, url.path, 1u);
|
||||||
|
@ -243,10 +242,10 @@ struct Content<C:Compositor> {
|
||||||
ResizeEvent(new_width, new_height) => {
|
ResizeEvent(new_width, new_height) => {
|
||||||
#debug("content got resize event: %d, %d", new_width, new_height);
|
#debug("content got resize event: %d, %d", new_width, new_height);
|
||||||
match copy self.document {
|
match copy self.document {
|
||||||
none => {
|
None => {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
some(document) => {
|
Some(document) => {
|
||||||
assert self.doc_url.is_some();
|
assert self.doc_url.is_some();
|
||||||
self.relayout(*document, &self.doc_url.get());
|
self.relayout(*document, &self.doc_url.get());
|
||||||
}
|
}
|
||||||
|
@ -256,10 +255,10 @@ struct Content<C:Compositor> {
|
||||||
ReflowEvent => {
|
ReflowEvent => {
|
||||||
#debug("content got reflow event");
|
#debug("content got reflow event");
|
||||||
match copy self.document {
|
match copy self.document {
|
||||||
none => {
|
None => {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
some(document) => {
|
Some(document) => {
|
||||||
assert self.doc_url.is_some();
|
assert self.doc_url.is_some();
|
||||||
self.relayout(*document, &self.doc_url.get());
|
self.relayout(*document, &self.doc_url.get());
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@ import js::jsapi::{JSClass, JSObject, JSPropertySpec, JSContext, jsid, jsval, JS
|
||||||
import js::{JSPROP_ENUMERATE, JSPROP_SHARED};
|
import js::{JSPROP_ENUMERATE, JSPROP_SHARED};
|
||||||
import js::crust::*;
|
import js::crust::*;
|
||||||
import js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
|
import js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
|
||||||
import dvec::{DVec, dvec};
|
import dvec::DVec;
|
||||||
import ptr::null;
|
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 comm::{Port, Chan};
|
||||||
import content::content_task::{ControlMsg, Timer};
|
import content::content_task::{ControlMsg, Timer};
|
||||||
|
@ -26,7 +26,7 @@ struct Window {
|
||||||
let timer_chan: Chan<TimerControlMsg>;
|
let timer_chan: Chan<TimerControlMsg>;
|
||||||
|
|
||||||
new(content_port: Port<ControlMsg>) {
|
new(content_port: Port<ControlMsg>) {
|
||||||
let content_chan = chan(content_port);
|
let content_chan = Chan(content_port);
|
||||||
|
|
||||||
self.timer_chan = do task::spawn_listener |timer_port: Port<TimerControlMsg>| {
|
self.timer_chan = do task::spawn_listener |timer_port: Port<TimerControlMsg>| {
|
||||||
loop {
|
loop {
|
||||||
|
@ -47,12 +47,12 @@ struct Window {
|
||||||
struct Document {
|
struct Document {
|
||||||
let root: Node;
|
let root: Node;
|
||||||
let scope: NodeScope;
|
let scope: NodeScope;
|
||||||
let css_rules: arc<Stylesheet>;
|
let css_rules: ARC<Stylesheet>;
|
||||||
|
|
||||||
new(root: Node, scope: NodeScope, -css_rules: Stylesheet) {
|
new(root: Node, scope: NodeScope, -css_rules: Stylesheet) {
|
||||||
self.root = root;
|
self.root = root;
|
||||||
self.scope = scope;
|
self.scope = scope;
|
||||||
self.css_rules = arc(css_rules);
|
self.css_rules = ARC(css_rules);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,19 +74,19 @@ struct ElementData {
|
||||||
new(-tag_name: ~str, -kind: ~ElementKind) {
|
new(-tag_name: ~str, -kind: ~ElementKind) {
|
||||||
self.tag_name = tag_name;
|
self.tag_name = tag_name;
|
||||||
self.kind = kind;
|
self.kind = kind;
|
||||||
self.attrs = dvec();
|
self.attrs = DVec();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_attr(attr_name: ~str) -> option<~str> {
|
fn get_attr(attr_name: ~str) -> Option<~str> {
|
||||||
let mut i = 0u;
|
let mut i = 0u;
|
||||||
while i < self.attrs.len() {
|
while i < self.attrs.len() {
|
||||||
if attr_name == self.attrs[i].name {
|
if attr_name == self.attrs[i].name {
|
||||||
return some(copy self.attrs[i].value);
|
return Some(copy self.attrs[i].value);
|
||||||
}
|
}
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
none
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ impl NodeScope : tree::ReadMethods<Node> {
|
||||||
tree::each_child(self, node, f)
|
tree::each_child(self, node, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_parent(node: Node) -> option<Node> {
|
fn get_parent(node: Node) -> Option<Node> {
|
||||||
tree::get_parent(self, node)
|
tree::get_parent(self, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,11 @@ import js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_Re
|
||||||
import js::glue::bindgen::*;
|
import js::glue::bindgen::*;
|
||||||
import js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB};
|
import js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB};
|
||||||
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 result::{result, ok, err};
|
|
||||||
import ptr::null;
|
import ptr::null;
|
||||||
import libc::c_uint;
|
import libc::c_uint;
|
||||||
import utils::{DOMString, domstring_to_jsval, rust_box, squirrel_away, str};
|
import utils::{DOMString, domstring_to_jsval, rust_box, squirrel_away, str};
|
||||||
import bindings::node::create;
|
import bindings::node::create;
|
||||||
import base::Document;
|
import base::Document;
|
||||||
import option::{some, none};
|
|
||||||
|
|
||||||
enum DOMException {
|
enum DOMException {
|
||||||
INVALID_CHARACTER_ERR
|
INVALID_CHARACTER_ERR
|
||||||
|
@ -90,7 +88,7 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(compartment: bare_compartment, doc: @Document) {
|
fn init(compartment: bare_compartment, doc: @Document) {
|
||||||
let obj = utils::define_empty_prototype(~"Document", none, compartment);
|
let obj = utils::define_empty_prototype(~"Document", None, compartment);
|
||||||
|
|
||||||
let attrs = @~[
|
let attrs = @~[
|
||||||
{name: compartment.add_name(~"documentElement"),
|
{name: compartment.add_name(~"documentElement"),
|
||||||
|
|
|
@ -28,7 +28,7 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(compartment: bare_compartment) {
|
fn init(compartment: bare_compartment) {
|
||||||
let obj = utils::define_empty_prototype(~"Element", some(~"Node"), compartment);
|
let obj = utils::define_empty_prototype(~"Element", Some(~"Node"), compartment);
|
||||||
let attrs = @~[
|
let attrs = @~[
|
||||||
{name: compartment.add_name(~"tagName"),
|
{name: compartment.add_name(~"tagName"),
|
||||||
tinyid: 0,
|
tinyid: 0,
|
||||||
|
@ -43,12 +43,12 @@ fn init(compartment: bare_compartment) {
|
||||||
compartment.register_class(utils::instance_jsclass(~"GenericElementInstance",
|
compartment.register_class(utils::instance_jsclass(~"GenericElementInstance",
|
||||||
finalize));
|
finalize));
|
||||||
|
|
||||||
let _ = utils::define_empty_prototype(~"HTMLElement", some(~"Element"), compartment);
|
let _ = utils::define_empty_prototype(~"HTMLElement", Some(~"Element"), compartment);
|
||||||
let _ = utils::define_empty_prototype(~"HTMLDivElement", some(~"HTMLElement"), compartment);
|
let _ = utils::define_empty_prototype(~"HTMLDivElement", Some(~"HTMLElement"), compartment);
|
||||||
let _ = utils::define_empty_prototype(~"HTMLScriptElement", some(~"HTMLElement"), compartment);
|
let _ = utils::define_empty_prototype(~"HTMLScriptElement", Some(~"HTMLElement"), compartment);
|
||||||
let _ = utils::define_empty_prototype(~"HTMLHeadElement", some(~"HTMLElement"), compartment);
|
let _ = utils::define_empty_prototype(~"HTMLHeadElement", Some(~"HTMLElement"), compartment);
|
||||||
|
|
||||||
let obj = utils::define_empty_prototype(~"HTMLImageElement", some(~"HTMLElement"), compartment);
|
let obj = utils::define_empty_prototype(~"HTMLImageElement", Some(~"HTMLElement"), compartment);
|
||||||
let attrs = @~[
|
let attrs = @~[
|
||||||
{name: compartment.add_name(~"width"),
|
{name: compartment.add_name(~"width"),
|
||||||
tinyid: 0,
|
tinyid: 0,
|
||||||
|
|
|
@ -15,7 +15,7 @@ import libc::c_uint;
|
||||||
import ptr::null;
|
import ptr::null;
|
||||||
|
|
||||||
fn init(compartment: bare_compartment) {
|
fn init(compartment: bare_compartment) {
|
||||||
let obj = utils::define_empty_prototype(~"Node", none, compartment);
|
let obj = utils::define_empty_prototype(~"Node", None, compartment);
|
||||||
|
|
||||||
let attrs = @~[
|
let attrs = @~[
|
||||||
{name: compartment.add_name(~"firstChild"),
|
{name: compartment.add_name(~"firstChild"),
|
||||||
|
@ -44,11 +44,11 @@ fn init(compartment: bare_compartment) {
|
||||||
fn create(cx: *JSContext, node: Node, scope: NodeScope) -> jsobj unsafe {
|
fn create(cx: *JSContext, node: Node, scope: NodeScope) -> jsobj unsafe {
|
||||||
do scope.write(node) |nd| {
|
do scope.write(node) |nd| {
|
||||||
match nd.kind {
|
match nd.kind {
|
||||||
~Element(ed) => {
|
~Element(*) => {
|
||||||
element::create(cx, node, scope)
|
element::create(cx, node, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
~Text(s) => {
|
~Text(*) => {
|
||||||
fail ~"no text node bindings yet";
|
fail ~"no text node bindings yet";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,11 +80,11 @@ extern fn getFirstChild(cx: *JSContext, _argc: c_uint, vp: *mut jsval) -> JSBool
|
||||||
let bundle = unwrap(obj);
|
let bundle = unwrap(obj);
|
||||||
do (*bundle).payload.scope.write((*bundle).payload.node) |nd| {
|
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, (*bundle).payload.scope).ptr;
|
let obj = create(cx, n, (*bundle).payload.scope).ptr;
|
||||||
*vp = RUST_OBJECT_TO_JSVAL(obj);
|
*vp = RUST_OBJECT_TO_JSVAL(obj);
|
||||||
}
|
}
|
||||||
none => {
|
None => {
|
||||||
*vp = JSVAL_NULL;
|
*vp = JSVAL_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,11 +103,11 @@ extern fn getNextSibling(cx: *JSContext, _argc: c_uint, vp: *mut jsval) -> JSBoo
|
||||||
let bundle = unwrap(obj);
|
let bundle = unwrap(obj);
|
||||||
do (*bundle).payload.scope.write((*bundle).payload.node) |nd| {
|
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, (*bundle).payload.scope).ptr;
|
let obj = create(cx, n, (*bundle).payload.scope).ptr;
|
||||||
*vp = RUST_OBJECT_TO_JSVAL(obj);
|
*vp = RUST_OBJECT_TO_JSVAL(obj);
|
||||||
}
|
}
|
||||||
none => {
|
None => {
|
||||||
*vp = JSVAL_NULL;
|
*vp = JSVAL_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_S
|
||||||
RESOLVE_STUB};
|
RESOLVE_STUB};
|
||||||
import js::glue::bindgen::*;
|
import js::glue::bindgen::*;
|
||||||
import ptr::null;
|
import ptr::null;
|
||||||
import result::{result, ok, err};
|
|
||||||
|
|
||||||
enum DOMString {
|
enum DOMString {
|
||||||
str(~str),
|
str(~str),
|
||||||
|
@ -34,25 +33,25 @@ unsafe fn squirrel_away_unique<T>(+x: ~T) -> *rust_box<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
//XXX very incomplete
|
//XXX very incomplete
|
||||||
fn jsval_to_str(cx: *JSContext, v: jsval) -> result<~str, ()> {
|
fn jsval_to_str(cx: *JSContext, v: jsval) -> Result<~str, ()> {
|
||||||
let jsstr;
|
let jsstr;
|
||||||
if RUST_JSVAL_IS_STRING(v) == 1 {
|
if RUST_JSVAL_IS_STRING(v) == 1 {
|
||||||
jsstr = RUST_JSVAL_TO_STRING(v)
|
jsstr = RUST_JSVAL_TO_STRING(v)
|
||||||
} else {
|
} else {
|
||||||
jsstr = JS_ValueToString(cx, v);
|
jsstr = JS_ValueToString(cx, v);
|
||||||
if jsstr.is_null() {
|
if jsstr.is_null() {
|
||||||
return err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let len = 0;
|
let len = 0;
|
||||||
let chars = JS_GetStringCharsZAndLength(cx, jsstr, ptr::addr_of(len));
|
let chars = JS_GetStringCharsZAndLength(cx, jsstr, ptr::addr_of(len));
|
||||||
return if chars.is_null() {
|
return if chars.is_null() {
|
||||||
err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
let buf = vec::unsafe::from_buf(chars as *u8, len as uint);
|
let buf = vec::unsafe::from_buf(chars as *u8, len as uint);
|
||||||
ok(str::from_bytes(buf))
|
Ok(str::from_bytes(buf))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,16 +151,16 @@ fn instance_jsclass(name: ~str, finalize: *u8)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_empty_prototype(name: ~str, proto: option<~str>, compartment: bare_compartment)
|
fn define_empty_prototype(name: ~str, proto: Option<~str>, compartment: bare_compartment)
|
||||||
-> js::rust::jsobj {
|
-> js::rust::jsobj {
|
||||||
compartment.register_class(utils::prototype_jsclass(name));
|
compartment.register_class(utils::prototype_jsclass(name));
|
||||||
|
|
||||||
//TODO error checking
|
//TODO error checking
|
||||||
let obj = result::unwrap(
|
let obj = result::unwrap(
|
||||||
match proto {
|
match proto {
|
||||||
some(s) => compartment.new_object_with_proto(name, s,
|
Some(s) => compartment.new_object_with_proto(name, s,
|
||||||
compartment.global_obj.ptr),
|
compartment.global_obj.ptr),
|
||||||
none => compartment.new_object(name, null(), compartment.global_obj.ptr)
|
None => compartment.new_object(name, null(), compartment.global_obj.ptr)
|
||||||
});
|
});
|
||||||
|
|
||||||
compartment.define_property(name, RUST_OBJECT_TO_JSVAL(obj.ptr),
|
compartment.define_property(name, RUST_OBJECT_TO_JSVAL(obj.ptr),
|
||||||
|
|
|
@ -9,13 +9,12 @@ 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 js::glue::bindgen::RUST_JSVAL_TO_INT;
|
||||||
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};
|
import 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 {
|
||||||
|
@ -38,7 +37,7 @@ struct TimerData {
|
||||||
let args: DVec<jsval>;
|
let args: DVec<jsval>;
|
||||||
new(argc: c_uint, argv: *jsval) unsafe {
|
new(argc: c_uint, argv: *jsval) unsafe {
|
||||||
self.funval = *argv;
|
self.funval = *argv;
|
||||||
self.args = dvec();
|
self.args = DVec();
|
||||||
let mut i = 2;
|
let mut i = 2;
|
||||||
while i < argc as uint {
|
while i < argc as uint {
|
||||||
self.args.push(*ptr::offset(argv, i));
|
self.args.push(*ptr::offset(argv, i));
|
||||||
|
@ -78,7 +77,7 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(compartment: bare_compartment, win: @Window) {
|
fn init(compartment: bare_compartment, win: @Window) {
|
||||||
let proto = utils::define_empty_prototype(~"Window", none, compartment);
|
let proto = utils::define_empty_prototype(~"Window", None, compartment);
|
||||||
compartment.register_class(utils::instance_jsclass(~"WindowInstance", finalize));
|
compartment.register_class(utils::instance_jsclass(~"WindowInstance", finalize));
|
||||||
|
|
||||||
let obj = result::unwrap(
|
let obj = result::unwrap(
|
||||||
|
|
|
@ -201,7 +201,9 @@ impl<T:copy send,A> Scope<T,A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<U>(h: Handle<T,A>, f: fn(T) -> U) -> U unsafe {
|
fn write<U>(h: Handle<T,A>, f: fn(T) -> U) -> U unsafe {
|
||||||
if self.d.layout_active && h.read_ptr() == h.write_ptr() {
|
let const_read_ptr = ptr::const_offset(h.read_ptr(), 0);
|
||||||
|
let const_write_ptr = ptr::const_offset(h.write_ptr(), 0);
|
||||||
|
if self.d.layout_active && const_read_ptr == const_write_ptr {
|
||||||
#debug["marking handle %? as dirty", h];
|
#debug["marking handle %? as dirty", h];
|
||||||
h.set_write_ptr(unsafe::reinterpret_cast(self.clone(h.read_ptr())));
|
h.set_write_ptr(unsafe::reinterpret_cast(self.clone(h.read_ptr())));
|
||||||
h.set_next_dirty(self.d.first_dirty);
|
h.set_next_dirty(self.d.first_dirty);
|
||||||
|
@ -273,8 +275,8 @@ mod test {
|
||||||
|
|
||||||
let iter1 = 3u;
|
let iter1 = 3u;
|
||||||
let iter2 = 22u;
|
let iter2 = 22u;
|
||||||
let read_port = comm::port();
|
let read_port = comm::Port();
|
||||||
let read_chan = comm::chan(read_port);
|
let read_chan = comm::Chan(read_port);
|
||||||
|
|
||||||
// fire up a reader task
|
// fire up a reader task
|
||||||
for uint::range(0u, iter1) |i| {
|
for uint::range(0u, iter1) |i| {
|
||||||
|
|
|
@ -62,3 +62,83 @@ pure fn PtToPx(u : Unit) -> Unit {
|
||||||
_ => fail ~"Calling PtToPx on a unit that is not a Pt"
|
_ => fail ~"Calling PtToPx on a unit that is not a Pt"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DisplayType: cmp::Eq {
|
||||||
|
pure fn eq(&&other: DisplayType) -> bool {
|
||||||
|
self as uint == other as uint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Unit: cmp::Eq {
|
||||||
|
pure fn eq(&&other: Unit) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Auto, Auto) => true,
|
||||||
|
(Auto, _) => false,
|
||||||
|
(Percent(a), Percent(b)) => a == b,
|
||||||
|
(Percent(*), _) => false,
|
||||||
|
(Mm(a), Mm(b)) => a == b,
|
||||||
|
(Mm(*), _) => false,
|
||||||
|
(Pt(a), Pt(b)) => a == b,
|
||||||
|
(Pt(*), _) => false,
|
||||||
|
(Px(a), Px(b)) => a == b,
|
||||||
|
(Px(*), _) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StyleDeclaration: cmp::Eq {
|
||||||
|
pure fn eq(&&other: StyleDeclaration) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(BackgroundColor(a), BackgroundColor(b)) => a == b,
|
||||||
|
(Display(a), Display(b)) => a == b,
|
||||||
|
(FontSize(a), FontSize(b)) => a == b,
|
||||||
|
(Height(a), Height(b)) => a == b,
|
||||||
|
(TextColor(a), TextColor(b)) => a == b,
|
||||||
|
(Width(a), Width(b)) => a == b,
|
||||||
|
|
||||||
|
(BackgroundColor(*), _)
|
||||||
|
| (Display(*), _)
|
||||||
|
| (FontSize(*), _)
|
||||||
|
| (Height(*), _)
|
||||||
|
| (TextColor(*), _)
|
||||||
|
| (Width(*), _) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Attr: cmp::Eq {
|
||||||
|
pure fn eq(&&other: Attr) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Exists(a), Exists(b)) => a == b,
|
||||||
|
|
||||||
|
(Exact(a, aa), Exact(b, bb))
|
||||||
|
| (Includes(a, aa), Includes(b, bb))
|
||||||
|
| (StartsWith(a, aa), StartsWith(b, bb)) => a == b && aa == bb,
|
||||||
|
|
||||||
|
(Exists(*), _)
|
||||||
|
| (Exact(*), _)
|
||||||
|
| (Includes(*), _)
|
||||||
|
| (StartsWith(*), _) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Selector: cmp::Eq {
|
||||||
|
pure fn eq(&&other: Selector) -> bool {
|
||||||
|
// FIXME: Lots of copying here
|
||||||
|
match (self, other) {
|
||||||
|
(Element(s_a, attrs_a), Element(s_b, attrs_b)) => s_a == s_b && attrs_a == attrs_b,
|
||||||
|
|
||||||
|
(Child(s1a, s2a), Child(s1b, s2b))
|
||||||
|
| (Descendant(s1a, s2a), Descendant(s1b, s2b))
|
||||||
|
| (Sibling(s1a, s2a), Sibling(s1b, s2b)) => {
|
||||||
|
s1a == s1b && s2a == s2b
|
||||||
|
}
|
||||||
|
|
||||||
|
(Element(*), _) => false,
|
||||||
|
(Child(*), _) => false,
|
||||||
|
(Descendant(*), _) => false,
|
||||||
|
(Sibling(*), _) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ import std::net::url::url;
|
||||||
import resource::image_cache_task;
|
import resource::image_cache_task;
|
||||||
import image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
import image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
||||||
|
|
||||||
import pipes::{port, chan};
|
import pipes::{Port, Chan};
|
||||||
|
|
||||||
fn macros() {
|
fn macros() {
|
||||||
include!("macros.rs");
|
include!("macros.rs");
|
||||||
|
|
|
@ -6,8 +6,8 @@ The interface used to by the renderer to aquire draw targets for
|
||||||
each rendered frame and submit them to be drawn to the display
|
each rendered frame and submit them to be drawn to the display
|
||||||
"]
|
"]
|
||||||
trait Compositor {
|
trait Compositor {
|
||||||
fn begin_drawing(+next_dt: pipes::chan<DrawTarget>);
|
fn begin_drawing(+next_dt: pipes::Chan<DrawTarget>);
|
||||||
fn draw(+next_dt: pipes::chan<DrawTarget>, +draw_me: DrawTarget);
|
fn draw(+next_dt: pipes::Chan<DrawTarget>, +draw_me: DrawTarget);
|
||||||
fn add_event_listener(listener: comm::Chan<Event>);
|
fn add_event_listener(listener: comm::Chan<Event>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,12 @@ impl au : Num {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl au : cmp::Eq {
|
||||||
|
pure fn eq(&&other: au) -> bool {
|
||||||
|
*self == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn box<A:copy Num>(x: A, y: A, w: A, h: A) -> Rect<A> {
|
fn box<A:copy Num>(x: A, y: A, w: A, h: A) -> Rect<A> {
|
||||||
Rect(Point2D(x, y), Size2D(w, h))
|
Rect(Point2D(x, y), Size2D(w, h))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,28 +20,28 @@ import cairo_bg::{cairo_image_surface_create, cairo_surface_destroy,
|
||||||
import compositor::Compositor;
|
import compositor::Compositor;
|
||||||
import render_task::{RenderTask, RenderMsg};
|
import render_task::{RenderTask, RenderMsg};
|
||||||
import task::spawn_listener;
|
import task::spawn_listener;
|
||||||
import comm::{Chan, Port, chan, port};
|
import comm::{Chan, Port};
|
||||||
import unsafe::reinterpret_cast;
|
import unsafe::reinterpret_cast;
|
||||||
import vec_from_buf = vec::unsafe::from_buf;
|
import vec_from_buf = vec::unsafe::from_buf;
|
||||||
import ptr::addr_of;
|
import ptr::addr_of;
|
||||||
import dom::event::Event;
|
import dom::event::Event;
|
||||||
import dvec::dvec;
|
import dvec::DVec;
|
||||||
import layout::display_list::display_list;
|
import layout::display_list::display_list;
|
||||||
import std::cell::Cell;
|
import std::cell::Cell;
|
||||||
|
|
||||||
type PngCompositor = Chan<Msg>;
|
type PngCompositor = Chan<Msg>;
|
||||||
|
|
||||||
enum Msg {
|
enum Msg {
|
||||||
BeginDrawing(pipes::chan<DrawTarget>),
|
BeginDrawing(pipes::Chan<DrawTarget>),
|
||||||
Draw(pipes::chan<DrawTarget>, DrawTarget),
|
Draw(pipes::Chan<DrawTarget>, DrawTarget),
|
||||||
Exit
|
Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chan<Msg> : Compositor {
|
impl Chan<Msg> : Compositor {
|
||||||
fn begin_drawing(+next_dt: pipes::chan<DrawTarget>) {
|
fn begin_drawing(+next_dt: pipes::Chan<DrawTarget>) {
|
||||||
self.send(BeginDrawing(next_dt))
|
self.send(BeginDrawing(next_dt))
|
||||||
}
|
}
|
||||||
fn draw(+next_dt: pipes::chan<DrawTarget>, +draw_me: DrawTarget) {
|
fn draw(+next_dt: pipes::Chan<DrawTarget>, +draw_me: DrawTarget) {
|
||||||
self.send(Draw(next_dt, draw_me))
|
self.send(Draw(next_dt, draw_me))
|
||||||
}
|
}
|
||||||
fn add_event_listener(_listener: Chan<Event>) {
|
fn add_event_listener(_listener: Chan<Event>) {
|
||||||
|
@ -70,7 +70,7 @@ fn PngCompositor(output: Chan<~[u8]>) -> PngCompositor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_draw(sender: pipes::chan<DrawTarget>,
|
fn do_draw(sender: pipes::Chan<DrawTarget>,
|
||||||
+dt: DrawTarget,
|
+dt: DrawTarget,
|
||||||
output: Chan<~[u8]>,
|
output: Chan<~[u8]>,
|
||||||
cairo_surface: ImageSurface) {
|
cairo_surface: ImageSurface) {
|
||||||
|
@ -89,7 +89,7 @@ fn sanity_check() {
|
||||||
let compositor = PngCompositor(self_channel);
|
let compositor = PngCompositor(self_channel);
|
||||||
let renderer = RenderTask(compositor);
|
let renderer = RenderTask(compositor);
|
||||||
|
|
||||||
let dlist : display_list = dvec();
|
let dlist : display_list = DVec();
|
||||||
renderer.send(RenderMsg(dlist));
|
renderer.send(RenderMsg(dlist));
|
||||||
let (exit_chan, exit_response_from_engine) = pipes::stream();
|
let (exit_chan, exit_response_from_engine) = pipes::stream();
|
||||||
renderer.send(render_task::ExitMsg(exit_chan));
|
renderer.send(render_task::ExitMsg(exit_chan));
|
||||||
|
|
|
@ -14,18 +14,18 @@ import geom::point::Point2D;
|
||||||
import azure_hl::{AsAzureRect, B8G8R8A8, Color, ColorPattern, DrawOptions, DrawSurfaceOptions};
|
import azure_hl::{AsAzureRect, B8G8R8A8, Color, ColorPattern, DrawOptions, DrawSurfaceOptions};
|
||||||
import azure_hl::{DrawTarget, Linear};
|
import azure_hl::{DrawTarget, Linear};
|
||||||
import ptr::addr_of;
|
import ptr::addr_of;
|
||||||
import std::arc::arc;
|
import std::arc::ARC;
|
||||||
import azure::cairo::{cairo_font_face_t, cairo_scaled_font_t};
|
import azure::cairo::{cairo_font_face_t, cairo_scaled_font_t};
|
||||||
import std::cell::Cell;
|
import std::cell::Cell;
|
||||||
import compositor::Compositor;
|
import compositor::Compositor;
|
||||||
|
|
||||||
import pipes::{port, chan};
|
import pipes::{Port, Chan};
|
||||||
|
|
||||||
type Renderer = comm::Chan<Msg>;
|
type Renderer = comm::Chan<Msg>;
|
||||||
|
|
||||||
enum Msg {
|
enum Msg {
|
||||||
RenderMsg(dl::display_list),
|
RenderMsg(dl::display_list),
|
||||||
ExitMsg(pipes::chan<()>)
|
ExitMsg(pipes::Chan<()>)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RenderTask = comm::Chan<Msg>;
|
type RenderTask = comm::Chan<Msg>;
|
||||||
|
@ -46,11 +46,11 @@ fn RenderTask<C: Compositor send>(+compositor: C) -> RenderTask {
|
||||||
#debug("renderer: got render request");
|
#debug("renderer: got render request");
|
||||||
let draw_target = Cell(draw_target_po.recv());
|
let draw_target = Cell(draw_target_po.recv());
|
||||||
let (ch, po) = pipes::stream();
|
let (ch, po) = pipes::stream();
|
||||||
let mut draw_target_ch_ = some(ch);
|
let mut draw_target_ch_ = Some(ch);
|
||||||
draw_target_po = po;
|
draw_target_po = po;
|
||||||
#debug("renderer: rendering");
|
#debug("renderer: rendering");
|
||||||
do util::time::time(~"rendering") {
|
do util::time::time(~"rendering") {
|
||||||
let mut draw_target_ch = none;
|
let mut draw_target_ch = None;
|
||||||
draw_target_ch_ <-> draw_target_ch;
|
draw_target_ch_ <-> draw_target_ch;
|
||||||
let draw_target_ch = option::unwrap(draw_target_ch);
|
let draw_target_ch = option::unwrap(draw_target_ch);
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ fn draw_solid_color(draw_target: &DrawTarget, item: dl::display_item, r: u8, g:
|
||||||
draw_target.fill_rect(item.bounds.to_azure_rect(), ColorPattern(color));
|
draw_target.fill_rect(item.bounds.to_azure_rect(), ColorPattern(color));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_image(draw_target: &DrawTarget, item: dl::display_item, image: arc<~Image>) unsafe {
|
fn draw_image(draw_target: &DrawTarget, item: dl::display_item, image: ARC<~Image>) unsafe {
|
||||||
let image = std::arc::get(&image);
|
let image = std::arc::get(&image);
|
||||||
let size = Size2D(image.width as i32, image.height as i32);
|
let size = Size2D(image.width as i32, image.height as i32);
|
||||||
let stride = image.width * 4;
|
let stride = image.width * 4;
|
||||||
|
|
|
@ -5,6 +5,14 @@ enum format {
|
||||||
// TODO: RGB 565, others?
|
// TODO: RGB 565, others?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl format: cmp::Eq {
|
||||||
|
pure fn eq(&&other: format) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(fo_rgba_8888, fo_rgba_8888) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type image_surface = {
|
type image_surface = {
|
||||||
size: Size2D<int>,
|
size: Size2D<int>,
|
||||||
format: format,
|
format: format,
|
||||||
|
|
|
@ -21,7 +21,7 @@ fn test_image_bin() -> ~[u8] {
|
||||||
return vec::from_fn(4962, |i| TEST_IMAGE[i]);
|
return vec::from_fn(4962, |i| TEST_IMAGE[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_from_memory(buffer: &[u8]) -> option<Image> {
|
fn load_from_memory(buffer: &[u8]) -> Option<Image> {
|
||||||
do stb_image::load_from_memory(buffer).map |image| {
|
do stb_image::load_from_memory(buffer).map |image| {
|
||||||
|
|
||||||
assert image.depth == 4;
|
assert image.depth == 4;
|
||||||
|
|
|
@ -20,7 +20,7 @@ import std::net::url::url;
|
||||||
import resource::image_cache_task;
|
import resource::image_cache_task;
|
||||||
import image_cache_task::ImageCacheTask;
|
import image_cache_task::ImageCacheTask;
|
||||||
import core::to_str::ToStr;
|
import core::to_str::ToStr;
|
||||||
import std::arc::{arc, clone};
|
import std::arc::{ARC, clone};
|
||||||
import task::spawn;
|
import task::spawn;
|
||||||
|
|
||||||
enum BoxKind {
|
enum BoxKind {
|
||||||
|
@ -30,14 +30,23 @@ enum BoxKind {
|
||||||
TextBoxKind(@TextBox)
|
TextBoxKind(@TextBox)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BoxKind : cmp::Eq {
|
||||||
|
pure fn eq(&&other: BoxKind) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(BlockBox, BlockBox) => true,
|
||||||
|
_ => fail ~"unimplemented case in BoxKind.eq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Appearance {
|
struct Appearance {
|
||||||
let mut background_image: option<ImageHolder>;
|
let mut background_image: Option<ImageHolder>;
|
||||||
let mut background_color: Color;
|
let mut background_color: Color;
|
||||||
let mut width: Unit;
|
let mut width: Unit;
|
||||||
let mut height: Unit;
|
let mut height: Unit;
|
||||||
|
|
||||||
new(kind: NodeKind) {
|
new(kind: NodeKind) {
|
||||||
self.background_image = none;
|
self.background_image = None;
|
||||||
self.background_color = kind.default_color();
|
self.background_color = kind.default_color();
|
||||||
self.width = kind.default_width();
|
self.width = kind.default_width();
|
||||||
self.height = kind.default_height();
|
self.height = kind.default_height();
|
||||||
|
@ -45,18 +54,18 @@ struct Appearance {
|
||||||
|
|
||||||
// This will be very unhappy if it is getting run in parallel with
|
// This will be very unhappy if it is getting run in parallel with
|
||||||
// anything trying to read the background image
|
// anything trying to read the background image
|
||||||
fn get_image() -> option<~arc<~Image>> {
|
fn get_image() -> Option<~ARC<~Image>> {
|
||||||
let mut image = none;
|
let mut image = None;
|
||||||
|
|
||||||
// Do a dance where we swap the ImageHolder out before we can
|
// Do a dance where we swap the ImageHolder out before we can
|
||||||
// get the image out of it because we can't match against it
|
// get the image out of it because we can't match against it
|
||||||
// because holder.get_image() is not pure.
|
// because holder.get_image() is not pure.
|
||||||
if (self.background_image).is_some() {
|
if (self.background_image).is_some() {
|
||||||
let mut temp = none;
|
let mut temp = None;
|
||||||
temp <-> self.background_image;
|
temp <-> self.background_image;
|
||||||
let holder <- option::unwrap(temp);
|
let holder <- option::unwrap(temp);
|
||||||
image = holder.get_image();
|
image = holder.get_image();
|
||||||
self.background_image = some(holder);
|
self.background_image = Some(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
|
@ -85,14 +94,14 @@ struct Box {
|
||||||
struct ImageHolder {
|
struct ImageHolder {
|
||||||
// Invariant: at least one of url and image is not none, except
|
// Invariant: at least one of url and image is not none, except
|
||||||
// occasionally while get_image is being called
|
// occasionally while get_image is being called
|
||||||
let mut url : option<url>;
|
let mut url : Option<url>;
|
||||||
let mut image : option<arc<~Image>>;
|
let mut image : Option<ARC<~Image>>;
|
||||||
let image_cache_task: ImageCacheTask;
|
let image_cache_task: ImageCacheTask;
|
||||||
let reflow: fn~();
|
let reflow: fn~();
|
||||||
|
|
||||||
new(-url : url, image_cache_task: ImageCacheTask, reflow: fn~()) {
|
new(-url : url, image_cache_task: ImageCacheTask, reflow: fn~()) {
|
||||||
self.url = some(copy url);
|
self.url = Some(copy url);
|
||||||
self.image = none;
|
self.image = None;
|
||||||
self.image_cache_task = image_cache_task;
|
self.image_cache_task = image_cache_task;
|
||||||
self.reflow = copy reflow;
|
self.reflow = copy reflow;
|
||||||
|
|
||||||
|
@ -106,26 +115,26 @@ struct ImageHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function should not be called by two tasks at the same time
|
// This function should not be called by two tasks at the same time
|
||||||
fn get_image() -> option<~arc<~Image>> {
|
fn get_image() -> Option<~ARC<~Image>> {
|
||||||
// If this is the first time we've called this function, load
|
// If this is the first time we've called this function, load
|
||||||
// the image and store it for the future
|
// the image and store it for the future
|
||||||
if self.image.is_none() {
|
if self.image.is_none() {
|
||||||
assert self.url.is_some();
|
assert self.url.is_some();
|
||||||
|
|
||||||
let mut temp = none;
|
let mut temp = None;
|
||||||
temp <-> self.url;
|
temp <-> self.url;
|
||||||
let url = option::unwrap(temp);
|
let url = option::unwrap(temp);
|
||||||
|
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
self.image_cache_task.send(image_cache_task::GetImage(copy url, response_port.chan()));
|
self.image_cache_task.send(image_cache_task::GetImage(copy url, response_port.chan()));
|
||||||
self.image = match response_port.recv() {
|
self.image = match response_port.recv() {
|
||||||
image_cache_task::ImageReady(image) => some(clone(&image)),
|
image_cache_task::ImageReady(image) => Some(clone(&image)),
|
||||||
image_cache_task::ImageNotReady => {
|
image_cache_task::ImageNotReady => {
|
||||||
// Need to reflow when the image is available
|
// Need to reflow when the image is available
|
||||||
let image_cache_task = self.image_cache_task;
|
let image_cache_task = self.image_cache_task;
|
||||||
let reflow = copy self.reflow;
|
let reflow = copy self.reflow;
|
||||||
do spawn |copy url, move reflow| {
|
do spawn |copy url, move reflow| {
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(image_cache_task::WaitForImage(copy url, response_port.chan()));
|
image_cache_task.send(image_cache_task::WaitForImage(copy url, response_port.chan()));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
image_cache_task::ImageReady(*) => reflow(),
|
image_cache_task::ImageReady(*) => reflow(),
|
||||||
|
@ -133,12 +142,12 @@ struct ImageHolder {
|
||||||
image_cache_task::ImageFailed => ()
|
image_cache_task::ImageFailed => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
none
|
None
|
||||||
}
|
}
|
||||||
image_cache_task::ImageFailed => {
|
image_cache_task::ImageFailed => {
|
||||||
#info("image was not ready for %s", url.to_str());
|
#info("image was not ready for %s", url.to_str());
|
||||||
// FIXME: Need to schedule another layout when the image is ready
|
// FIXME: Need to schedule another layout when the image is ready
|
||||||
none
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -147,21 +156,21 @@ struct ImageHolder {
|
||||||
// Temporarily swap out the arc of the image so we can clone
|
// Temporarily swap out the arc of the image so we can clone
|
||||||
// it without breaking purity, then put it back and return the
|
// it without breaking purity, then put it back and return the
|
||||||
// clone. This is not threadsafe.
|
// clone. This is not threadsafe.
|
||||||
let mut temp = none;
|
let mut temp = None;
|
||||||
temp <-> self.image;
|
temp <-> self.image;
|
||||||
let im_arc = option::unwrap(temp);
|
let im_arc = option::unwrap(temp);
|
||||||
self.image = some(clone(&im_arc));
|
self.image = Some(clone(&im_arc));
|
||||||
|
|
||||||
return some(~im_arc);
|
return Some(~im_arc);
|
||||||
} else {
|
} else {
|
||||||
return none;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LayoutData = {
|
enum LayoutData = {
|
||||||
mut specified_style: ~SpecifiedStyle,
|
mut specified_style: ~SpecifiedStyle,
|
||||||
mut box: option<@Box>
|
mut box: Option<@Box>
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: This is way too complex! Why do these have to have dummy receivers? --pcw
|
// FIXME: This is way too complex! Why do these have to have dummy receivers? --pcw
|
||||||
|
|
|
@ -23,14 +23,14 @@ enum ctxt = {
|
||||||
// See CSS2 9.2.1.1.
|
// See CSS2 9.2.1.1.
|
||||||
//
|
//
|
||||||
|
|
||||||
mut anon_box: option<@Box>
|
mut anon_box: Option<@Box>
|
||||||
};
|
};
|
||||||
|
|
||||||
fn create_context(parent_node: Node, parent_box: @Box) -> ctxt {
|
fn create_context(parent_node: Node, parent_box: @Box) -> ctxt {
|
||||||
return ctxt({
|
return ctxt({
|
||||||
parent_node: parent_node,
|
parent_node: parent_node,
|
||||||
parent_box: parent_box,
|
parent_box: parent_box,
|
||||||
mut anon_box: none
|
mut anon_box: None
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,16 +46,16 @@ impl ctxt {
|
||||||
|
|
||||||
// Determine the child's display.
|
// Determine the child's display.
|
||||||
let disp = kid.get_specified_style().display_type;
|
let disp = kid.get_specified_style().display_type;
|
||||||
if disp != some(DisInline) {
|
if disp != Some(DisInline) {
|
||||||
self.finish_anonymous_box_if_necessary();
|
self.finish_anonymous_box_if_necessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the child's box to the current enclosing box or the current anonymous box.
|
// Add the child's box to the current enclosing box or the current anonymous box.
|
||||||
match kid.get_specified_style().display_type {
|
match kid.get_specified_style().display_type {
|
||||||
some(DisBlock) => BTree.add_child(self.parent_box, kid_box),
|
Some(DisBlock) => BTree.add_child(self.parent_box, kid_box),
|
||||||
some(DisInline) => {
|
Some(DisInline) => {
|
||||||
let anon_box = match self.anon_box {
|
let anon_box = match self.anon_box {
|
||||||
none => {
|
None => {
|
||||||
//
|
//
|
||||||
// The anonymous box inherits the attributes of its parents for now, so
|
// The anonymous box inherits the attributes of its parents for now, so
|
||||||
// that properties of intrinsic boxes are not spread to their parenting
|
// that properties of intrinsic boxes are not spread to their parenting
|
||||||
|
@ -65,14 +65,14 @@ impl ctxt {
|
||||||
//
|
//
|
||||||
|
|
||||||
let b = @Box(self.parent_node, InlineBox);
|
let b = @Box(self.parent_node, InlineBox);
|
||||||
self.anon_box = some(b);
|
self.anon_box = Some(b);
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
some(b) => b
|
Some(b) => b
|
||||||
};
|
};
|
||||||
BTree.add_child(anon_box, kid_box);
|
BTree.add_child(anon_box, kid_box);
|
||||||
}
|
}
|
||||||
some(DisNone) => {
|
Some(DisNone) => {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
_ => { //hack for now
|
_ => { //hack for now
|
||||||
|
@ -93,21 +93,21 @@ impl ctxt {
|
||||||
|
|
||||||
// Determine the child's display.
|
// Determine the child's display.
|
||||||
let disp = kid.get_specified_style().display_type;
|
let disp = kid.get_specified_style().display_type;
|
||||||
if disp != some(DisInline) {
|
if disp != Some(DisInline) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the child's box to the current enclosing box.
|
// Add the child's box to the current enclosing box.
|
||||||
match kid.get_specified_style().display_type {
|
match kid.get_specified_style().display_type {
|
||||||
some(DisBlock) => {
|
Some(DisBlock) => {
|
||||||
// TODO
|
// TODO
|
||||||
#warn("TODO: non-inline display found inside inline box");
|
#warn("TODO: non-inline display found inside inline box");
|
||||||
BTree.add_child(self.parent_box, kid_box);
|
BTree.add_child(self.parent_box, kid_box);
|
||||||
}
|
}
|
||||||
some(DisInline) => {
|
Some(DisInline) => {
|
||||||
BTree.add_child(self.parent_box, kid_box);
|
BTree.add_child(self.parent_box, kid_box);
|
||||||
}
|
}
|
||||||
some(DisNone) => {
|
Some(DisNone) => {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
_ => { //hack for now
|
_ => { //hack for now
|
||||||
|
@ -122,9 +122,9 @@ impl ctxt {
|
||||||
self.parent_node.dump();
|
self.parent_node.dump();
|
||||||
|
|
||||||
match self.parent_node.get_specified_style().display_type {
|
match self.parent_node.get_specified_style().display_type {
|
||||||
some(DisBlock) => self.construct_boxes_for_block_children(),
|
Some(DisBlock) => self.construct_boxes_for_block_children(),
|
||||||
some(DisInline) => self.construct_boxes_for_inline_children(),
|
Some(DisInline) => self.construct_boxes_for_inline_children(),
|
||||||
some(DisNone) => { /* Nothing to do. */ }
|
Some(DisNone) => { /* Nothing to do. */ }
|
||||||
_ => { //hack for now
|
_ => { //hack for now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,10 +139,10 @@ impl ctxt {
|
||||||
"]
|
"]
|
||||||
fn finish_anonymous_box_if_necessary() {
|
fn finish_anonymous_box_if_necessary() {
|
||||||
match copy self.anon_box {
|
match copy self.anon_box {
|
||||||
none => { /* Nothing to do. */ }
|
None => { /* Nothing to do. */ }
|
||||||
some(b) => BTree.add_child(self.parent_box, b)
|
Some(b) => BTree.add_child(self.parent_box, b)
|
||||||
}
|
}
|
||||||
self.anon_box = none;
|
self.anon_box = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,13 +161,13 @@ impl Node : PrivBoxBuilder {
|
||||||
~Element(element) => {
|
~Element(element) => {
|
||||||
match (copy *element.kind, self.get_specified_style().display_type) {
|
match (copy *element.kind, self.get_specified_style().display_type) {
|
||||||
(HTMLImageElement({size}), _) => IntrinsicBox(@size),
|
(HTMLImageElement({size}), _) => IntrinsicBox(@size),
|
||||||
(_, some(DisBlock)) => BlockBox,
|
(_, Some(DisBlock)) => BlockBox,
|
||||||
(_, some(DisInline)) => InlineBox,
|
(_, Some(DisInline)) => InlineBox,
|
||||||
(_, some(DisNone)) => {
|
(_, Some(DisNone)) => {
|
||||||
// TODO: don't have a box here at all?
|
// TODO: don't have a box here at all?
|
||||||
IntrinsicBox(@zero_size_au())
|
IntrinsicBox(@zero_size_au())
|
||||||
}
|
}
|
||||||
(_, none) => {
|
(_, None) => {
|
||||||
fail ~"The specified display style should be a default instead of none"
|
fail ~"The specified display style should be a default instead of none"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,12 @@ import geom::rect::Rect;
|
||||||
import image::base::Image;
|
import image::base::Image;
|
||||||
import servo_text::text_run::TextRun;
|
import servo_text::text_run::TextRun;
|
||||||
|
|
||||||
import std::arc::arc;
|
import std::arc::ARC;
|
||||||
import dvec::DVec;
|
import dvec::DVec;
|
||||||
|
|
||||||
enum item_type {
|
enum item_type {
|
||||||
display_item_solid_color(u8, u8, u8),
|
display_item_solid_color(u8, u8, u8),
|
||||||
display_item_image(~arc<~Image>),
|
display_item_image(~ARC<~Image>),
|
||||||
display_item_text(TextRun),
|
display_item_text(TextRun),
|
||||||
// FIXME: Shape code does not understand the alignment without this
|
// FIXME: Shape code does not understand the alignment without this
|
||||||
padding(u8, u8, u8, u8)
|
padding(u8, u8, u8, u8)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import geom::size::Size2D;
|
||||||
import gfx::geometry::{au, au_to_px, box, px_to_au};
|
import gfx::geometry::{au, au_to_px, box, px_to_au};
|
||||||
import util::tree;
|
import util::tree;
|
||||||
|
|
||||||
import dvec::dvec;
|
import dvec::DVec;
|
||||||
import vec::push;
|
import vec::push;
|
||||||
|
|
||||||
#[doc = "
|
#[doc = "
|
||||||
|
@ -20,7 +20,7 @@ Builds a display list for a box and all its children
|
||||||
|
|
||||||
"]
|
"]
|
||||||
fn build_display_list(box : @Box) -> dl::display_list {
|
fn build_display_list(box : @Box) -> dl::display_list {
|
||||||
let list = dvec();
|
let list = DVec();
|
||||||
build_display_list_from_origin(list, box, Point2D(au(0), au(0)));
|
build_display_list_from_origin(list, box, Point2D(au(0), au(0)));
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -113,10 +113,13 @@ fn should_convert_text_boxes_to_solid_color_background_items() {
|
||||||
let n = s.new_node(Text(~"firecracker"));
|
let n = s.new_node(Text(~"firecracker"));
|
||||||
let b = n.construct_boxes();
|
let b = n.construct_boxes();
|
||||||
|
|
||||||
let subbox = match check b.kind { TextBoxKind(subbox) => subbox };
|
let subbox = match b.kind {
|
||||||
|
TextBoxKind(subbox) => subbox,
|
||||||
|
_ => fail
|
||||||
|
};
|
||||||
|
|
||||||
b.reflow_text(subbox);
|
b.reflow_text(subbox);
|
||||||
let list = dvec();
|
let list = DVec();
|
||||||
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
||||||
|
|
||||||
match list[0].item_type {
|
match list[0].item_type {
|
||||||
|
@ -133,10 +136,13 @@ fn should_convert_text_boxes_to_text_items() {
|
||||||
let n = s.new_node(Text(~"firecracker"));
|
let n = s.new_node(Text(~"firecracker"));
|
||||||
let b = n.construct_boxes();
|
let b = n.construct_boxes();
|
||||||
|
|
||||||
let subbox = match check b.kind { TextBoxKind(subbox) => { subbox } };
|
let subbox = match b.kind {
|
||||||
|
TextBoxKind(subbox) => { subbox },
|
||||||
|
_ => fail
|
||||||
|
};
|
||||||
|
|
||||||
b.reflow_text(subbox);
|
b.reflow_text(subbox);
|
||||||
let list = dvec();
|
let list = DVec();
|
||||||
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
||||||
|
|
||||||
match list[1].item_type {
|
match list[1].item_type {
|
||||||
|
@ -153,10 +159,13 @@ fn should_calculate_the_bounds_of_the_text_box_background_color() {
|
||||||
let n = s.new_node(Text(~"firecracker"));
|
let n = s.new_node(Text(~"firecracker"));
|
||||||
let b = n.construct_boxes();
|
let b = n.construct_boxes();
|
||||||
|
|
||||||
let subbox = match check b.kind { TextBoxKind(subbox) => { subbox } };
|
let subbox = match b.kind {
|
||||||
|
TextBoxKind(subbox) => { subbox },
|
||||||
|
_ => fail
|
||||||
|
};
|
||||||
|
|
||||||
b.reflow_text(subbox);
|
b.reflow_text(subbox);
|
||||||
let list = dvec();
|
let list = DVec();
|
||||||
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
||||||
|
|
||||||
let expected = Rect(
|
let expected = Rect(
|
||||||
|
@ -175,10 +184,13 @@ fn should_calculate_the_bounds_of_the_text_items() {
|
||||||
let n = s.new_node(Text(~"firecracker"));
|
let n = s.new_node(Text(~"firecracker"));
|
||||||
let b = n.construct_boxes();
|
let b = n.construct_boxes();
|
||||||
|
|
||||||
let subbox = match check b.kind { TextBoxKind(subbox) => { subbox } };
|
let subbox = match b.kind {
|
||||||
|
TextBoxKind(subbox) => { subbox },
|
||||||
|
_ => fail
|
||||||
|
};
|
||||||
|
|
||||||
b.reflow_text(subbox);
|
b.reflow_text(subbox);
|
||||||
let list = dvec();
|
let list = DVec();
|
||||||
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));
|
||||||
|
|
||||||
let expected = Rect(
|
let expected = Rect(
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl @Box : InlineLayout {
|
||||||
for tree::each_child(BTree, self) |kid| {
|
for tree::each_child(BTree, self) |kid| {
|
||||||
kid.bounds.origin = Point2D(au(x), au(y));
|
kid.bounds.origin = Point2D(au(x), au(y));
|
||||||
x += *kid.bounds.size.width;
|
x += *kid.bounds.size.width;
|
||||||
current_height = i32::max(current_height, *kid.bounds.size.height);
|
current_height = i32::max(¤t_height, &*kid.bounds.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
let height = match self.appearance.height {
|
let height = match self.appearance.height {
|
||||||
|
@ -41,7 +41,7 @@ impl @Box : InlineLayout {
|
||||||
|
|
||||||
let width = match self.appearance.width {
|
let width = match self.appearance.width {
|
||||||
Px(p) => px_to_au(p.to_int()),
|
Px(p) => px_to_au(p.to_int()),
|
||||||
Auto => au(i32::max(x, *self.bounds.size.width)),
|
Auto => au(i32::max(&x, &*self.bounds.size.width)),
|
||||||
_ => fail ~"inhereit_width failed, width is neither a Px or auto"
|
_ => fail ~"inhereit_width failed, width is neither a Px or auto"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
rendered.
|
rendered.
|
||||||
"];
|
"];
|
||||||
|
|
||||||
import std::arc::arc;
|
import std::arc::ARC;
|
||||||
import display_list_builder::build_display_list;
|
import display_list_builder::build_display_list;
|
||||||
import dom::base::Node;
|
import dom::base::Node;
|
||||||
import dom::style::Stylesheet;
|
import dom::style::Stylesheet;
|
||||||
|
@ -22,7 +22,7 @@ import comm::*;
|
||||||
type LayoutTask = Chan<Msg>;
|
type LayoutTask = Chan<Msg>;
|
||||||
|
|
||||||
enum Msg {
|
enum Msg {
|
||||||
BuildMsg(Node, arc<Stylesheet>, url, Chan<Event>),
|
BuildMsg(Node, ARC<Stylesheet>, url, Chan<Event>),
|
||||||
PingMsg(Chan<content_task::PingMsg>),
|
PingMsg(Chan<content_task::PingMsg>),
|
||||||
ExitMsg
|
ExitMsg
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,15 +47,15 @@ fn inhereit_height(box : @Box) {
|
||||||
let style = box.node.get_specified_style();
|
let style = box.node.get_specified_style();
|
||||||
|
|
||||||
box.appearance.height = match style.height {
|
box.appearance.height = match style.height {
|
||||||
none => Auto,
|
None => Auto,
|
||||||
some(h) => match h {
|
Some(h) => match h {
|
||||||
Auto | Px(*) => h,
|
Auto | Px(*) => h,
|
||||||
Pt(*) => PtToPx(h),
|
Pt(*) => PtToPx(h),
|
||||||
Mm(*) => MmToPx(h),
|
Mm(*) => MmToPx(h),
|
||||||
Percent(em) => {
|
Percent(em) => {
|
||||||
match box.tree.parent {
|
match box.tree.parent {
|
||||||
none => Auto,
|
None => Auto,
|
||||||
some(parent) => {
|
Some(parent) => {
|
||||||
match parent.appearance.height {
|
match parent.appearance.height {
|
||||||
//This is a poorly constrained case, so we ignore the percentage
|
//This is a poorly constrained case, so we ignore the percentage
|
||||||
Auto => Auto,
|
Auto => Auto,
|
||||||
|
@ -77,15 +77,15 @@ fn inhereit_width(box : @Box) {
|
||||||
let style = box.node.get_specified_style();
|
let style = box.node.get_specified_style();
|
||||||
|
|
||||||
box.appearance.width = match style.width {
|
box.appearance.width = match style.width {
|
||||||
none => Auto,
|
None => Auto,
|
||||||
some(h) => match h {
|
Some(h) => match h {
|
||||||
Auto | Px(*) => h,
|
Auto | Px(*) => h,
|
||||||
Pt(*) => PtToPx(h),
|
Pt(*) => PtToPx(h),
|
||||||
Mm(*) => MmToPx(h),
|
Mm(*) => MmToPx(h),
|
||||||
Percent(em) => {
|
Percent(em) => {
|
||||||
match box.tree.parent {
|
match box.tree.parent {
|
||||||
none => Auto,
|
None => Auto,
|
||||||
some(parent) => {
|
Some(parent) => {
|
||||||
match parent.appearance.width {
|
match parent.appearance.width {
|
||||||
//This is a poorly constrained case, so we ignore the percentage
|
//This is a poorly constrained case, so we ignore the percentage
|
||||||
Auto => Auto,
|
Auto => Auto,
|
||||||
|
@ -127,8 +127,8 @@ impl StyleApplicator {
|
||||||
let style = self.box.node.get_specified_style();
|
let style = self.box.node.get_specified_style();
|
||||||
|
|
||||||
self.box.appearance.background_color = match style.background_color {
|
self.box.appearance.background_color = match style.background_color {
|
||||||
some(col) => col,
|
Some(col) => col,
|
||||||
none => node.kind.default_color()
|
None => node.kind.default_color()
|
||||||
};
|
};
|
||||||
|
|
||||||
match element.kind {
|
match element.kind {
|
||||||
|
@ -138,8 +138,8 @@ impl StyleApplicator {
|
||||||
if url.is_some() {
|
if url.is_some() {
|
||||||
// FIXME: Some sort of BASE HREF support!
|
// FIXME: Some sort of BASE HREF support!
|
||||||
// FIXME: Parse URLs!
|
// FIXME: Parse URLs!
|
||||||
let new_url = make_url(option::unwrap(url), some(copy *self.doc_url));
|
let new_url = make_url(option::unwrap(url), Some(copy *self.doc_url));
|
||||||
self.box.appearance.background_image = some(ImageHolder(new_url, self.image_cache_task, self.reflow))
|
self.box.appearance.background_image = Some(ImageHolder(new_url, self.image_cache_task, self.reflow))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => { /* Ignore. */ }
|
_ => { /* Ignore. */ }
|
||||||
|
@ -155,7 +155,7 @@ impl StyleApplicator {
|
||||||
mod test {
|
mod test {
|
||||||
import dom::base::{Attr, HTMLDivElement, HTMLHeadElement, HTMLImageElement, ElementData};
|
import dom::base::{Attr, HTMLDivElement, HTMLHeadElement, HTMLImageElement, ElementData};
|
||||||
import dom::base::{NodeScope, UnknownElement};
|
import dom::base::{NodeScope, UnknownElement};
|
||||||
import dvec::dvec;
|
import dvec::DVec;
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
fn new_node(scope: NodeScope, -name: ~str) -> Node {
|
fn new_node(scope: NodeScope, -name: ~str) -> Node {
|
||||||
|
@ -179,11 +179,11 @@ mod test {
|
||||||
scope.add_child(child, g2);
|
scope.add_child(child, g2);
|
||||||
let _handles = parent.initialize_style_for_subtree();
|
let _handles = parent.initialize_style_for_subtree();
|
||||||
|
|
||||||
do parent.aux |aux| { aux.specified_style.height = some(Px(100.0)); }
|
do parent.aux |aux| { aux.specified_style.height = Some(Px(100.0)); }
|
||||||
do child.aux |aux| { aux.specified_style.height = some(Auto); }
|
do child.aux |aux| { aux.specified_style.height = Some(Auto); }
|
||||||
do child2.aux |aux| { aux.specified_style.height = some(Percent(50.0)); }
|
do child2.aux |aux| { aux.specified_style.height = Some(Percent(50.0)); }
|
||||||
do g1.aux |aux| { aux.specified_style.height = some(Percent(50.0)); }
|
do g1.aux |aux| { aux.specified_style.height = Some(Percent(50.0)); }
|
||||||
do g2.aux |aux| { aux.specified_style.height = some(Px(10.0)); }
|
do g2.aux |aux| { aux.specified_style.height = Some(Px(10.0)); }
|
||||||
|
|
||||||
let parent_box = parent.construct_boxes();
|
let parent_box = parent.construct_boxes();
|
||||||
let child_box = parent_box.tree.first_child.get();
|
let child_box = parent_box.tree.first_child.get();
|
||||||
|
|
|
@ -13,14 +13,14 @@ fn attrs_match(attr: Attr, elmt: ElementData) -> bool {
|
||||||
match attr {
|
match attr {
|
||||||
Exists(name) => {
|
Exists(name) => {
|
||||||
match elmt.get_attr(name) {
|
match elmt.get_attr(name) {
|
||||||
some(_) => true,
|
Some(_) => true,
|
||||||
none => false
|
None => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Exact(name, val) => {
|
Exact(name, val) => {
|
||||||
match elmt.get_attr(name) {
|
match elmt.get_attr(name) {
|
||||||
some(value) => value == val,
|
Some(value) => value == val,
|
||||||
none => false
|
None => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Includes(name, val) => {
|
Includes(name, val) => {
|
||||||
|
@ -29,13 +29,13 @@ fn attrs_match(attr: Attr, elmt: ElementData) -> bool {
|
||||||
if val == ~"" { return false; }
|
if val == ~"" { return false; }
|
||||||
|
|
||||||
match elmt.get_attr(name) {
|
match elmt.get_attr(name) {
|
||||||
some(value) => value.split_char(' ').contains(val),
|
Some(value) => value.split_char(' ').contains(val),
|
||||||
none => false
|
None => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StartsWith(name, val) => {
|
StartsWith(name, val) => {
|
||||||
match elmt.get_attr(name) {
|
match elmt.get_attr(name) {
|
||||||
some(value) => {
|
Some(value) => {
|
||||||
//check that there is only one attribute value and it
|
//check that there is only one attribute value and it
|
||||||
//starts with the perscribed value
|
//starts with the perscribed value
|
||||||
if !value.starts_with(val) || value.contains(~" ") { return false; }
|
if !value.starts_with(val) || value.contains(~" ") { return false; }
|
||||||
|
@ -44,7 +44,7 @@ fn attrs_match(attr: Attr, elmt: ElementData) -> bool {
|
||||||
if value.len() == val.len() { true }
|
if value.len() == val.len() { true }
|
||||||
else { value.starts_with(val + ~"-") }
|
else { value.starts_with(val + ~"-") }
|
||||||
}
|
}
|
||||||
none => {
|
None => {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ impl Node : PrivMatchingMethods {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Text(str) => { /*fall through, currently unsupported*/ }
|
Text(*) => { /*fall through, currently unsupported*/ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,11 +92,11 @@ impl Node : PrivMatchingMethods {
|
||||||
#[doc = "Checks if a generic CSS selector matches a given HTML element"]
|
#[doc = "Checks if a generic CSS selector matches a given HTML element"]
|
||||||
fn matches_selector(sel : ~Selector) -> bool {
|
fn matches_selector(sel : ~Selector) -> bool {
|
||||||
match *sel {
|
match *sel {
|
||||||
Element(str, atts) => { return self.matches_element(sel); }
|
Element(*) => { return self.matches_element(sel); }
|
||||||
Child(sel1, sel2) => {
|
Child(sel1, sel2) => {
|
||||||
return match self.read(|n| n.tree.parent) {
|
return match self.read(|n| n.tree.parent) {
|
||||||
some(parent) => self.matches_element(sel2) && parent.matches_selector(sel1),
|
Some(parent) => self.matches_element(sel2) && parent.matches_selector(sel1),
|
||||||
none => false
|
None => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Descendant(sel1, sel2) => {
|
Descendant(sel1, sel2) => {
|
||||||
|
@ -105,16 +105,16 @@ impl Node : PrivMatchingMethods {
|
||||||
//loop over all ancestors to check if they are the person
|
//loop over all ancestors to check if they are the person
|
||||||
//we should be descended from.
|
//we should be descended from.
|
||||||
let mut cur_parent = match self.read(|n| n.tree.parent) {
|
let mut cur_parent = match self.read(|n| n.tree.parent) {
|
||||||
some(parent) => parent,
|
Some(parent) => parent,
|
||||||
none => return false
|
None => return false
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if cur_parent.matches_selector(sel1) { return true; }
|
if cur_parent.matches_selector(sel1) { return true; }
|
||||||
|
|
||||||
cur_parent = match cur_parent.read(|n| n.tree.parent) {
|
cur_parent = match cur_parent.read(|n| n.tree.parent) {
|
||||||
some(parent) => parent,
|
Some(parent) => parent,
|
||||||
none => return false
|
None => return false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,34 +123,34 @@ impl Node : PrivMatchingMethods {
|
||||||
|
|
||||||
// Loop over this node's previous siblings to see if they match.
|
// Loop over this node's previous siblings to see if they match.
|
||||||
match self.read(|n| n.tree.prev_sibling) {
|
match self.read(|n| n.tree.prev_sibling) {
|
||||||
some(sib) => {
|
Some(sib) => {
|
||||||
let mut cur_sib = sib;
|
let mut cur_sib = sib;
|
||||||
loop {
|
loop {
|
||||||
if cur_sib.matches_selector(sel1) { return true; }
|
if cur_sib.matches_selector(sel1) { return true; }
|
||||||
|
|
||||||
cur_sib = match cur_sib.read(|n| n.tree.prev_sibling) {
|
cur_sib = match cur_sib.read(|n| n.tree.prev_sibling) {
|
||||||
some(sib) => sib,
|
Some(sib) => sib,
|
||||||
none => { break; }
|
None => { break; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
none => { }
|
None => { }
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the rest of the siblings
|
// check the rest of the siblings
|
||||||
match self.read(|n| n.tree.next_sibling) {
|
match self.read(|n| n.tree.next_sibling) {
|
||||||
some(sib) => {
|
Some(sib) => {
|
||||||
let mut cur_sib = sib;
|
let mut cur_sib = sib;
|
||||||
loop {
|
loop {
|
||||||
if cur_sib.matches_selector(sel1) { return true; }
|
if cur_sib.matches_selector(sel1) { return true; }
|
||||||
|
|
||||||
cur_sib = match cur_sib.read(|n| n.tree.next_sibling) {
|
cur_sib = match cur_sib.read(|n| n.tree.next_sibling) {
|
||||||
some(sib) => sib,
|
Some(sib) => sib,
|
||||||
none => { break; }
|
None => { break; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
none => { }
|
None => { }
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -168,12 +168,12 @@ impl Node : PrivStyleMethods {
|
||||||
fn update_style(decl : StyleDeclaration) {
|
fn update_style(decl : StyleDeclaration) {
|
||||||
self.aux(|layout| {
|
self.aux(|layout| {
|
||||||
match decl {
|
match decl {
|
||||||
BackgroundColor(col) => layout.specified_style.background_color = some(col),
|
BackgroundColor(col) => layout.specified_style.background_color = Some(col),
|
||||||
Display(dis) => layout.specified_style.display_type = some(dis),
|
Display(dis) => layout.specified_style.display_type = Some(dis),
|
||||||
FontSize(size) => layout.specified_style.font_size = some(size),
|
FontSize(size) => layout.specified_style.font_size = Some(size),
|
||||||
Height(size) => layout.specified_style.height = some(size),
|
Height(size) => layout.specified_style.height = Some(size),
|
||||||
TextColor(col) => layout.specified_style.text_color = some(col),
|
TextColor(col) => layout.specified_style.text_color = Some(col),
|
||||||
Width(size) => layout.specified_style.width = some(size)
|
Width(size) => layout.specified_style.width = Some(size)
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ impl Node : MatchingMethods {
|
||||||
mod test {
|
mod test {
|
||||||
import dom::base::{Attr, HTMLDivElement, HTMLHeadElement, HTMLImageElement};
|
import dom::base::{Attr, HTMLDivElement, HTMLHeadElement, HTMLImageElement};
|
||||||
import dom::base::{NodeScope, UnknownElement};
|
import dom::base::{NodeScope, UnknownElement};
|
||||||
import dvec::dvec;
|
import dvec::DVec;
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
fn new_node_from_attr(scope: NodeScope, -name: ~str, -val: ~str) -> Node {
|
fn new_node_from_attr(scope: NodeScope, -name: ~str, -val: ~str) -> Node {
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
#[doc="High-level interface to CSS selector matching."]
|
#[doc="High-level interface to CSS selector matching."]
|
||||||
|
|
||||||
import std::arc::{arc, get, clone};
|
import std::arc::{ARC, get, clone};
|
||||||
|
|
||||||
import dom::style::{DisplayType, DisBlock, DisInline, DisNone, Stylesheet, Unit, Auto};
|
import dom::style::{DisplayType, DisBlock, DisInline, DisNone, Stylesheet, Unit, Auto};
|
||||||
import dom::base::{Element, HTMLDivElement, HTMLHeadElement, HTMLImageElement, Node, NodeKind};
|
import dom::base::{Element, HTMLDivElement, HTMLHeadElement, HTMLImageElement, Node, NodeKind, UnknownElement, HTMLScriptElement};
|
||||||
import dom::base::{Text};
|
import dom::base::{Text};
|
||||||
import util::color::{Color, rgb};
|
import util::color::{Color, rgb};
|
||||||
import util::color::css_colors::{white, black};
|
import util::color::css_colors::{white, black};
|
||||||
import base::{LayoutData, NTree};
|
import base::{LayoutData, NTree};
|
||||||
|
|
||||||
type SpecifiedStyle = {mut background_color : option<Color>,
|
type SpecifiedStyle = {mut background_color : Option<Color>,
|
||||||
mut display_type : option<DisplayType>,
|
mut display_type : Option<DisplayType>,
|
||||||
mut font_size : option<Unit>,
|
mut font_size : Option<Unit>,
|
||||||
mut height : option<Unit>,
|
mut height : Option<Unit>,
|
||||||
mut text_color : option<Color>,
|
mut text_color : Option<Color>,
|
||||||
mut width : option<Unit>
|
mut width : Option<Unit>
|
||||||
};
|
};
|
||||||
|
|
||||||
trait DefaultStyleMethods {
|
trait DefaultStyleMethods {
|
||||||
|
@ -41,7 +41,8 @@ impl NodeKind : DefaultStyleMethods {
|
||||||
HTMLDivElement => DisBlock,
|
HTMLDivElement => DisBlock,
|
||||||
HTMLHeadElement => DisNone,
|
HTMLHeadElement => DisNone,
|
||||||
HTMLImageElement(*) => DisInline,
|
HTMLImageElement(*) => DisInline,
|
||||||
UnknownElement => DisInline
|
HTMLScriptElement => DisNone,
|
||||||
|
UnknownElement => DisInline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,12 +67,12 @@ impl NodeKind : DefaultStyleMethods {
|
||||||
fn empty_style_for_node_kind(kind: NodeKind) -> SpecifiedStyle {
|
fn empty_style_for_node_kind(kind: NodeKind) -> SpecifiedStyle {
|
||||||
let display_type = kind.default_display_type();
|
let display_type = kind.default_display_type();
|
||||||
|
|
||||||
{mut background_color : none,
|
{mut background_color : None,
|
||||||
mut display_type : some(display_type),
|
mut display_type : Some(display_type),
|
||||||
mut font_size : none,
|
mut font_size : None,
|
||||||
mut height : none,
|
mut height : None,
|
||||||
mut text_color : none,
|
mut text_color : None,
|
||||||
mut width : none}
|
mut width : None}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait StylePriv {
|
trait StylePriv {
|
||||||
|
@ -94,7 +95,7 @@ impl Node : StylePriv {
|
||||||
let node_kind = self.read(|n| copy *n.kind);
|
let node_kind = self.read(|n| copy *n.kind);
|
||||||
let the_layout_data = @LayoutData({
|
let the_layout_data = @LayoutData({
|
||||||
mut specified_style : ~empty_style_for_node_kind(node_kind),
|
mut specified_style : ~empty_style_for_node_kind(node_kind),
|
||||||
mut box : none
|
mut box : None
|
||||||
});
|
});
|
||||||
|
|
||||||
self.set_aux(the_layout_data);
|
self.set_aux(the_layout_data);
|
||||||
|
@ -109,7 +110,7 @@ impl Node : StylePriv {
|
||||||
trait StyleMethods {
|
trait StyleMethods {
|
||||||
fn initialize_style_for_subtree() -> ~[@LayoutData];
|
fn initialize_style_for_subtree() -> ~[@LayoutData];
|
||||||
fn get_specified_style() -> SpecifiedStyle;
|
fn get_specified_style() -> SpecifiedStyle;
|
||||||
fn recompute_style_for_subtree(styles : arc<Stylesheet>);
|
fn recompute_style_for_subtree(styles : ARC<Stylesheet>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node : StyleMethods {
|
impl Node : StyleMethods {
|
||||||
|
@ -143,7 +144,7 @@ impl Node : StyleMethods {
|
||||||
This is, importantly, the function that updates the layout data for the node (the reader-
|
This is, importantly, the function that updates the layout data for the node (the reader-
|
||||||
auxiliary box in the RCU model) with the computed style.
|
auxiliary box in the RCU model) with the computed style.
|
||||||
"]
|
"]
|
||||||
fn recompute_style_for_subtree(styles : arc<Stylesheet>) {
|
fn recompute_style_for_subtree(styles : ARC<Stylesheet>) {
|
||||||
listen(|ack_chan| {
|
listen(|ack_chan| {
|
||||||
let mut i = 0u;
|
let mut i = 0u;
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,11 @@ import base::{Box, TextBoxKind};
|
||||||
|
|
||||||
struct TextBox {
|
struct TextBox {
|
||||||
text: ~str;
|
text: ~str;
|
||||||
mut run: option<TextRun>;
|
mut run: Option<TextRun>;
|
||||||
|
|
||||||
new(-text: ~str) {
|
new(-text: ~str) {
|
||||||
self.text = text;
|
self.text = text;
|
||||||
self.run = none;
|
self.run = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ impl @Box : TextLayout {
|
||||||
let font = flib.get_test_font();
|
let font = flib.get_test_font();
|
||||||
let run = TextRun(*font, subbox.text);
|
let run = TextRun(*font, subbox.text);
|
||||||
self.bounds.size = run.size();
|
self.bounds.size = run.size();
|
||||||
subbox.run = some(run);
|
subbox.run = Some(run);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,10 @@ fn should_calculate_the_size_of_the_text_box() {
|
||||||
let n = s.new_node(Text(~"firecracker"));
|
let n = s.new_node(Text(~"firecracker"));
|
||||||
let b = n.construct_boxes();
|
let b = n.construct_boxes();
|
||||||
|
|
||||||
let subbox = match check b.kind { TextBoxKind(subbox) => { subbox } };
|
let subbox = match b.kind {
|
||||||
|
TextBoxKind(subbox) => { subbox },
|
||||||
|
_ => fail
|
||||||
|
};
|
||||||
b.reflow_text(subbox);
|
b.reflow_text(subbox);
|
||||||
let expected = Size2D(px_to_au(84), px_to_au(20));
|
let expected = Size2D(px_to_au(84), px_to_au(20));
|
||||||
assert b.bounds.size == expected;
|
assert b.bounds.size == expected;
|
||||||
|
|
|
@ -74,11 +74,11 @@ fn traverse_helper<T : copy send>(-root : @Box, returned : T, -top_down : fn~(+T
|
||||||
let unwrapped = unwrap_box(copy kid);
|
let unwrapped = unwrap_box(copy kid);
|
||||||
// Hide the box in an option so we can get it across the
|
// Hide the box in an option so we can get it across the
|
||||||
// task boundary without copying it
|
// task boundary without copying it
|
||||||
let swappable : ~mut option<*shared_box<Box>> = ~mut some(unwrapped);
|
let swappable : ~mut Option<*shared_box<Box>> = ~mut Some(unwrapped);
|
||||||
|
|
||||||
do task::spawn |copy top_down, copy bottom_up| {
|
do task::spawn |copy top_down, copy bottom_up| {
|
||||||
// Get the box out of the option and into the new task
|
// Get the box out of the option and into the new task
|
||||||
let mut swapped_in = none;
|
let mut swapped_in = None;
|
||||||
swapped_in <-> *swappable;
|
swapped_in <-> *swappable;
|
||||||
|
|
||||||
// Retrieve the original @Box and recurse
|
// Retrieve the original @Box and recurse
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
} => {
|
} => {
|
||||||
if $index == $count {
|
if $index == $count {
|
||||||
match move pipes::try_recv($port) {
|
match move pipes::try_recv($port) {
|
||||||
$(some($message($($(ref $x,)+)* ref next)) => {
|
$(Some($message($($(ref $x,)+)* ref next)) => {
|
||||||
// FIXME (#2329) we really want move out of enum here.
|
// FIXME (#2329) we really want move out of enum here.
|
||||||
let $next = move_ref!(next);
|
let $next = move_ref!(next);
|
||||||
$e
|
$e
|
||||||
|
|
|
@ -26,8 +26,8 @@ fn from_cmdline_args(args: ~[~str]) -> Opts {
|
||||||
];
|
];
|
||||||
|
|
||||||
let opt_match = match getopts::getopts(args, opts) {
|
let opt_match = match getopts::getopts(args, opts) {
|
||||||
result::ok(m) => { copy m }
|
result::Ok(m) => { copy m }
|
||||||
result::err(f) => { fail getopts::fail_str(f) }
|
result::Err(f) => { fail getopts::fail_str(f) }
|
||||||
};
|
};
|
||||||
|
|
||||||
let urls = if opt_match.free.is_empty() {
|
let urls = if opt_match.free.is_empty() {
|
||||||
|
@ -37,8 +37,8 @@ fn from_cmdline_args(args: ~[~str]) -> Opts {
|
||||||
};
|
};
|
||||||
|
|
||||||
let render_mode = match getopts::opt_maybe_str(opt_match, ~"o") {
|
let render_mode = match getopts::opt_maybe_str(opt_match, ~"o") {
|
||||||
some(output_file) => { Png(copy output_file) }
|
Some(output_file) => { Png(copy output_file) }
|
||||||
none => { Screen }
|
None => { Screen }
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,7 +17,7 @@ import parser::parser_util::{parse_display_type, parse_font_size, parse_size};
|
||||||
import util::color::parsing::parse_color;
|
import util::color::parsing::parse_color;
|
||||||
import vec::push;
|
import vec::push;
|
||||||
|
|
||||||
type TokenReader = {stream : pipes::port<Token>, mut lookahead : option<Token>};
|
type TokenReader = {stream : pipes::Port<Token>, mut lookahead : Option<Token>};
|
||||||
|
|
||||||
trait TokenReaderMethods {
|
trait TokenReaderMethods {
|
||||||
fn get() -> Token;
|
fn get() -> Token;
|
||||||
|
@ -27,30 +27,30 @@ trait TokenReaderMethods {
|
||||||
impl TokenReader : TokenReaderMethods {
|
impl TokenReader : TokenReaderMethods {
|
||||||
fn get() -> Token {
|
fn get() -> Token {
|
||||||
match copy self.lookahead {
|
match copy self.lookahead {
|
||||||
some(tok) => { self.lookahead = none; copy tok }
|
Some(tok) => { self.lookahead = None; copy tok }
|
||||||
none => { self.stream.recv() }
|
None => { self.stream.recv() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unget(-tok : Token) {
|
fn unget(-tok : Token) {
|
||||||
assert is_none(self.lookahead);
|
assert is_none(self.lookahead);
|
||||||
self.lookahead = some(tok);
|
self.lookahead = Some(tok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ParserMethods {
|
trait ParserMethods {
|
||||||
fn parse_element() -> option<~style::Selector>;
|
fn parse_element() -> Option<~style::Selector>;
|
||||||
fn parse_selector() -> option<~[~Selector]>;
|
fn parse_selector() -> Option<~[~Selector]>;
|
||||||
fn parse_description() -> option<~[StyleDeclaration]>;
|
fn parse_description() -> Option<~[StyleDeclaration]>;
|
||||||
fn parse_rule() -> option<~style::Rule>;
|
fn parse_rule() -> Option<~style::Rule>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenReader : ParserMethods {
|
impl TokenReader : ParserMethods {
|
||||||
fn parse_element() -> option<~style::Selector> {
|
fn parse_element() -> Option<~style::Selector> {
|
||||||
// Get the current element type
|
// Get the current element type
|
||||||
let elmt_name = match self.get() {
|
let elmt_name = match self.get() {
|
||||||
Element(tag) => { copy tag }
|
Element(tag) => { copy tag }
|
||||||
Eof => { return none; }
|
Eof => { return None; }
|
||||||
_ => { fail ~"Expected an element" }
|
_ => { fail ~"Expected an element" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,16 +65,16 @@ impl TokenReader : ParserMethods {
|
||||||
self.unget(tok);
|
self.unget(tok);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Eof => { return none; }
|
Eof => { return None; }
|
||||||
Element(_) => fail ~"Unexpected second element without relation to first element",
|
Element(_) => fail ~"Unexpected second element without relation to first element",
|
||||||
EndDescription => fail ~"Unexpected '}'",
|
EndDescription => fail ~"Unexpected '}'",
|
||||||
Description(_, _) => fail ~"Unexpected description"
|
Description(_, _) => fail ~"Unexpected description"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return some(~style::Element(elmt_name, attr_list));
|
return Some(~style::Element(elmt_name, attr_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_selector() -> option<~[~Selector]> {
|
fn parse_selector() -> Option<~[~Selector]> {
|
||||||
let mut sel_list = ~[];
|
let mut sel_list = ~[];
|
||||||
|
|
||||||
// Collect all the selectors that this rule applies to
|
// Collect all the selectors that this rule applies to
|
||||||
|
@ -82,8 +82,8 @@ impl TokenReader : ParserMethods {
|
||||||
let mut cur_sel;
|
let mut cur_sel;
|
||||||
|
|
||||||
match self.parse_element() {
|
match self.parse_element() {
|
||||||
some(elmt) => { cur_sel = copy elmt; }
|
Some(elmt) => { cur_sel = copy elmt; }
|
||||||
none => { return none; } // we hit an eof in the middle of a rule
|
None => { return None; } // we hit an eof in the middle of a rule
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -93,29 +93,29 @@ impl TokenReader : ParserMethods {
|
||||||
match tok {
|
match tok {
|
||||||
Descendant => {
|
Descendant => {
|
||||||
match self.parse_element() {
|
match self.parse_element() {
|
||||||
some(elmt) => {
|
Some(elmt) => {
|
||||||
let new_sel = copy elmt;
|
let new_sel = copy elmt;
|
||||||
cur_sel <- ~style::Descendant(built_sel, new_sel)
|
cur_sel <- ~style::Descendant(built_sel, new_sel)
|
||||||
}
|
}
|
||||||
none => { return none; }
|
None => { return None; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Child => {
|
Child => {
|
||||||
match self.parse_element() {
|
match self.parse_element() {
|
||||||
some(elmt) => {
|
Some(elmt) => {
|
||||||
let new_sel = copy elmt;
|
let new_sel = copy elmt;
|
||||||
cur_sel <- ~style::Child(built_sel, new_sel)
|
cur_sel <- ~style::Child(built_sel, new_sel)
|
||||||
}
|
}
|
||||||
none => { return none; }
|
None => { return None; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Sibling => {
|
Sibling => {
|
||||||
match self.parse_element() {
|
match self.parse_element() {
|
||||||
some(elmt) => {
|
Some(elmt) => {
|
||||||
let new_sel = copy elmt;
|
let new_sel = copy elmt;
|
||||||
cur_sel <- ~style::Sibling(built_sel, new_sel)
|
cur_sel <- ~style::Sibling(built_sel, new_sel)
|
||||||
}
|
}
|
||||||
none => { return none; }
|
None => { return None; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StartDescription => {
|
StartDescription => {
|
||||||
|
@ -131,7 +131,7 @@ impl TokenReader : ParserMethods {
|
||||||
Attr(_) | EndDescription | Element(_) | Description(_, _) => {
|
Attr(_) | EndDescription | Element(_) | Description(_, _) => {
|
||||||
fail #fmt["Unexpected token %? in elements", tok];
|
fail #fmt["Unexpected token %? in elements", tok];
|
||||||
}
|
}
|
||||||
Eof => { return none; }
|
Eof => { return None; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,10 +145,10 @@ impl TokenReader : ParserMethods {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return some(sel_list);
|
return Some(sel_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_description() -> option<~[StyleDeclaration]> {
|
fn parse_description() -> Option<~[StyleDeclaration]> {
|
||||||
let mut desc_list : ~[StyleDeclaration]= ~[];
|
let mut desc_list : ~[StyleDeclaration]= ~[];
|
||||||
|
|
||||||
// Get the description to be applied to the selector
|
// Get the description to be applied to the selector
|
||||||
|
@ -165,49 +165,49 @@ impl TokenReader : ParserMethods {
|
||||||
~"font-size" => parse_font_size(val).map(|res| FontSize(res)),
|
~"font-size" => parse_font_size(val).map(|res| FontSize(res)),
|
||||||
~"height" => parse_size(val).map(|res| Height(res)),
|
~"height" => parse_size(val).map(|res| Height(res)),
|
||||||
~"width" => parse_size(val).map(|res| Width(res)),
|
~"width" => parse_size(val).map(|res| Width(res)),
|
||||||
_ => { #debug["Recieved unknown style property '%s'", val]; none }
|
_ => { #debug["Recieved unknown style property '%s'", val]; None }
|
||||||
};
|
};
|
||||||
desc.map(|res| push(desc_list, res));
|
desc.map(|res| push(desc_list, res));
|
||||||
}
|
}
|
||||||
Eof => { return none; }
|
Eof => { return None; }
|
||||||
StartDescription | Descendant | Child | Sibling | Comma | Element(_) | Attr(_) => {
|
StartDescription | Descendant | Child | Sibling | Comma | Element(_) | Attr(_) => {
|
||||||
fail #fmt["Unexpected token %? in description", tok];
|
fail #fmt["Unexpected token %? in description", tok];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return some(desc_list);
|
return Some(desc_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_rule() -> option<~style::Rule> {
|
fn parse_rule() -> Option<~style::Rule> {
|
||||||
// TODO: get rid of copies once match move works
|
// TODO: get rid of copies once match move works
|
||||||
let sel_list = match self.parse_selector() {
|
let sel_list = match self.parse_selector() {
|
||||||
some(list) => { copy list }
|
Some(list) => { copy list }
|
||||||
none => { return none; }
|
None => { return None; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#debug("sel_list: %?", sel_list);
|
#debug("sel_list: %?", sel_list);
|
||||||
|
|
||||||
// Get the description to be applied to the selector
|
// Get the description to be applied to the selector
|
||||||
let desc_list = match self.parse_description() {
|
let desc_list = match self.parse_description() {
|
||||||
some(list) => { copy list }
|
Some(list) => { copy list }
|
||||||
none => { return none; }
|
None => { return None; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#debug("desc_list: %?", desc_list);
|
#debug("desc_list: %?", desc_list);
|
||||||
|
|
||||||
return some(~(sel_list, desc_list));
|
return Some(~(sel_list, desc_list));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stylesheet(+stream : pipes::port<Token>) -> ~[~style::Rule] {
|
fn build_stylesheet(+stream : pipes::Port<Token>) -> ~[~style::Rule] {
|
||||||
let mut rule_list = ~[];
|
let mut rule_list = ~[];
|
||||||
let reader = {stream : stream, mut lookahead : none};
|
let reader = {stream : stream, mut lookahead : None};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match reader.parse_rule() {
|
match reader.parse_rule() {
|
||||||
some(rule) => { push(rule_list, copy rule); }
|
Some(rule) => { push(rule_list, copy rule); }
|
||||||
none => { break; }
|
None => { break; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,12 @@ import option::is_none;
|
||||||
import str::from_bytes;
|
import str::from_bytes;
|
||||||
import vec::push;
|
import vec::push;
|
||||||
|
|
||||||
import pipes::{port, chan};
|
import pipes::{Port, Chan};
|
||||||
|
|
||||||
import lexer_util::*;
|
import lexer_util::*;
|
||||||
|
|
||||||
import std::net::url::url;
|
import std::net::url::url;
|
||||||
import resource::resource_task::{ResourceTask, ProgressMsg, Load};
|
import resource::resource_task::{ResourceTask, ProgressMsg, Load};
|
||||||
import result::ok;
|
|
||||||
|
|
||||||
enum ParserState {
|
enum ParserState {
|
||||||
CssElement,
|
CssElement,
|
||||||
|
@ -230,7 +229,7 @@ impl CssLexer : CssLexerMethods {
|
||||||
fn parser(input_port: comm::Port<ProgressMsg>, state : ParserState) -> CssLexer {
|
fn parser(input_port: comm::Port<ProgressMsg>, state : ParserState) -> CssLexer {
|
||||||
return {
|
return {
|
||||||
input_state: {
|
input_state: {
|
||||||
mut lookahead: none,
|
mut lookahead: None,
|
||||||
mut buffer: ~[],
|
mut buffer: ~[],
|
||||||
input_port: input_port,
|
input_port: input_port,
|
||||||
mut eof: false
|
mut eof: false
|
||||||
|
@ -239,12 +238,12 @@ fn parser(input_port: comm::Port<ProgressMsg>, state : ParserState) -> CssLexer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lex_css_from_bytes(+input_port: comm::Port<ProgressMsg>, result_chan : chan<Token>) {
|
fn lex_css_from_bytes(+input_port: comm::Port<ProgressMsg>, result_chan : Chan<Token>) {
|
||||||
let lexer = parser(input_port, CssElement);
|
let lexer = parser(input_port, CssElement);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let token = lexer.parse_css();
|
let token = lexer.parse_css();
|
||||||
let should_break = (token == Eof);
|
let should_break = match token { Eof => true, _ => false };
|
||||||
|
|
||||||
result_chan.send(token);
|
result_chan.send(token);
|
||||||
|
|
||||||
|
@ -254,13 +253,13 @@ fn lex_css_from_bytes(+input_port: comm::Port<ProgressMsg>, result_chan : chan<T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_css_lexer_from_string(-content : ~str) -> pipes::port<Token> {
|
fn spawn_css_lexer_from_string(-content : ~str) -> pipes::Port<Token> {
|
||||||
let (result_chan, result_port) = pipes::stream();
|
let (result_chan, result_port) = pipes::stream();
|
||||||
|
|
||||||
do task::spawn {
|
do task::spawn {
|
||||||
let input_port = comm::port();
|
let input_port = comm::Port();
|
||||||
input_port.send(Payload(str::to_bytes(content)));
|
input_port.send(Payload(str::to_bytes(content)));
|
||||||
input_port.send(Done(ok(())));
|
input_port.send(Done(Ok(())));
|
||||||
|
|
||||||
lex_css_from_bytes(input_port, result_chan);
|
lex_css_from_bytes(input_port, result_chan);
|
||||||
}
|
}
|
||||||
|
@ -269,12 +268,12 @@ fn spawn_css_lexer_from_string(-content : ~str) -> pipes::port<Token> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
fn spawn_css_lexer_task(-url: url, resource_task: ResourceTask) -> pipes::port<Token> {
|
fn spawn_css_lexer_task(-url: url, resource_task: ResourceTask) -> pipes::Port<Token> {
|
||||||
let (result_chan, result_port) = pipes::stream();
|
let (result_chan, result_port) = pipes::stream();
|
||||||
|
|
||||||
do task::spawn || {
|
do task::spawn || {
|
||||||
assert url.path.ends_with(".css");
|
assert url.path.ends_with(".css");
|
||||||
let input_port = port();
|
let input_port = Port();
|
||||||
// TODO: change copy to move once the compiler permits it
|
// TODO: change copy to move once the compiler permits it
|
||||||
resource_task.send(Load(copy url, input_port.chan()));
|
resource_task.send(Load(copy url, input_port.chan()));
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import dom::style::Stylesheet;
|
||||||
import vec::{push, push_all_move, flat_map};
|
import vec::{push, push_all_move, flat_map};
|
||||||
import std::net::url::url;
|
import std::net::url::url;
|
||||||
import resource::resource_task::{ResourceTask, Load, Payload, Done};
|
import resource::resource_task::{ResourceTask, Load, Payload, Done};
|
||||||
import result::{ok, err};
|
|
||||||
import to_str::ToStr;
|
import to_str::ToStr;
|
||||||
|
|
||||||
enum CSSMessage {
|
enum CSSMessage {
|
||||||
|
@ -35,18 +34,18 @@ fn link_up_attribute(scope: NodeScope, node: Node, -key: ~str, -value: ~str) {
|
||||||
match *element.kind {
|
match *element.kind {
|
||||||
HTMLImageElement(img) if key == ~"width" => {
|
HTMLImageElement(img) if key == ~"width" => {
|
||||||
match int::from_str(value) {
|
match int::from_str(value) {
|
||||||
none => {
|
None => {
|
||||||
// Drop on the floor.
|
// Drop on the floor.
|
||||||
}
|
}
|
||||||
some(s) => { img.size.width = geometry::px_to_au(s); }
|
Some(s) => { img.size.width = geometry::px_to_au(s); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HTMLImageElement(img) if key == ~"height" => {
|
HTMLImageElement(img) if key == ~"height" => {
|
||||||
match int::from_str(value) {
|
match int::from_str(value) {
|
||||||
none => {
|
None => {
|
||||||
// Drop on the floor.
|
// Drop on the floor.
|
||||||
}
|
}
|
||||||
some(s) => {
|
Some(s) => {
|
||||||
img.size.height = geometry::px_to_au(s);
|
img.size.height = geometry::px_to_au(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,8 +99,8 @@ fn css_link_listener(to_parent : comm::Chan<Stylesheet>, from_parent : comm::Por
|
||||||
loop {
|
loop {
|
||||||
match from_parent.recv() {
|
match from_parent.recv() {
|
||||||
File(url) => {
|
File(url) => {
|
||||||
let result_port = comm::port();
|
let result_port = comm::Port();
|
||||||
let result_chan = comm::chan(result_port);
|
let result_chan = comm::Chan(result_port);
|
||||||
// TODO: change copy to move once we have match move
|
// TODO: change copy to move once we have match move
|
||||||
let url = copy url;
|
let url = copy url;
|
||||||
task::spawn(|| {
|
task::spawn(|| {
|
||||||
|
@ -131,12 +130,12 @@ fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port
|
||||||
loop {
|
loop {
|
||||||
match from_parent.recv() {
|
match from_parent.recv() {
|
||||||
js_file(url) => {
|
js_file(url) => {
|
||||||
let result_port = comm::port();
|
let result_port = comm::Port();
|
||||||
let result_chan = comm::chan(result_port);
|
let result_chan = comm::Chan(result_port);
|
||||||
// TODO: change copy to move once we have match move
|
// TODO: change copy to move once we have match move
|
||||||
let url = copy url;
|
let url = copy url;
|
||||||
do task::spawn || {
|
do task::spawn || {
|
||||||
let input_port = port();
|
let input_port = Port();
|
||||||
// TODO: change copy to move once we can move into closures
|
// TODO: change copy to move once we can move into closures
|
||||||
resource_task.send(Load(copy url, input_port.chan()));
|
resource_task.send(Load(copy url, input_port.chan()));
|
||||||
|
|
||||||
|
@ -146,11 +145,11 @@ fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port
|
||||||
Payload(data) => {
|
Payload(data) => {
|
||||||
buf += data;
|
buf += data;
|
||||||
}
|
}
|
||||||
Done(ok(*)) => {
|
Done(Ok(*)) => {
|
||||||
result_chan.send(buf);
|
result_chan.send(buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Done(err(*)) => {
|
Done(Err(*)) => {
|
||||||
#error("error loading script %s", url.to_str());
|
#error("error loading script %s", url.to_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,14 +177,14 @@ fn build_dom(scope: NodeScope, stream: comm::Port<Token>, url: url,
|
||||||
// task. After the html sheet has been fully read, the spawned
|
// task. After the html sheet has been fully read, the spawned
|
||||||
// task will collect the results of all linked style data and send
|
// task will collect the results of all linked style data and send
|
||||||
// it along the returned port.
|
// it along the returned port.
|
||||||
let style_port = comm::port();
|
let style_port = comm::Port();
|
||||||
let child_chan = comm::chan(style_port);
|
let child_chan = comm::Chan(style_port);
|
||||||
let style_chan = task::spawn_listener(|child_port| {
|
let style_chan = task::spawn_listener(|child_port| {
|
||||||
css_link_listener(child_chan, child_port, resource_task);
|
css_link_listener(child_chan, child_port, resource_task);
|
||||||
});
|
});
|
||||||
|
|
||||||
let js_port = comm::port();
|
let js_port = comm::Port();
|
||||||
let child_chan = comm::chan(js_port);
|
let child_chan = comm::Chan(js_port);
|
||||||
let js_chan = task::spawn_listener(|child_port| {
|
let js_chan = task::spawn_listener(|child_port| {
|
||||||
js_script_listener(child_chan, child_port, resource_task);
|
js_script_listener(child_chan, child_port, resource_task);
|
||||||
});
|
});
|
||||||
|
@ -216,15 +215,15 @@ fn build_dom(scope: NodeScope, stream: comm::Port<Token>, url: url,
|
||||||
match *n.kind {
|
match *n.kind {
|
||||||
Element(elmt) if elmt.tag_name == ~"link" => {
|
Element(elmt) if elmt.tag_name == ~"link" => {
|
||||||
match elmt.get_attr(~"rel") {
|
match elmt.get_attr(~"rel") {
|
||||||
some(r) if r == ~"stylesheet" => {
|
Some(r) if r == ~"stylesheet" => {
|
||||||
match elmt.get_attr(~"href") {
|
match elmt.get_attr(~"href") {
|
||||||
some(filename) => {
|
Some(filename) => {
|
||||||
#debug["Linking to a css sheet named: %s", filename];
|
#debug["Linking to a css sheet named: %s", filename];
|
||||||
// FIXME: Need to base the new url on the current url
|
// FIXME: Need to base the new url on the current url
|
||||||
let new_url = make_url(filename, some(copy url));
|
let new_url = make_url(filename, Some(copy url));
|
||||||
style_chan.send(File(new_url));
|
style_chan.send(File(new_url));
|
||||||
}
|
}
|
||||||
none => { /* fall through*/ }
|
None => { /* fall through*/ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => { /* fall through*/ }
|
_ => { /* fall through*/ }
|
||||||
|
@ -235,18 +234,18 @@ fn build_dom(scope: NodeScope, stream: comm::Port<Token>, url: url,
|
||||||
});
|
});
|
||||||
cur_node = scope.get_parent(cur_node).get();
|
cur_node = scope.get_parent(cur_node).get();
|
||||||
}
|
}
|
||||||
parser::EndTag(tag_name) => {
|
parser::EndTag(*) => {
|
||||||
// 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| {
|
scope.read(cur_node, |n| {
|
||||||
match *n.kind {
|
match *n.kind {
|
||||||
Element(elmt) if elmt.tag_name == ~"script" => {
|
Element(elmt) if elmt.tag_name == ~"script" => {
|
||||||
match elmt.get_attr(~"src") {
|
match elmt.get_attr(~"src") {
|
||||||
some(filename) => {
|
Some(filename) => {
|
||||||
#debug["Linking to a js script named: %s", filename];
|
#debug["Linking to a js script named: %s", filename];
|
||||||
let new_url = make_url(filename, some(copy url));
|
let new_url = make_url(filename, Some(copy url));
|
||||||
js_chan.send(js_file(new_url));
|
js_chan.send(js_file(new_url));
|
||||||
}
|
}
|
||||||
none => { /* fall through */ }
|
None => { /* fall through */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => { /* fall though */ }
|
_ => { /* fall though */ }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import comm::{Port, Chan, port, chan};
|
import comm::{Port, Chan};
|
||||||
import dom::style;
|
import dom::style;
|
||||||
import option::is_none;
|
import option::is_none;
|
||||||
import str::from_bytes;
|
import str::from_bytes;
|
||||||
|
@ -121,23 +121,23 @@ impl HtmlLexer : HtmlLexerMethods {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eat_until_end_of_comment() {
|
fn eat_until_end_of_comment() {
|
||||||
let mut state = none;
|
let mut state = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.input_state.get() {
|
match self.input_state.get() {
|
||||||
CoeChar(c) => {
|
CoeChar(c) => {
|
||||||
match c {
|
match c {
|
||||||
'-' as u8 if state == none => {
|
'-' as u8 if state == None => {
|
||||||
state = some(~"-")
|
state = Some(~"-")
|
||||||
}
|
}
|
||||||
'-' as u8 if state == some(~"-") => {
|
'-' as u8 if state == Some(~"-") => {
|
||||||
state = some(~"--")
|
state = Some(~"--")
|
||||||
}
|
}
|
||||||
'>' as u8 if state == some(~"--") => {
|
'>' as u8 if state == Some(~"--") => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
state = none
|
state = None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ impl HtmlLexer : HtmlLexerMethods {
|
||||||
fn lexer(+input_port: Port<resource_task::ProgressMsg>, state : ParseState) -> HtmlLexer {
|
fn lexer(+input_port: Port<resource_task::ProgressMsg>, state : ParseState) -> HtmlLexer {
|
||||||
return {
|
return {
|
||||||
input_state: {
|
input_state: {
|
||||||
mut lookahead: none,
|
mut lookahead: None,
|
||||||
mut buffer: ~[],
|
mut buffer: ~[],
|
||||||
input_port: input_port,
|
input_port: input_port,
|
||||||
mut eof: false
|
mut eof: false
|
||||||
|
@ -225,11 +225,11 @@ fn lexer(+input_port: Port<resource_task::ProgressMsg>, state : ParseState) -> H
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
fn spawn_html_lexer_task(-url: url, resource_task: ResourceTask) -> Port<Token> {
|
fn spawn_html_lexer_task(-url: url, resource_task: ResourceTask) -> Port<Token> {
|
||||||
let html_port = port();
|
let html_port = Port();
|
||||||
let html_chan = chan(html_port);
|
let html_chan = Chan(html_port);
|
||||||
|
|
||||||
task::spawn(|| {
|
task::spawn(|| {
|
||||||
let input_port = port();
|
let input_port = Port();
|
||||||
// TODO: change copy to move once we can move into closures
|
// TODO: change copy to move once we can move into closures
|
||||||
resource_task.send(Load(copy url, input_port.chan()));
|
resource_task.send(Load(copy url, input_port.chan()));
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ fn spawn_html_lexer_task(-url: url, resource_task: ResourceTask) -> Port<Token>
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let token = lexer.parse_html();
|
let token = lexer.parse_html();
|
||||||
let should_break = token == Eof;
|
let should_break = match token { Eof => true, _ => false };
|
||||||
html_chan.send(token);
|
html_chan.send(token);
|
||||||
if should_break { break; }
|
if should_break { break; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,9 @@ use JSExitMessage = parser::html_builder::js_exit;
|
||||||
use JSFileMessage = parser::html_builder::js_file;
|
use JSFileMessage = parser::html_builder::js_file;
|
||||||
use JSMessage = parser::html_builder::js_message;
|
use JSMessage = parser::html_builder::js_message;
|
||||||
|
|
||||||
use comm::{chan, port};
|
use comm::{Chan, Port};
|
||||||
use str::from_slice;
|
use str::from_slice;
|
||||||
use unsafe::reinterpret_cast;
|
use unsafe::reinterpret_cast;
|
||||||
use Error = result::err;
|
|
||||||
use OK = result::ok;
|
|
||||||
use Result = result::result;
|
|
||||||
use Url = std::net::url::url;
|
use Url = std::net::url::url;
|
||||||
|
|
||||||
type JSResult = ~[~[u8]];
|
type JSResult = ~[~[u8]];
|
||||||
|
@ -48,8 +45,8 @@ fn css_link_listener(to_parent : comm::Chan<Stylesheet>, from_parent : comm::Por
|
||||||
loop {
|
loop {
|
||||||
match from_parent.recv() {
|
match from_parent.recv() {
|
||||||
CSSFileMessage(url) => {
|
CSSFileMessage(url) => {
|
||||||
let result_port = comm::port();
|
let result_port = comm::Port();
|
||||||
let result_chan = comm::chan(result_port);
|
let result_chan = comm::Chan(result_port);
|
||||||
// TODO: change copy to move once we have match move
|
// TODO: change copy to move once we have match move
|
||||||
let url = copy url;
|
let url = copy url;
|
||||||
task::spawn(|| {
|
task::spawn(|| {
|
||||||
|
@ -79,12 +76,12 @@ fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port
|
||||||
loop {
|
loop {
|
||||||
match from_parent.recv() {
|
match from_parent.recv() {
|
||||||
JSFileMessage(url) => {
|
JSFileMessage(url) => {
|
||||||
let result_port = comm::port();
|
let result_port = comm::Port();
|
||||||
let result_chan = comm::chan(result_port);
|
let result_chan = comm::Chan(result_port);
|
||||||
// TODO: change copy to move once we have match move
|
// TODO: change copy to move once we have match move
|
||||||
let url = copy url;
|
let url = copy url;
|
||||||
do task::spawn || {
|
do task::spawn || {
|
||||||
let input_port = port();
|
let input_port = Port();
|
||||||
// TODO: change copy to move once we can move into closures
|
// TODO: change copy to move once we can move into closures
|
||||||
resource_task.send(Load(copy url, input_port.chan()));
|
resource_task.send(Load(copy url, input_port.chan()));
|
||||||
|
|
||||||
|
@ -94,11 +91,11 @@ fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port
|
||||||
Payload(data) => {
|
Payload(data) => {
|
||||||
buf += data;
|
buf += data;
|
||||||
}
|
}
|
||||||
Done(OK(*)) => {
|
Done(Ok(*)) => {
|
||||||
result_chan.send(buf);
|
result_chan.send(buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Done(Error(*)) => {
|
Done(Err(*)) => {
|
||||||
#error("error loading script %s", url.to_str());
|
#error("error loading script %s", url.to_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,7 +159,7 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
|
||||||
create_doctype: |_doctype| {
|
create_doctype: |_doctype| {
|
||||||
debug!("create doctype");
|
debug!("create doctype");
|
||||||
let new_node = scope.new_node(Element(ElementData(~"doctype", ~UnknownElement)));
|
let new_node = scope.new_node(Element(ElementData(~"doctype", ~UnknownElement)));
|
||||||
reinterpret_cast(new_node)
|
unsafe { reinterpret_cast(new_node) }
|
||||||
},
|
},
|
||||||
create_element: |tag| {
|
create_element: |tag| {
|
||||||
debug!("create element");
|
debug!("create element");
|
||||||
|
@ -177,14 +174,14 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
|
||||||
match *element.kind {
|
match *element.kind {
|
||||||
HTMLImageElement(img) if attribute.name == "width" => {
|
HTMLImageElement(img) if attribute.name == "width" => {
|
||||||
match int::from_str(from_slice(attribute.value)) {
|
match int::from_str(from_slice(attribute.value)) {
|
||||||
none => {} // Drop on the floor.
|
None => {} // Drop on the floor.
|
||||||
some(s) => img.size.width = px_to_au(s)
|
Some(s) => img.size.width = px_to_au(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HTMLImageElement(img) if attribute.name == "height" => {
|
HTMLImageElement(img) if attribute.name == "height" => {
|
||||||
match int::from_str(from_slice(attribute.value)) {
|
match int::from_str(from_slice(attribute.value)) {
|
||||||
none => {} // Drop on the floor.
|
None => {} // Drop on the floor.
|
||||||
some(s) => img.size.height = px_to_au(s)
|
Some(s) => img.size.height = px_to_au(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HTMLDivElement | HTMLImageElement(*) | HTMLHeadElement |
|
HTMLDivElement | HTMLImageElement(*) | HTMLHeadElement |
|
||||||
|
@ -202,9 +199,9 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
|
||||||
match *node_contents.kind {
|
match *node_contents.kind {
|
||||||
Element(element) if element.tag_name == ~"link" => {
|
Element(element) if element.tag_name == ~"link" => {
|
||||||
match (element.get_attr(~"rel"), element.get_attr(~"href")) {
|
match (element.get_attr(~"rel"), element.get_attr(~"href")) {
|
||||||
(some(rel), some(href)) if rel == ~"stylesheet" => {
|
(Some(rel), Some(href)) if rel == ~"stylesheet" => {
|
||||||
debug!("found CSS stylesheet: %s", href);
|
debug!("found CSS stylesheet: %s", href);
|
||||||
css_chan.send(CSSFileMessage(make_url(href, some(copy *url))));
|
css_chan.send(CSSFileMessage(make_url(href, Some(copy *url))));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -213,12 +210,12 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reinterpret_cast(node)
|
unsafe { reinterpret_cast(node) }
|
||||||
},
|
},
|
||||||
create_text: |data| {
|
create_text: |data| {
|
||||||
debug!("create text");
|
debug!("create text");
|
||||||
let new_node = scope.new_node(Text(from_slice(data)));
|
let new_node = scope.new_node(Text(from_slice(data)));
|
||||||
reinterpret_cast(new_node)
|
unsafe { reinterpret_cast(new_node) }
|
||||||
},
|
},
|
||||||
ref_node: |_node| {},
|
ref_node: |_node| {},
|
||||||
unref_node: |_node| {},
|
unref_node: |_node| {},
|
||||||
|
@ -268,12 +265,12 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
|
||||||
match *node_contents.kind {
|
match *node_contents.kind {
|
||||||
Element(element) if element.tag_name == ~"script" => {
|
Element(element) if element.tag_name == ~"script" => {
|
||||||
match element.get_attr(~"src") {
|
match element.get_attr(~"src") {
|
||||||
some(src) => {
|
Some(src) => {
|
||||||
debug!("found script: %s", src);
|
debug!("found script: %s", src);
|
||||||
let new_url = make_url(src, some(copy *url));
|
let new_url = make_url(src, Some(copy *url));
|
||||||
js_chan.send(JSFileMessage(new_url));
|
js_chan.send(JSFileMessage(new_url));
|
||||||
}
|
}
|
||||||
none => {}
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -284,7 +281,7 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
|
||||||
});
|
});
|
||||||
debug!("set tree handler");
|
debug!("set tree handler");
|
||||||
|
|
||||||
let input_port = port();
|
let input_port = Port();
|
||||||
resource_task.send(Load(copy *url, input_port.chan()));
|
resource_task.send(Load(copy *url, input_port.chan()));
|
||||||
debug!("loaded page");
|
debug!("loaded page");
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -11,8 +11,18 @@ enum CharOrEof {
|
||||||
CoeEof
|
CoeEof
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CharOrEof: cmp::Eq {
|
||||||
|
pure fn eq(&&other: CharOrEof) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(CoeChar(a), CoeChar(b)) => a == b,
|
||||||
|
(CoeChar(*), _) | (_, CoeChar(*)) => false,
|
||||||
|
(CoeEof, CoeEof) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type InputState = {
|
type InputState = {
|
||||||
mut lookahead: option<CharOrEof>,
|
mut lookahead: Option<CharOrEof>,
|
||||||
mut buffer: ~[u8],
|
mut buffer: ~[u8],
|
||||||
input_port: Port<ProgressMsg>,
|
input_port: Port<ProgressMsg>,
|
||||||
mut eof: bool
|
mut eof: bool
|
||||||
|
@ -47,12 +57,12 @@ trait InputStateUtil {
|
||||||
impl InputState : InputStateUtil {
|
impl InputState : InputStateUtil {
|
||||||
fn get() -> CharOrEof {
|
fn get() -> CharOrEof {
|
||||||
match copy self.lookahead {
|
match copy self.lookahead {
|
||||||
some(coe) => {
|
Some(coe) => {
|
||||||
let rv = coe;
|
let rv = coe;
|
||||||
self.lookahead = none;
|
self.lookahead = None;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
none => {
|
None => {
|
||||||
/* fall through */
|
/* fall through */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +92,7 @@ impl InputState : InputStateUtil {
|
||||||
|
|
||||||
fn unget(ch: u8) {
|
fn unget(ch: u8) {
|
||||||
assert is_none(self.lookahead);
|
assert is_none(self.lookahead);
|
||||||
self.lookahead = some(CoeChar(ch));
|
self.lookahead = Some(CoeChar(ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_err(err: ~str) -> ! {
|
fn parse_err(err: ~str) -> ! {
|
||||||
|
|
|
@ -9,7 +9,7 @@ export parse_font_size;
|
||||||
export parse_size;
|
export parse_size;
|
||||||
export parse_display_type;
|
export parse_display_type;
|
||||||
|
|
||||||
fn parse_unit(str : ~str) -> option<Unit> {
|
fn parse_unit(str : ~str) -> Option<Unit> {
|
||||||
match str {
|
match str {
|
||||||
s if s.ends_with(~"%") => from_str(str.substr(0, str.len() - 1)).map(|f| Percent(f)),
|
s if s.ends_with(~"%") => from_str(str.substr(0, str.len() - 1)).map(|f| Percent(f)),
|
||||||
s if s.ends_with(~"in") => from_str(str.substr(0, str.len() - 2)).map(|f| Pt(72.0*f)),
|
s if s.ends_with(~"in") => from_str(str.substr(0, str.len() - 2)).map(|f| Pt(72.0*f)),
|
||||||
|
@ -19,44 +19,44 @@ fn parse_unit(str : ~str) -> option<Unit> {
|
||||||
s if s.ends_with(~"pc") => from_str(str.substr(0, str.len() - 2)).map(|f| Pt(12.0*f)),
|
s if s.ends_with(~"pc") => from_str(str.substr(0, str.len() - 2)).map(|f| Pt(12.0*f)),
|
||||||
s if s.ends_with(~"px") => from_str(str.substr(0, str.len() - 2)).map(|f| Px(f)),
|
s if s.ends_with(~"px") => from_str(str.substr(0, str.len() - 2)).map(|f| Px(f)),
|
||||||
s if s.ends_with(~"ex") | s.ends_with(~"em") => fail ~"Em and Ex sizes not yet supported",
|
s if s.ends_with(~"ex") | s.ends_with(~"em") => fail ~"Em and Ex sizes not yet supported",
|
||||||
_ => none,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_font_size(str : ~str) -> option<Unit> {
|
fn parse_font_size(str : ~str) -> Option<Unit> {
|
||||||
// The default pixel size, not sure if this is accurate.
|
// The default pixel size, not sure if this is accurate.
|
||||||
let default = 16.0;
|
let default = 16.0;
|
||||||
|
|
||||||
match str {
|
match str {
|
||||||
~"xx-small" => some(Px(0.6*default)),
|
~"xx-small" => Some(Px(0.6*default)),
|
||||||
~"x-small" => some(Px(0.75*default)),
|
~"x-small" => Some(Px(0.75*default)),
|
||||||
~"small" => some(Px(8.0/9.0*default)),
|
~"small" => Some(Px(8.0/9.0*default)),
|
||||||
~"medium" => some(Px(default)),
|
~"medium" => Some(Px(default)),
|
||||||
~"large" => some(Px(1.2*default)),
|
~"large" => Some(Px(1.2*default)),
|
||||||
~"x-large" => some(Px(1.5*default)),
|
~"x-large" => Some(Px(1.5*default)),
|
||||||
~"xx-large" => some(Px(2.0*default)),
|
~"xx-large" => Some(Px(2.0*default)),
|
||||||
~"smaller" => some(Percent(80.0)),
|
~"smaller" => Some(Percent(80.0)),
|
||||||
~"larger" => some(Percent(125.0)),
|
~"larger" => Some(Percent(125.0)),
|
||||||
~"inherit" => some(Percent(100.0)),
|
~"inherit" => Some(Percent(100.0)),
|
||||||
_ => parse_unit(str),
|
_ => parse_unit(str),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For width / height, and anything else with the same attribute values
|
// For width / height, and anything else with the same attribute values
|
||||||
fn parse_size(str : ~str) -> option<Unit> {
|
fn parse_size(str : ~str) -> Option<Unit> {
|
||||||
match str {
|
match str {
|
||||||
~"auto" => some(Auto),
|
~"auto" => Some(Auto),
|
||||||
~"inherit" => some(Percent(100.0)),
|
~"inherit" => Some(Percent(100.0)),
|
||||||
_ => parse_unit(str),
|
_ => parse_unit(str),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_display_type(str : ~str) -> option<DisplayType> {
|
fn parse_display_type(str : ~str) -> Option<DisplayType> {
|
||||||
match str {
|
match str {
|
||||||
~"inline" => some(DisInline),
|
~"inline" => Some(DisInline),
|
||||||
~"block" => some(DisBlock),
|
~"block" => Some(DisBlock),
|
||||||
~"none" => some(DisNone),
|
~"none" => Some(DisNone),
|
||||||
_ => { #debug["Recieved unknown display value '%s'", str]; none }
|
_ => { #debug["Recieved unknown display value '%s'", str]; None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,13 @@ import azure::cairo;
|
||||||
import azure::cairo::bindgen::*;
|
import azure::cairo::bindgen::*;
|
||||||
import azure::cairo_hl::ImageSurface;
|
import azure::cairo_hl::ImageSurface;
|
||||||
import comm::*;
|
import comm::*;
|
||||||
import dvec::{DVec, dvec};
|
import dvec::DVec;
|
||||||
import azure::cairo::cairo_surface_t;
|
import azure::cairo::cairo_surface_t;
|
||||||
import gfx::compositor::Compositor;
|
import gfx::compositor::Compositor;
|
||||||
import dom::event::{Event, ResizeEvent};
|
import dom::event::{Event, ResizeEvent};
|
||||||
import layers::ImageLayer;
|
import layers::ImageLayer;
|
||||||
import geom::size::Size2D;
|
import geom::size::Size2D;
|
||||||
import std::cmp::fuzzy_eq;
|
import std::cmp::FuzzyEq;
|
||||||
import task::TaskBuilder;
|
import task::TaskBuilder;
|
||||||
import vec::push;
|
import vec::push;
|
||||||
|
|
||||||
|
@ -23,9 +23,9 @@ import pipes::chan;
|
||||||
type OSMain = comm::Chan<Msg>;
|
type OSMain = comm::Chan<Msg>;
|
||||||
|
|
||||||
enum Msg {
|
enum Msg {
|
||||||
BeginDrawing(pipes::chan<DrawTarget>),
|
BeginDrawing(pipes::Chan<DrawTarget>),
|
||||||
Draw(pipes::chan<DrawTarget>, DrawTarget),
|
Draw(pipes::Chan<DrawTarget>, DrawTarget),
|
||||||
AddKeyHandler(pipes::chan<()>),
|
AddKeyHandler(pipes::Chan<()>),
|
||||||
AddEventListener(comm::Chan<Event>),
|
AddEventListener(comm::Chan<Event>),
|
||||||
Exit
|
Exit
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,8 @@ fn OSMain() -> OSMain {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mainloop(po: Port<Msg>) {
|
fn mainloop(po: Port<Msg>) {
|
||||||
let key_handlers: @DVec<pipes::chan<()>> = @dvec();
|
let key_handlers: @DVec<pipes::Chan<()>> = @DVec();
|
||||||
let event_listeners: @DVec<comm::Chan<Event>> = @dvec();
|
let event_listeners: @DVec<comm::Chan<Event>> = @DVec();
|
||||||
|
|
||||||
glut::init();
|
glut::init();
|
||||||
glut::init_display_mode(glut::DOUBLE);
|
glut::init_display_mode(glut::DOUBLE);
|
||||||
|
@ -85,7 +85,7 @@ fn mainloop(po: Port<Msg>) {
|
||||||
let image = @layers::layers::Image(800, 600, layers::layers::ARGB32Format, buffer);
|
let image = @layers::layers::Image(800, 600, layers::layers::ARGB32Format, buffer);
|
||||||
image_layer.set_image(image);
|
image_layer.set_image(image);
|
||||||
}
|
}
|
||||||
exit => {
|
Exit => {
|
||||||
*done = true;
|
*done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,10 +125,10 @@ Implementation to allow the osmain channel to be used as a graphics
|
||||||
compositor for the renderer
|
compositor for the renderer
|
||||||
"]
|
"]
|
||||||
impl OSMain : Compositor {
|
impl OSMain : Compositor {
|
||||||
fn begin_drawing(+next_dt: pipes::chan<DrawTarget>) {
|
fn begin_drawing(+next_dt: pipes::Chan<DrawTarget>) {
|
||||||
self.send(BeginDrawing(next_dt))
|
self.send(BeginDrawing(next_dt))
|
||||||
}
|
}
|
||||||
fn draw(+next_dt: pipes::chan<DrawTarget>, +draw_me: DrawTarget) {
|
fn draw(+next_dt: pipes::Chan<DrawTarget>, +draw_me: DrawTarget) {
|
||||||
self.send(Draw(next_dt, draw_me))
|
self.send(Draw(next_dt, draw_me))
|
||||||
}
|
}
|
||||||
fn add_event_listener(listener: comm::Chan<Event>) {
|
fn add_event_listener(listener: comm::Chan<Event>) {
|
||||||
|
@ -141,7 +141,7 @@ struct SurfaceSet {
|
||||||
mut back: Surface;
|
mut back: Surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lend_surface(surfaces: SurfaceSet, receiver: pipes::chan<DrawTarget>) {
|
fn lend_surface(surfaces: SurfaceSet, receiver: pipes::Chan<DrawTarget>) {
|
||||||
// We are in a position to lend out the surface?
|
// We are in a position to lend out the surface?
|
||||||
assert surfaces.front.have;
|
assert surfaces.front.have;
|
||||||
// Ok then take it
|
// Ok then take it
|
||||||
|
|
|
@ -4,8 +4,7 @@ import comm::Chan;
|
||||||
import task::spawn;
|
import task::spawn;
|
||||||
import resource_task::{ProgressMsg, Payload, Done};
|
import resource_task::{ProgressMsg, Payload, Done};
|
||||||
import std::net::url::url;
|
import std::net::url::url;
|
||||||
import io::file_reader;
|
import io::{file_reader, ReaderUtil};
|
||||||
import result::{result, ok, err};
|
|
||||||
|
|
||||||
const READ_SIZE: uint = 1024;
|
const READ_SIZE: uint = 1024;
|
||||||
|
|
||||||
|
@ -13,16 +12,16 @@ fn factory(+url: url, progress_chan: Chan<ProgressMsg>) {
|
||||||
assert url.scheme == ~"file";
|
assert url.scheme == ~"file";
|
||||||
|
|
||||||
do spawn {
|
do spawn {
|
||||||
match file_reader(url.path) {
|
match file_reader(&Path(url.path)) {
|
||||||
ok(reader) => {
|
Ok(reader) => {
|
||||||
while !reader.eof() {
|
while !reader.eof() {
|
||||||
let data = reader.read_bytes(READ_SIZE);
|
let data = reader.read_bytes(READ_SIZE);
|
||||||
progress_chan.send(Payload(data));
|
progress_chan.send(Payload(data));
|
||||||
}
|
}
|
||||||
progress_chan.send(Done(ok(())));
|
progress_chan.send(Done(Ok(())));
|
||||||
}
|
}
|
||||||
err(*) => {
|
Err(*) => {
|
||||||
progress_chan.send(Done(err(())));
|
progress_chan.send(Done(Err(())));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import task::spawn;
|
||||||
import resource_task::{ProgressMsg, Payload, Done};
|
import resource_task::{ProgressMsg, Payload, Done};
|
||||||
import std::net::url::url;
|
import std::net::url::url;
|
||||||
import http_client::{uv_http_request};
|
import http_client::{uv_http_request};
|
||||||
import result::{ok, err};
|
|
||||||
|
|
||||||
fn factory(+url: url, progress_chan: Chan<ProgressMsg>) {
|
fn factory(+url: url, progress_chan: Chan<ProgressMsg>) {
|
||||||
assert url.scheme == ~"http";
|
assert url.scheme == ~"http";
|
||||||
|
@ -22,20 +21,20 @@ fn factory(+url: url, progress_chan: Chan<ProgressMsg>) {
|
||||||
http_client::Status(*) => { }
|
http_client::Status(*) => { }
|
||||||
http_client::Payload(data) => {
|
http_client::Payload(data) => {
|
||||||
#debug("http_loader: got data from %?", url);
|
#debug("http_loader: got data from %?", url);
|
||||||
let mut crap = none;
|
let mut crap = None;
|
||||||
*data <-> crap;
|
*data <-> crap;
|
||||||
progress_chan.send(Payload(option::unwrap(crap)));
|
progress_chan.send(Payload(option::unwrap(crap)));
|
||||||
}
|
}
|
||||||
http_client::Error(*) => {
|
http_client::Error(*) => {
|
||||||
#debug("http_loader: error loading %?", url);
|
#debug("http_loader: error loading %?", url);
|
||||||
*errored = true;
|
*errored = true;
|
||||||
progress_chan.send(Done(err(())));
|
progress_chan.send(Done(Err(())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !*errored {
|
if !*errored {
|
||||||
progress_chan.send(Done(ok(())));
|
progress_chan.send(Done(Ok(())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,13 @@ export SyncImageCacheTask;
|
||||||
import image::base::{Image, load_from_memory, test_image_bin};
|
import image::base::{Image, load_from_memory, test_image_bin};
|
||||||
import std::net::url::url;
|
import std::net::url::url;
|
||||||
import util::url::{make_url, UrlMap, url_map};
|
import util::url::{make_url, UrlMap, url_map};
|
||||||
import comm::{Chan, Port, chan, port};
|
import comm::{Chan, Port};
|
||||||
import task::{spawn, spawn_listener};
|
import task::{spawn, spawn_listener};
|
||||||
import resource::resource_task;
|
import resource::resource_task;
|
||||||
import resource_task::ResourceTask;
|
import resource_task::ResourceTask;
|
||||||
import std::arc::arc;
|
import std::arc::ARC;
|
||||||
import clone_arc = std::arc::clone;
|
import clone_arc = std::arc::clone;
|
||||||
import std::cell::Cell;
|
import std::cell::Cell;
|
||||||
import result::{result, ok, err};
|
|
||||||
import to_str::ToStr;
|
import to_str::ToStr;
|
||||||
|
|
||||||
enum Msg {
|
enum Msg {
|
||||||
|
@ -23,13 +22,13 @@ enum Msg {
|
||||||
Prefetch(url),
|
Prefetch(url),
|
||||||
|
|
||||||
/// Used be the prefetch tasks to post back image binaries
|
/// Used be the prefetch tasks to post back image binaries
|
||||||
/*priv*/ StorePrefetchedImageData(url, result<Cell<~[u8]>, ()>),
|
/*priv*/ StorePrefetchedImageData(url, Result<Cell<~[u8]>, ()>),
|
||||||
|
|
||||||
/// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage
|
/// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage
|
||||||
Decode(url),
|
Decode(url),
|
||||||
|
|
||||||
/// Used by the decoder tasks to post decoded images back to the cache
|
/// Used by the decoder tasks to post decoded images back to the cache
|
||||||
/*priv*/ StoreImage(url, option<arc<~Image>>),
|
/*priv*/ StoreImage(url, Option<ARC<~Image>>),
|
||||||
|
|
||||||
/// Request an Image object for a URL. If the image is not is not immediately
|
/// Request an Image object for a URL. If the image is not is not immediately
|
||||||
/// available then ImageNotReady is returned.
|
/// available then ImageNotReady is returned.
|
||||||
|
@ -46,14 +45,39 @@ enum Msg {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ImageResponseMsg {
|
enum ImageResponseMsg {
|
||||||
ImageReady(arc<~Image>),
|
ImageReady(ARC<~Image>),
|
||||||
ImageNotReady,
|
ImageNotReady,
|
||||||
ImageFailed
|
ImageFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ImageResponseMsg {
|
||||||
|
pure fn clone() -> ImageResponseMsg {
|
||||||
|
match self {
|
||||||
|
ImageReady(img) => ImageReady(unchecked { clone_arc(&img) }),
|
||||||
|
ImageNotReady => ImageNotReady,
|
||||||
|
ImageFailed => ImageFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImageResponseMsg: cmp::Eq {
|
||||||
|
pure fn eq(&&other: ImageResponseMsg) -> bool {
|
||||||
|
// FIXME: Bad copies
|
||||||
|
match (self.clone(), other.clone()) {
|
||||||
|
(ImageReady(*), ImageReady(*)) => fail ~"unimplemented comparison",
|
||||||
|
(ImageNotReady, ImageNotReady) => true,
|
||||||
|
(ImageFailed, ImageFailed) => true,
|
||||||
|
|
||||||
|
(ImageReady(*), _)
|
||||||
|
| (ImageNotReady, _)
|
||||||
|
| (ImageFailed, _) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ImageCacheTask = Chan<Msg>;
|
type ImageCacheTask = Chan<Msg>;
|
||||||
|
|
||||||
type DecoderFactory = ~fn() -> ~fn(~[u8]) -> option<Image>;
|
type DecoderFactory = ~fn() -> ~fn(~[u8]) -> Option<Image>;
|
||||||
|
|
||||||
fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
||||||
ImageCacheTask_(resource_task, default_decoder_factory)
|
ImageCacheTask_(resource_task, default_decoder_factory)
|
||||||
|
@ -71,7 +95,7 @@ fn ImageCacheTask_(resource_task: ResourceTask, +decoder_factory: DecoderFactory
|
||||||
from_client: from_client,
|
from_client: from_client,
|
||||||
state_map: url_map(),
|
state_map: url_map(),
|
||||||
wait_map: url_map(),
|
wait_map: url_map(),
|
||||||
need_exit: none
|
need_exit: None
|
||||||
}.run();
|
}.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +130,7 @@ struct ImageCache {
|
||||||
state_map: UrlMap<ImageState>;
|
state_map: UrlMap<ImageState>;
|
||||||
/// List of clients waiting on a WaitForImage response
|
/// List of clients waiting on a WaitForImage response
|
||||||
wait_map: UrlMap<@mut ~[Chan<ImageResponseMsg>]>;
|
wait_map: UrlMap<@mut ~[Chan<ImageResponseMsg>]>;
|
||||||
mut need_exit: option<Chan<()>>;
|
mut need_exit: Option<Chan<()>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ImageState {
|
enum ImageState {
|
||||||
|
@ -114,7 +138,7 @@ enum ImageState {
|
||||||
Prefetching(AfterPrefetch),
|
Prefetching(AfterPrefetch),
|
||||||
Prefetched(@Cell<~[u8]>),
|
Prefetched(@Cell<~[u8]>),
|
||||||
Decoding,
|
Decoding,
|
||||||
Decoded(@arc<~Image>),
|
Decoded(@ARC<~Image>),
|
||||||
Failed
|
Failed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,12 +172,12 @@ impl ImageCache {
|
||||||
OnMsg(handler) => msg_handlers += [copy handler],
|
OnMsg(handler) => msg_handlers += [copy handler],
|
||||||
Exit(response) => {
|
Exit(response) => {
|
||||||
assert self.need_exit.is_none();
|
assert self.need_exit.is_none();
|
||||||
self.need_exit = some(response);
|
self.need_exit = Some(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match copy self.need_exit {
|
match copy self.need_exit {
|
||||||
some(response) => {
|
Some(response) => {
|
||||||
// Wait until we have no outstanding requests and subtasks
|
// Wait until we have no outstanding requests and subtasks
|
||||||
// before exiting
|
// before exiting
|
||||||
let mut can_exit = true;
|
let mut can_exit = true;
|
||||||
|
@ -174,15 +198,15 @@ impl ImageCache {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
none => ()
|
None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*priv*/ fn get_state(+url: url) -> ImageState {
|
/*priv*/ fn get_state(+url: url) -> ImageState {
|
||||||
match self.state_map.find(url) {
|
match self.state_map.find(url) {
|
||||||
some(state) => state,
|
Some(state) => state,
|
||||||
none => Init
|
None => Init
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,9 +228,9 @@ impl ImageCache {
|
||||||
let image = load_image_data(copy url, resource_task);
|
let image = load_image_data(copy url, resource_task);
|
||||||
|
|
||||||
let result = if image.is_ok() {
|
let result = if image.is_ok() {
|
||||||
ok(Cell(result::unwrap(image)))
|
Ok(Cell(result::unwrap(image)))
|
||||||
} else {
|
} else {
|
||||||
err(())
|
Err(())
|
||||||
};
|
};
|
||||||
to_cache.send(StorePrefetchedImageData(copy url, result));
|
to_cache.send(StorePrefetchedImageData(copy url, result));
|
||||||
#debug("image_cache_task: ended fetch for %s", (copy url).to_str());
|
#debug("image_cache_task: ended fetch for %s", (copy url).to_str());
|
||||||
|
@ -225,18 +249,19 @@ impl ImageCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*priv*/ fn store_prefetched_image_data(+url: url, data: &result<Cell<~[u8]>, ()>) {
|
/*priv*/ fn store_prefetched_image_data(+url: url, data: &Result<Cell<~[u8]>, ()>) {
|
||||||
match self.get_state(copy url) {
|
match self.get_state(copy url) {
|
||||||
Prefetching(next_step) => {
|
Prefetching(next_step) => {
|
||||||
match *data {
|
match *data {
|
||||||
ok(data_cell) => {
|
Ok(data_cell) => {
|
||||||
let data = data_cell.take();
|
let data = data_cell.take();
|
||||||
self.set_state(copy url, Prefetched(@Cell(data)));
|
self.set_state(copy url, Prefetched(@Cell(data)));
|
||||||
if next_step == DoDecode {
|
match next_step {
|
||||||
self.decode(url);
|
DoDecode => self.decode(url),
|
||||||
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err(*) => {
|
Err(*) => {
|
||||||
self.set_state(copy url, Failed);
|
self.set_state(copy url, Failed);
|
||||||
self.purge_waiters(url, || ImageFailed);
|
self.purge_waiters(url, || ImageFailed);
|
||||||
}
|
}
|
||||||
|
@ -280,9 +305,9 @@ impl ImageCache {
|
||||||
#debug("image_cache_task: started image decode for %s", url.to_str());
|
#debug("image_cache_task: started image decode for %s", url.to_str());
|
||||||
let image = decode(data);
|
let image = decode(data);
|
||||||
let image = if image.is_some() {
|
let image = if image.is_some() {
|
||||||
some(arc(~option::unwrap(image)))
|
Some(ARC(~option::unwrap(image)))
|
||||||
} else {
|
} else {
|
||||||
none
|
None
|
||||||
};
|
};
|
||||||
to_cache.send(StoreImage(copy url, move image));
|
to_cache.send(StoreImage(copy url, move image));
|
||||||
#debug("image_cache_task: ended image decode for %s", url.to_str());
|
#debug("image_cache_task: ended image decode for %s", url.to_str());
|
||||||
|
@ -299,16 +324,16 @@ impl ImageCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*priv*/ fn store_image(+url: url, image: &option<arc<~Image>>) {
|
/*priv*/ fn store_image(+url: url, image: &Option<ARC<~Image>>) {
|
||||||
|
|
||||||
match self.get_state(copy url) {
|
match self.get_state(copy url) {
|
||||||
Decoding => {
|
Decoding => {
|
||||||
match *image {
|
match *image {
|
||||||
some(image) => {
|
Some(image) => {
|
||||||
self.set_state(copy url, Decoded(@clone_arc(&image)));
|
self.set_state(copy url, Decoded(@clone_arc(&image)));
|
||||||
self.purge_waiters(url, || ImageReady(clone_arc(&image)) );
|
self.purge_waiters(url, || ImageReady(clone_arc(&image)) );
|
||||||
}
|
}
|
||||||
none => {
|
None => {
|
||||||
self.set_state(copy url, Failed);
|
self.set_state(copy url, Failed);
|
||||||
self.purge_waiters(url, || ImageFailed );
|
self.purge_waiters(url, || ImageFailed );
|
||||||
}
|
}
|
||||||
|
@ -328,13 +353,13 @@ impl ImageCache {
|
||||||
|
|
||||||
/*priv*/ fn purge_waiters(+url: url, f: fn() -> ImageResponseMsg) {
|
/*priv*/ fn purge_waiters(+url: url, f: fn() -> ImageResponseMsg) {
|
||||||
match self.wait_map.find(copy url) {
|
match self.wait_map.find(copy url) {
|
||||||
some(@waiters) => {
|
Some(@waiters) => {
|
||||||
for waiters.each |response| {
|
for waiters.each |response| {
|
||||||
response.send(f());
|
response.send(f());
|
||||||
}
|
}
|
||||||
self.wait_map.remove(url);
|
self.wait_map.remove(url);
|
||||||
}
|
}
|
||||||
none => ()
|
None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,10 +402,10 @@ impl ImageCache {
|
||||||
| Decoding => {
|
| Decoding => {
|
||||||
// We don't have this image yet
|
// We don't have this image yet
|
||||||
match self.wait_map.find(copy url) {
|
match self.wait_map.find(copy url) {
|
||||||
some(waiters) => {
|
Some(waiters) => {
|
||||||
vec::push(*waiters, response);
|
vec::push(*waiters, response);
|
||||||
}
|
}
|
||||||
none => {
|
None => {
|
||||||
self.wait_map.insert(url, @mut ~[response]);
|
self.wait_map.insert(url, @mut ~[response]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,15 +431,15 @@ trait ImageCacheTaskClient {
|
||||||
impl ImageCacheTask: ImageCacheTaskClient {
|
impl ImageCacheTask: ImageCacheTaskClient {
|
||||||
|
|
||||||
fn exit() {
|
fn exit() {
|
||||||
let response = port();
|
let response = Port();
|
||||||
self.send(Exit(response.chan()));
|
self.send(Exit(response.chan()));
|
||||||
response.recv();
|
response.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_image_data(+url: url, resource_task: ResourceTask) -> result<~[u8], ()> {
|
fn load_image_data(+url: url, resource_task: ResourceTask) -> Result<~[u8], ()> {
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
resource_task.send(resource_task::Load(url, response_port.chan()));
|
resource_task.send(resource_task::Load(url, response_port.chan()));
|
||||||
|
|
||||||
let mut image_data = ~[];
|
let mut image_data = ~[];
|
||||||
|
@ -424,18 +449,18 @@ fn load_image_data(+url: url, resource_task: ResourceTask) -> result<~[u8], ()>
|
||||||
resource_task::Payload(data) => {
|
resource_task::Payload(data) => {
|
||||||
image_data += data;
|
image_data += data;
|
||||||
}
|
}
|
||||||
resource_task::Done(result::ok(*)) => {
|
resource_task::Done(result::Ok(*)) => {
|
||||||
return ok(image_data);
|
return Ok(image_data);
|
||||||
}
|
}
|
||||||
resource_task::Done(result::err(*)) => {
|
resource_task::Done(result::Err(*)) => {
|
||||||
return err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_decoder_factory() -> ~fn(~[u8]) -> option<Image> {
|
fn default_decoder_factory() -> ~fn(~[u8]) -> Option<Image> {
|
||||||
fn~(data: ~[u8]) -> option<Image> { load_from_memory(data) }
|
fn~(data: ~[u8]) -> Option<Image> { load_from_memory(data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -462,7 +487,7 @@ fn should_exit_on_request() {
|
||||||
let mock_resource_task = mock_resource_task(|_response| () );
|
let mock_resource_task = mock_resource_task(|_response| () );
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let _url = make_url(~"file", none);
|
let _url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.exit();
|
image_cache_task.exit();
|
||||||
mock_resource_task.send(resource_task::Exit);
|
mock_resource_task.send(resource_task::Exit);
|
||||||
|
@ -475,25 +500,25 @@ fn should_fail_if_unprefetched_image_is_requested() {
|
||||||
let mock_resource_task = mock_resource_task(|_response| () );
|
let mock_resource_task = mock_resource_task(|_response| () );
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let request = port();
|
let request = Port();
|
||||||
image_cache_task.send(GetImage(url, request.chan()));
|
image_cache_task.send(GetImage(url, request.chan()));
|
||||||
request.recv();
|
request.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_request_url_from_resource_task_on_prefetch() {
|
fn should_request_url_from_resource_task_on_prefetch() {
|
||||||
let url_requested = port();
|
let url_requested = Port();
|
||||||
let url_requested_chan = url_requested.chan();
|
let url_requested_chan = url_requested.chan();
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
url_requested_chan.send(());
|
url_requested_chan.send(());
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url));
|
image_cache_task.send(Prefetch(url));
|
||||||
url_requested.recv();
|
url_requested.recv();
|
||||||
|
@ -509,7 +534,7 @@ fn should_fail_if_requesting_decode_of_an_unprefetched_image() {
|
||||||
let mock_resource_task = mock_resource_task(|_response| () );
|
let mock_resource_task = mock_resource_task(|_response| () );
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Decode(url));
|
image_cache_task.send(Decode(url));
|
||||||
image_cache_task.exit();
|
image_cache_task.exit();
|
||||||
|
@ -520,16 +545,16 @@ fn should_fail_if_requesting_decode_of_an_unprefetched_image() {
|
||||||
fn should_fail_if_requesting_image_before_requesting_decode() {
|
fn should_fail_if_requesting_image_before_requesting_decode() {
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(copy url));
|
image_cache_task.send(Prefetch(copy url));
|
||||||
// no decode message
|
// no decode message
|
||||||
|
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(url, response_port.chan()));
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
|
|
||||||
image_cache_task.exit();
|
image_cache_task.exit();
|
||||||
|
@ -538,16 +563,16 @@ fn should_fail_if_requesting_image_before_requesting_decode() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
|
fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
|
||||||
let url_requested = port();
|
let url_requested = Port();
|
||||||
let url_requested_chan = url_requested.chan();
|
let url_requested_chan = url_requested.chan();
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
url_requested_chan.send(());
|
url_requested_chan.send(());
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(copy url));
|
image_cache_task.send(Prefetch(copy url));
|
||||||
image_cache_task.send(Prefetch(url));
|
image_cache_task.send(Prefetch(url));
|
||||||
|
@ -567,15 +592,15 @@ fn should_return_image_not_ready_if_data_has_not_arrived() {
|
||||||
// the image
|
// the image
|
||||||
wait_port.recv();
|
wait_port.recv();
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(copy url));
|
image_cache_task.send(Prefetch(copy url));
|
||||||
image_cache_task.send(Decode(copy url));
|
image_cache_task.send(Decode(copy url));
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(url, response_port.chan()));
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
assert response_port.recv() == ImageNotReady;
|
assert response_port.recv() == ImageNotReady;
|
||||||
wait_chan.send(());
|
wait_chan.send(());
|
||||||
|
@ -588,13 +613,13 @@ fn should_return_decoded_image_data_if_data_has_arrived() {
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let wait_for_image = port();
|
let wait_for_image = Port();
|
||||||
let wait_for_image_chan = wait_for_image.chan();
|
let wait_for_image_chan = wait_for_image.chan();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
image_cache_task.send(OnMsg(|msg| {
|
||||||
|
@ -610,7 +635,7 @@ fn should_return_decoded_image_data_if_data_has_arrived() {
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_image_chan.recv();
|
wait_for_image_chan.recv();
|
||||||
|
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(url, response_port.chan()));
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageReady(_) => (),
|
ImageReady(_) => (),
|
||||||
|
@ -626,13 +651,13 @@ fn should_return_decoded_image_data_for_multiple_requests() {
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let wait_for_image = port();
|
let wait_for_image = Port();
|
||||||
let wait_for_image_chan = wait_for_image.chan();
|
let wait_for_image_chan = wait_for_image.chan();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
image_cache_task.send(OnMsg(|msg| {
|
||||||
|
@ -649,7 +674,7 @@ fn should_return_decoded_image_data_for_multiple_requests() {
|
||||||
wait_for_image.recv();
|
wait_for_image.recv();
|
||||||
|
|
||||||
for iter::repeat(2) {
|
for iter::repeat(2) {
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(copy url, response_port.chan()));
|
image_cache_task.send(GetImage(copy url, response_port.chan()));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageReady(_) => (),
|
ImageReady(_) => (),
|
||||||
|
@ -664,10 +689,10 @@ fn should_return_decoded_image_data_for_multiple_requests() {
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_request_image_from_resource_task_if_image_is_already_available() {
|
fn should_not_request_image_from_resource_task_if_image_is_already_available() {
|
||||||
|
|
||||||
let image_bin_sent = port();
|
let image_bin_sent = Port();
|
||||||
let image_bin_sent_chan = image_bin_sent.chan();
|
let image_bin_sent_chan = image_bin_sent.chan();
|
||||||
|
|
||||||
let resource_task_exited = port();
|
let resource_task_exited = Port();
|
||||||
let resource_task_exited_chan = resource_task_exited.chan();
|
let resource_task_exited_chan = resource_task_exited.chan();
|
||||||
|
|
||||||
let mock_resource_task = do spawn_listener |from_client| {
|
let mock_resource_task = do spawn_listener |from_client| {
|
||||||
|
@ -679,7 +704,7 @@ fn should_not_request_image_from_resource_task_if_image_is_already_available() {
|
||||||
match from_client.recv() {
|
match from_client.recv() {
|
||||||
resource_task::Load(_, response) => {
|
resource_task::Load(_, response) => {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
image_bin_sent_chan.send(());
|
image_bin_sent_chan.send(());
|
||||||
}
|
}
|
||||||
resource_task::Exit => {
|
resource_task::Exit => {
|
||||||
|
@ -691,7 +716,7 @@ fn should_not_request_image_from_resource_task_if_image_is_already_available() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(copy url));
|
image_cache_task.send(Prefetch(copy url));
|
||||||
|
|
||||||
|
@ -713,10 +738,10 @@ fn should_not_request_image_from_resource_task_if_image_is_already_available() {
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
|
fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
|
||||||
|
|
||||||
let image_bin_sent = port();
|
let image_bin_sent = Port();
|
||||||
let image_bin_sent_chan = image_bin_sent.chan();
|
let image_bin_sent_chan = image_bin_sent.chan();
|
||||||
|
|
||||||
let resource_task_exited = port();
|
let resource_task_exited = Port();
|
||||||
let resource_task_exited_chan = resource_task_exited.chan();
|
let resource_task_exited_chan = resource_task_exited.chan();
|
||||||
|
|
||||||
let mock_resource_task = do spawn_listener |from_client| {
|
let mock_resource_task = do spawn_listener |from_client| {
|
||||||
|
@ -728,7 +753,7 @@ fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
|
||||||
match from_client.recv() {
|
match from_client.recv() {
|
||||||
resource_task::Load(_, response) => {
|
resource_task::Load(_, response) => {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::err(())));
|
response.send(resource_task::Done(result::Err(())));
|
||||||
image_bin_sent_chan.send(());
|
image_bin_sent_chan.send(());
|
||||||
}
|
}
|
||||||
resource_task::Exit => {
|
resource_task::Exit => {
|
||||||
|
@ -740,7 +765,7 @@ fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(copy url));
|
image_cache_task.send(Prefetch(copy url));
|
||||||
image_cache_task.send(Decode(copy url));
|
image_cache_task.send(Decode(copy url));
|
||||||
|
@ -767,13 +792,13 @@ fn should_return_failed_if_image_bin_cannot_be_fetched() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
// ERROR fetching image
|
// ERROR fetching image
|
||||||
response.send(resource_task::Done(result::err(())));
|
response.send(resource_task::Done(result::Err(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let wait_for_prefetech = port();
|
let wait_for_prefetech = Port();
|
||||||
let wait_for_prefetech_chan = wait_for_prefetech.chan();
|
let wait_for_prefetech_chan = wait_for_prefetech.chan();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
image_cache_task.send(OnMsg(|msg| {
|
||||||
|
@ -789,7 +814,7 @@ fn should_return_failed_if_image_bin_cannot_be_fetched() {
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_prefetech.recv();
|
wait_for_prefetech.recv();
|
||||||
|
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(url, response_port.chan()));
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageFailed => (),
|
ImageFailed => (),
|
||||||
|
@ -806,13 +831,13 @@ fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_f
|
||||||
let mock_resource_task = do mock_resource_task |response | {
|
let mock_resource_task = do mock_resource_task |response | {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
// ERROR fetching image
|
// ERROR fetching image
|
||||||
response.send(resource_task::Done(result::err(())));
|
response.send(resource_task::Done(result::Err(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let wait_for_prefetech = port();
|
let wait_for_prefetech = Port();
|
||||||
let wait_for_prefetech_chan = wait_for_prefetech.chan();
|
let wait_for_prefetech_chan = wait_for_prefetech.chan();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
image_cache_task.send(OnMsg(|msg| {
|
||||||
|
@ -828,7 +853,7 @@ fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_f
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_prefetech.recv();
|
wait_for_prefetech.recv();
|
||||||
|
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(copy url, response_port.chan()));
|
image_cache_task.send(GetImage(copy url, response_port.chan()));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageFailed => (),
|
ImageFailed => (),
|
||||||
|
@ -836,7 +861,7 @@ fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_f
|
||||||
}
|
}
|
||||||
|
|
||||||
// And ask again, we should get the same response
|
// And ask again, we should get the same response
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(url, response_port.chan()));
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageFailed => (),
|
ImageFailed => (),
|
||||||
|
@ -854,13 +879,13 @@ fn should_return_not_ready_if_image_is_still_decoding() {
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let wait_to_decode_port_cell = Cell(wait_to_decode_port);
|
let wait_to_decode_port_cell = Cell(wait_to_decode_port);
|
||||||
let decoder_factory = fn~(move wait_to_decode_port_cell) -> ~fn(~[u8]) -> option<Image> {
|
let decoder_factory = fn~(move wait_to_decode_port_cell) -> ~fn(~[u8]) -> Option<Image> {
|
||||||
let wait_to_decode_port = wait_to_decode_port_cell.take();
|
let wait_to_decode_port = wait_to_decode_port_cell.take();
|
||||||
fn~(data: ~[u8], move wait_to_decode_port) -> option<Image> {
|
fn~(data: ~[u8], move wait_to_decode_port) -> Option<Image> {
|
||||||
// Don't decode until after the client requests the image
|
// Don't decode until after the client requests the image
|
||||||
wait_to_decode_port.recv();
|
wait_to_decode_port.recv();
|
||||||
load_from_memory(data)
|
load_from_memory(data)
|
||||||
|
@ -868,9 +893,9 @@ fn should_return_not_ready_if_image_is_still_decoding() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask_(mock_resource_task, decoder_factory);
|
let image_cache_task = ImageCacheTask_(mock_resource_task, decoder_factory);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let wait_for_prefetech = port();
|
let wait_for_prefetech = Port();
|
||||||
let wait_for_prefetech_chan = wait_for_prefetech.chan();
|
let wait_for_prefetech_chan = wait_for_prefetech.chan();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
image_cache_task.send(OnMsg(|msg| {
|
||||||
|
@ -887,7 +912,7 @@ fn should_return_not_ready_if_image_is_still_decoding() {
|
||||||
wait_for_prefetech.recv();
|
wait_for_prefetech.recv();
|
||||||
|
|
||||||
// Make the request
|
// Make the request
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(url, response_port.chan()));
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
|
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
|
@ -908,13 +933,13 @@ fn should_return_failed_if_image_decode_fails() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
// Bogus data
|
// Bogus data
|
||||||
response.send(resource_task::Payload(~[]));
|
response.send(resource_task::Payload(~[]));
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let wait_for_decode = port();
|
let wait_for_decode = Port();
|
||||||
let wait_for_decode_chan = wait_for_decode.chan();
|
let wait_for_decode_chan = wait_for_decode.chan();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
image_cache_task.send(OnMsg(|msg| {
|
||||||
|
@ -931,7 +956,7 @@ fn should_return_failed_if_image_decode_fails() {
|
||||||
wait_for_decode.recv();
|
wait_for_decode.recv();
|
||||||
|
|
||||||
// Make the request
|
// Make the request
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(url, response_port.chan()));
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
|
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
|
@ -948,13 +973,13 @@ fn should_return_image_on_wait_if_image_is_already_loaded() {
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let wait_for_decode = port();
|
let wait_for_decode = Port();
|
||||||
let wait_for_decode_chan = wait_for_decode.chan();
|
let wait_for_decode_chan = wait_for_decode.chan();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
image_cache_task.send(OnMsg(|msg| {
|
||||||
|
@ -970,7 +995,7 @@ fn should_return_image_on_wait_if_image_is_already_loaded() {
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_decode.recv();
|
wait_for_decode.recv();
|
||||||
|
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(WaitForImage(url, response_port.chan()));
|
image_cache_task.send(WaitForImage(url, response_port.chan()));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageReady(*) => (),
|
ImageReady(*) => (),
|
||||||
|
@ -989,16 +1014,16 @@ fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
wait_port.recv();
|
wait_port.recv();
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(copy url));
|
image_cache_task.send(Prefetch(copy url));
|
||||||
image_cache_task.send(Decode(copy url));
|
image_cache_task.send(Decode(copy url));
|
||||||
|
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(WaitForImage(url, response_port.chan()));
|
image_cache_task.send(WaitForImage(url, response_port.chan()));
|
||||||
|
|
||||||
wait_chan.send(());
|
wait_chan.send(());
|
||||||
|
@ -1020,16 +1045,16 @@ fn should_return_image_failed_on_wait_if_image_fails_to_load() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
wait_port.recv();
|
wait_port.recv();
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::err(())));
|
response.send(resource_task::Done(result::Err(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task);
|
let image_cache_task = ImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(copy url));
|
image_cache_task.send(Prefetch(copy url));
|
||||||
image_cache_task.send(Decode(copy url));
|
image_cache_task.send(Decode(copy url));
|
||||||
|
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(WaitForImage(url, response_port.chan()));
|
image_cache_task.send(WaitForImage(url, response_port.chan()));
|
||||||
|
|
||||||
wait_chan.send(());
|
wait_chan.send(());
|
||||||
|
@ -1047,16 +1072,16 @@ fn should_return_image_failed_on_wait_if_image_fails_to_load() {
|
||||||
fn sync_cache_should_wait_for_images() {
|
fn sync_cache_should_wait_for_images() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = do mock_resource_task |response| {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::ok(())));
|
response.send(resource_task::Done(result::Ok(())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_cache_task = SyncImageCacheTask(mock_resource_task);
|
let image_cache_task = SyncImageCacheTask(mock_resource_task);
|
||||||
let url = make_url(~"file", none);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(copy url));
|
image_cache_task.send(Prefetch(copy url));
|
||||||
image_cache_task.send(Decode(copy url));
|
image_cache_task.send(Decode(copy url));
|
||||||
|
|
||||||
let response_port = port();
|
let response_port = Port();
|
||||||
image_cache_task.send(GetImage(url, response_port.chan()));
|
image_cache_task.send(GetImage(url, response_port.chan()));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageReady(_) => (),
|
ImageReady(_) => (),
|
||||||
|
|
|
@ -8,11 +8,10 @@ export ControlMsg, Load, Exit;
|
||||||
export ProgressMsg, Payload, Done;
|
export ProgressMsg, Payload, Done;
|
||||||
export ResourceTask, ResourceManager, LoaderTaskFactory;
|
export ResourceTask, ResourceManager, LoaderTaskFactory;
|
||||||
|
|
||||||
import comm::{Chan, Port, chan, port};
|
import comm::{Chan, Port};
|
||||||
import task::{spawn, spawn_listener};
|
import task::{spawn, spawn_listener};
|
||||||
import std::net::url;
|
import std::net::url;
|
||||||
import std::net::url::url;
|
import std::net::url::url;
|
||||||
import result::{result, ok, err};
|
|
||||||
|
|
||||||
enum ControlMsg {
|
enum ControlMsg {
|
||||||
/// Request the data associated with a particular URL
|
/// Request the data associated with a particular URL
|
||||||
|
@ -25,7 +24,19 @@ enum ProgressMsg {
|
||||||
/// Binary data - there may be multiple of these
|
/// Binary data - there may be multiple of these
|
||||||
Payload(~[u8]),
|
Payload(~[u8]),
|
||||||
/// Indicates loading is complete, either successfully or not
|
/// Indicates loading is complete, either successfully or not
|
||||||
Done(result<(), ()>)
|
Done(Result<(), ()>)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProgressMsg: cmp::Eq {
|
||||||
|
pure fn eq(&&other: ProgressMsg) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Payload(a), Payload(b)) => a == b,
|
||||||
|
(Done(a), Done(b)) => a == b,
|
||||||
|
|
||||||
|
(Payload(*), _)
|
||||||
|
| (Done(*), _) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle to a resource task
|
/// Handle to a resource task
|
||||||
|
@ -81,25 +92,25 @@ struct ResourceManager {
|
||||||
fn load(+url: url, progress_chan: Chan<ProgressMsg>) {
|
fn load(+url: url, progress_chan: Chan<ProgressMsg>) {
|
||||||
|
|
||||||
match self.get_loader_factory(url) {
|
match self.get_loader_factory(url) {
|
||||||
some(loader_factory) => {
|
Some(loader_factory) => {
|
||||||
#debug("resource_task: loading url: %s", url::to_str(url));
|
#debug("resource_task: loading url: %s", url::to_str(url));
|
||||||
loader_factory(url, progress_chan);
|
loader_factory(url, progress_chan);
|
||||||
}
|
}
|
||||||
none => {
|
None => {
|
||||||
#debug("resource_task: no loader for scheme %s", url.scheme);
|
#debug("resource_task: no loader for scheme %s", url.scheme);
|
||||||
progress_chan.send(Done(err(())));
|
progress_chan.send(Done(Err(())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_loader_factory(url: url) -> option<LoaderTaskFactory> {
|
fn get_loader_factory(url: url) -> Option<LoaderTaskFactory> {
|
||||||
for self.loaders.each |scheme_loader| {
|
for self.loaders.each |scheme_loader| {
|
||||||
let (scheme, loader_factory) = copy scheme_loader;
|
let (scheme, loader_factory) = copy scheme_loader;
|
||||||
if scheme == url.scheme {
|
if scheme == url.scheme {
|
||||||
return some(loader_factory);
|
return Some(loader_factory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return none;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,10 +124,11 @@ fn test_exit() {
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
fn test_bad_scheme() {
|
fn test_bad_scheme() {
|
||||||
let resource_task = ResourceTask();
|
let resource_task = ResourceTask();
|
||||||
let progress = port();
|
let progress = Port();
|
||||||
resource_task.send(Load(url::from_str(~"bogus://whatever").get(), progress.chan()));
|
resource_task.send(Load(url::from_str(~"bogus://whatever").get(), progress.chan()));
|
||||||
match check progress.recv() {
|
match progress.recv() {
|
||||||
Done(result) => { assert result.is_err() }
|
Done(result) => { assert result.is_err() }
|
||||||
|
_ => fail
|
||||||
}
|
}
|
||||||
resource_task.send(Exit);
|
resource_task.send(Exit);
|
||||||
}
|
}
|
||||||
|
@ -127,13 +139,13 @@ fn should_delegate_to_scheme_loader() {
|
||||||
let payload = ~[1, 2, 3];
|
let payload = ~[1, 2, 3];
|
||||||
let loader_factory = fn~(+_url: url, progress_chan: Chan<ProgressMsg>, copy payload) {
|
let loader_factory = fn~(+_url: url, progress_chan: Chan<ProgressMsg>, copy payload) {
|
||||||
progress_chan.send(Payload(copy payload));
|
progress_chan.send(Payload(copy payload));
|
||||||
progress_chan.send(Done(ok(())));
|
progress_chan.send(Done(Ok(())));
|
||||||
};
|
};
|
||||||
let loader_factories = ~[(~"snicklefritz", loader_factory)];
|
let loader_factories = ~[(~"snicklefritz", loader_factory)];
|
||||||
let resource_task = create_resource_task_with_loaders(loader_factories);
|
let resource_task = create_resource_task_with_loaders(loader_factories);
|
||||||
let progress = port();
|
let progress = Port();
|
||||||
resource_task.send(Load(url::from_str(~"snicklefritz://heya").get(), progress.chan()));
|
resource_task.send(Load(url::from_str(~"snicklefritz://heya").get(), progress.chan()));
|
||||||
assert progress.recv() == Payload(payload);
|
assert progress.recv() == Payload(payload);
|
||||||
assert progress.recv() == Done(ok(()));
|
assert progress.recv() == Done(Ok(()));
|
||||||
resource_task.send(Exit);
|
resource_task.send(Exit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import engine::{EngineTask, EngineProto};
|
||||||
import url_to_str = std::net::url::to_str;
|
import url_to_str = std::net::url::to_str;
|
||||||
import util::url::make_url;
|
import util::url::make_url;
|
||||||
|
|
||||||
import pipes::{port, chan};
|
import pipes::{Port, Chan};
|
||||||
|
|
||||||
fn main(args: ~[~str]) {
|
fn main(args: ~[~str]) {
|
||||||
run(opts::from_cmdline_args(args))
|
run(opts::from_cmdline_args(args))
|
||||||
|
@ -38,19 +38,19 @@ fn run_pipeline_screen(urls: ~[~str]) {
|
||||||
osmain.send(AddKeyHandler(keypress_to_engine));
|
osmain.send(AddKeyHandler(keypress_to_engine));
|
||||||
|
|
||||||
// Create a serve instance
|
// Create a serve instance
|
||||||
let mut engine_task = some(EngineTask(osmain));
|
let mut engine_task = Some(EngineTask(osmain));
|
||||||
|
|
||||||
for urls.each |filename| {
|
for urls.each |filename| {
|
||||||
let url = make_url(filename, none);
|
let url = make_url(filename, None);
|
||||||
#debug["master: Sending url `%s`", url_to_str(url)];
|
#debug["master: Sending url `%s`", url_to_str(url)];
|
||||||
engine_task =
|
engine_task =
|
||||||
some(EngineProto::client::LoadURL(swap_unwrap(&mut engine_task),
|
Some(EngineProto::client::LoadURL(swap_unwrap(&mut engine_task),
|
||||||
url));
|
url));
|
||||||
#debug["master: Waiting for keypress"];
|
#debug["master: Waiting for keypress"];
|
||||||
|
|
||||||
match keypress_from_osmain.try_recv() {
|
match keypress_from_osmain.try_recv() {
|
||||||
some(*) => { }
|
Some(*) => { }
|
||||||
none => { #error("keypress stream closed unexpectedly") }
|
None => { #error("keypress stream closed unexpectedly") }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,6 @@ fn run_pipeline_png(-url: ~str, outfile: ~str) {
|
||||||
// Use a PNG encoder as the graphics compositor
|
// Use a PNG encoder as the graphics compositor
|
||||||
import gfx::png_compositor;
|
import gfx::png_compositor;
|
||||||
import png_compositor::PngCompositor;
|
import png_compositor::PngCompositor;
|
||||||
import result::{ok, err};
|
|
||||||
import io::{Writer, buffered_file_writer};
|
import io::{Writer, buffered_file_writer};
|
||||||
import resource::resource_task::ResourceTask;
|
import resource::resource_task::ResourceTask;
|
||||||
import resource::image_cache_task::SyncImageCacheTask;
|
import resource::image_cache_task::SyncImageCacheTask;
|
||||||
|
@ -81,11 +80,11 @@ fn run_pipeline_png(-url: ~str, outfile: ~str) {
|
||||||
// render
|
// render
|
||||||
let image_cache_task = SyncImageCacheTask(resource_task);
|
let image_cache_task = SyncImageCacheTask(resource_task);
|
||||||
let engine_task = EngineTask_(compositor, resource_task, image_cache_task);
|
let engine_task = EngineTask_(compositor, resource_task, image_cache_task);
|
||||||
let engine_task = EngineProto::client::LoadURL(engine_task, make_url(url, none));
|
let engine_task = EngineProto::client::LoadURL(engine_task, make_url(url, None));
|
||||||
|
|
||||||
match buffered_file_writer(outfile) {
|
match buffered_file_writer(&Path(outfile)) {
|
||||||
ok(writer) => writer.write(pngdata_from_compositor.recv()),
|
Ok(writer) => writer.write(pngdata_from_compositor.recv()),
|
||||||
err(e) => fail e
|
Err(e) => fail e
|
||||||
}
|
}
|
||||||
|
|
||||||
let engine_task = EngineProto::client::Exit(engine_task);
|
let engine_task = EngineProto::client::Exit(engine_task);
|
||||||
|
|
|
@ -24,14 +24,14 @@ struct Font {
|
||||||
self.fontbuf
|
self.fontbuf
|
||||||
}
|
}
|
||||||
|
|
||||||
fn glyph_index(codepoint: char) -> option<GlyphIndex> {
|
fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
|
||||||
self.native_font.glyph_index(codepoint)
|
self.native_font.glyph_index(codepoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn glyph_h_advance(glyph: GlyphIndex) -> int {
|
fn glyph_h_advance(glyph: GlyphIndex) -> int {
|
||||||
match self.native_font.glyph_h_advance(glyph) {
|
match self.native_font.glyph_h_advance(glyph) {
|
||||||
some(adv) => adv,
|
Some(adv) => adv,
|
||||||
none => /* FIXME: Need fallback strategy */ 10
|
None => /* FIXME: Need fallback strategy */ 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ fn should_get_glyph_indexes() {
|
||||||
let lib = FontLibrary();
|
let lib = FontLibrary();
|
||||||
let font = lib.get_test_font();
|
let font = lib.get_test_font();
|
||||||
let glyph_idx = font.glyph_index('w');
|
let glyph_idx = font.glyph_index('w');
|
||||||
assert glyph_idx == some(40u);
|
assert glyph_idx == Some(40u);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_get_glyph_advance() {
|
fn should_get_glyph_advance() {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
export FontLibrary, native;
|
export FontLibrary, native;
|
||||||
|
|
||||||
import font::{Font, test_font_bin};
|
import font::{Font, test_font_bin};
|
||||||
import result::{result, ok, err};
|
|
||||||
|
|
||||||
struct FontLibrary {
|
struct FontLibrary {
|
||||||
let native_lib: native::NativeFontLibrary;
|
let native_lib: native::NativeFontLibrary;
|
||||||
|
@ -16,8 +15,8 @@ struct FontLibrary {
|
||||||
|
|
||||||
fn get_font() -> @Font {
|
fn get_font() -> @Font {
|
||||||
match create_font(&self.native_lib) {
|
match create_font(&self.native_lib) {
|
||||||
ok(font) => font,
|
Ok(font) => font,
|
||||||
err(*) => /* FIXME */ fail
|
Err(*) => /* FIXME */ fail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,15 +26,15 @@ struct FontLibrary {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn create_font(native_lib: &native::NativeFontLibrary) -> result<@Font, ()> {
|
fn create_font(native_lib: &native::NativeFontLibrary) -> Result<@Font, ()> {
|
||||||
let font_bin = test_font_bin();
|
let font_bin = test_font_bin();
|
||||||
let native_font = native_font::create(native_lib, &font_bin);
|
let native_font = native_font::create(native_lib, &font_bin);
|
||||||
let native_font = if native_font.is_ok() {
|
let native_font = if native_font.is_ok() {
|
||||||
result::unwrap(native_font)
|
result::unwrap(native_font)
|
||||||
} else {
|
} else {
|
||||||
return err(native_font.get_err());
|
return Err(native_font.get_err());
|
||||||
};
|
};
|
||||||
return ok(@Font(font_bin, native_font));
|
return Ok(@Font(font_bin, native_font));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
|
|
@ -9,7 +9,6 @@ font resources needed by the graphics layer to draw glyphs.
|
||||||
|
|
||||||
export NativeFont, create;
|
export NativeFont, create;
|
||||||
|
|
||||||
import result::result;
|
|
||||||
import font_library::native::NativeFontLibrary;
|
import font_library::native::NativeFontLibrary;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
@ -19,12 +18,12 @@ type NativeFont/& = quartz_native_font::QuartzNativeFont;
|
||||||
type NativeFont/& = ft_native_font::FreeTypeNativeFont;
|
type NativeFont/& = ft_native_font::FreeTypeNativeFont;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
fn create(_native_lib: &NativeFontLibrary, buf: &~[u8]) -> result<NativeFont, ()> {
|
fn create(_native_lib: &NativeFontLibrary, buf: &~[u8]) -> Result<NativeFont, ()> {
|
||||||
quartz_native_font::create(buf)
|
quartz_native_font::create(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
fn create(native_lib: &NativeFontLibrary, buf: &~[u8]) -> result<NativeFont, ()> {
|
fn create(native_lib: &NativeFontLibrary, buf: &~[u8]) -> Result<NativeFont, ()> {
|
||||||
ft_native_font::create(*native_lib, buf)
|
ft_native_font::create(*native_lib, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ fn with_test_native_font(f: fn@(nf: &NativeFont)) {
|
||||||
fn should_get_glyph_indexes() {
|
fn should_get_glyph_indexes() {
|
||||||
with_test_native_font(|font| {
|
with_test_native_font(|font| {
|
||||||
let idx = font.glyph_index('w');
|
let idx = font.glyph_index('w');
|
||||||
assert idx == some(40u);
|
assert idx == Some(40u);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ fn should_get_glyph_indexes() {
|
||||||
fn should_return_none_glyph_index_for_bad_codepoints() {
|
fn should_return_none_glyph_index_for_bad_codepoints() {
|
||||||
with_test_native_font(|font| {
|
with_test_native_font(|font| {
|
||||||
let idx = font.glyph_index(0 as char);
|
let idx = font.glyph_index(0 as char);
|
||||||
assert idx == none;
|
assert idx == None;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +60,7 @@ fn should_return_none_glyph_index_for_bad_codepoints() {
|
||||||
fn should_get_glyph_h_advance() {
|
fn should_get_glyph_h_advance() {
|
||||||
with_test_native_font(|font| {
|
with_test_native_font(|font| {
|
||||||
let adv = font.glyph_h_advance(40u);
|
let adv = font.glyph_h_advance(40u);
|
||||||
assert adv == some(15);
|
assert adv == Some(15);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +69,6 @@ fn should_get_glyph_h_advance() {
|
||||||
fn should_return_none_glyph_h_advance_for_bad_codepoints() {
|
fn should_return_none_glyph_h_advance_for_bad_codepoints() {
|
||||||
with_test_native_font(|font| {
|
with_test_native_font(|font| {
|
||||||
let adv = font.glyph_h_advance(-1 as uint);
|
let adv = font.glyph_h_advance(-1 as uint);
|
||||||
assert adv == none;
|
assert adv == None;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
export FreeTypeNativeFont, with_test_native_font, create;
|
export FreeTypeNativeFont, with_test_native_font, create;
|
||||||
|
|
||||||
import vec_as_buf = vec::as_buf;
|
import vec_as_buf = vec::as_buf;
|
||||||
import result::{result, ok, err};
|
|
||||||
import ptr::{addr_of, null};
|
import ptr::{addr_of, null};
|
||||||
import unsafe::reinterpret_cast;
|
import unsafe::reinterpret_cast;
|
||||||
import glyph::GlyphIndex;
|
import glyph::GlyphIndex;
|
||||||
|
@ -32,19 +31,19 @@ struct FreeTypeNativeFont/& {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn glyph_index(codepoint: char) -> option<GlyphIndex> {
|
fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
|
||||||
assert self.face.is_not_null();
|
assert self.face.is_not_null();
|
||||||
let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
|
let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
|
||||||
return if idx != 0 as FT_UInt {
|
return if idx != 0 as FT_UInt {
|
||||||
some(idx as GlyphIndex)
|
Some(idx as GlyphIndex)
|
||||||
} else {
|
} else {
|
||||||
#warn("Invalid codepoint: %?", codepoint);
|
#warn("Invalid codepoint: %?", codepoint);
|
||||||
none
|
None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: What unit is this returning? Let's have a custom type
|
// FIXME: What unit is this returning? Let's have a custom type
|
||||||
fn glyph_h_advance(glyph: GlyphIndex) -> option<int> {
|
fn glyph_h_advance(glyph: GlyphIndex) -> Option<int> {
|
||||||
assert self.face.is_not_null();
|
assert self.face.is_not_null();
|
||||||
let res = FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
|
let res = FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
|
||||||
if res.succeeded() {
|
if res.succeeded() {
|
||||||
|
@ -56,16 +55,16 @@ struct FreeTypeNativeFont/& {
|
||||||
#debug("h_advance for %? is %?", glyph, advance);
|
#debug("h_advance for %? is %?", glyph, advance);
|
||||||
// FIXME: Dividing by 64 converts to pixels, which
|
// FIXME: Dividing by 64 converts to pixels, which
|
||||||
// is not the unit we should be using
|
// is not the unit we should be using
|
||||||
return some((advance / 64) as int);
|
return Some((advance / 64) as int);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#warn("Unable to load glyph %?. reason: %?", glyph, res);
|
#warn("Unable to load glyph %?. reason: %?", glyph, res);
|
||||||
return none;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(lib: FT_Library, buf: &~[u8]) -> result<FreeTypeNativeFont, ()> {
|
fn create(lib: FT_Library, buf: &~[u8]) -> Result<FreeTypeNativeFont, ()> {
|
||||||
assert lib.is_not_null();
|
assert lib.is_not_null();
|
||||||
let face: FT_Face = null();
|
let face: FT_Face = null();
|
||||||
return vec_as_buf(*buf, |cbuf, _len| {
|
return vec_as_buf(*buf, |cbuf, _len| {
|
||||||
|
@ -74,9 +73,9 @@ fn create(lib: FT_Library, buf: &~[u8]) -> result<FreeTypeNativeFont, ()> {
|
||||||
// FIXME: These values are placeholders
|
// FIXME: These values are placeholders
|
||||||
let res = FT_Set_Char_Size(face, 0, 20*64, 0, 72);
|
let res = FT_Set_Char_Size(face, 0, 20*64, 0, 72);
|
||||||
if !res.succeeded() { fail ~"unable to set font char size" }
|
if !res.succeeded() { fail ~"unable to set font char size" }
|
||||||
ok(FreeTypeNativeFont(face))
|
Ok(FreeTypeNativeFont(face))
|
||||||
} else {
|
} else {
|
||||||
err(())
|
Err(())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,11 +113,11 @@ extern fn glyph_func(_font: *hb_font_t,
|
||||||
assert font.is_not_null();
|
assert font.is_not_null();
|
||||||
|
|
||||||
return match (*font).glyph_index(unicode as char) {
|
return match (*font).glyph_index(unicode as char) {
|
||||||
some(g) => {
|
Some(g) => {
|
||||||
*glyph = g as hb_codepoint_t;
|
*glyph = g as hb_codepoint_t;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
none => {
|
None => {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
} as hb_bool_t;
|
} as hb_bool_t;
|
||||||
|
|
|
@ -66,13 +66,13 @@ impl Color {
|
||||||
mod parsing {
|
mod parsing {
|
||||||
export parse_color;
|
export parse_color;
|
||||||
|
|
||||||
fn fail_unrecognized(col : ~str) -> option<Color> {
|
fn fail_unrecognized(col : ~str) -> Option<Color> {
|
||||||
#warn["Unrecognized color %s", col];
|
#warn["Unrecognized color %s", col];
|
||||||
return none;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc="Match an exact color keyword."]
|
#[doc="Match an exact color keyword."]
|
||||||
fn parse_by_name(color : ~str) -> option<Color> {
|
fn parse_by_name(color : ~str) -> Option<Color> {
|
||||||
let col = match color.to_lower() {
|
let col = match color.to_lower() {
|
||||||
~"black" => black(),
|
~"black" => black(),
|
||||||
~"silver" => silver(),
|
~"silver" => silver(),
|
||||||
|
@ -94,11 +94,11 @@ mod parsing {
|
||||||
_ => return fail_unrecognized(color)
|
_ => return fail_unrecognized(color)
|
||||||
};
|
};
|
||||||
|
|
||||||
return some(col);
|
return Some(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc="Parses a color specification in the form rgb(foo,bar,baz)"]
|
#[doc="Parses a color specification in the form rgb(foo,bar,baz)"]
|
||||||
fn parse_rgb(color : ~str) -> option<Color> {
|
fn parse_rgb(color : ~str) -> Option<Color> {
|
||||||
// Shave off the rgb( and the )
|
// Shave off the rgb( and the )
|
||||||
let only_colors = color.substr(4u, color.len() - 5u);
|
let only_colors = color.substr(4u, color.len() - 5u);
|
||||||
|
|
||||||
|
@ -108,13 +108,13 @@ mod parsing {
|
||||||
|
|
||||||
match (u8::from_str(cols[0]), u8::from_str(cols[1]),
|
match (u8::from_str(cols[0]), u8::from_str(cols[1]),
|
||||||
u8::from_str(cols[2])) {
|
u8::from_str(cols[2])) {
|
||||||
(some(r), some(g), some(b)) => { some(rgb(r, g, b)) }
|
(Some(r), Some(g), Some(b)) => { Some(rgb(r, g, b)) }
|
||||||
_ => { fail_unrecognized(color) }
|
_ => { fail_unrecognized(color) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc="Parses a color specification in the form rgba(foo,bar,baz,qux)"]
|
#[doc="Parses a color specification in the form rgba(foo,bar,baz,qux)"]
|
||||||
fn parse_rgba(color : ~str) -> option<Color> {
|
fn parse_rgba(color : ~str) -> Option<Color> {
|
||||||
// Shave off the rgba( and the )
|
// Shave off the rgba( and the )
|
||||||
let only_vals = color.substr(5u, color.len() - 6u);
|
let only_vals = color.substr(5u, color.len() - 6u);
|
||||||
|
|
||||||
|
@ -124,13 +124,13 @@ mod parsing {
|
||||||
|
|
||||||
match (u8::from_str(cols[0]), u8::from_str(cols[1]),
|
match (u8::from_str(cols[0]), u8::from_str(cols[1]),
|
||||||
u8::from_str(cols[2]), float::from_str(cols[3])) {
|
u8::from_str(cols[2]), float::from_str(cols[3])) {
|
||||||
(some(r), some(g), some(b), some(a)) => { some(rgba(r, g, b, a)) }
|
(Some(r), Some(g), Some(b), Some(a)) => { Some(rgba(r, g, b, a)) }
|
||||||
_ => { fail_unrecognized(color) }
|
_ => { fail_unrecognized(color) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc="Parses a color specification in the form hsl(foo,bar,baz)"]
|
#[doc="Parses a color specification in the form hsl(foo,bar,baz)"]
|
||||||
fn parse_hsl(color : ~str) -> option<Color> {
|
fn parse_hsl(color : ~str) -> Option<Color> {
|
||||||
// Shave off the hsl( and the )
|
// Shave off the hsl( and the )
|
||||||
let only_vals = color.substr(4u, color.len() - 5u);
|
let only_vals = color.substr(4u, color.len() - 5u);
|
||||||
|
|
||||||
|
@ -140,13 +140,13 @@ mod parsing {
|
||||||
|
|
||||||
match (float::from_str(vals[0]), float::from_str(vals[1]),
|
match (float::from_str(vals[0]), float::from_str(vals[1]),
|
||||||
float::from_str(vals[2])) {
|
float::from_str(vals[2])) {
|
||||||
(some(h), some(s), some(l)) => { some(hsl(h, s, l)) }
|
(Some(h), Some(s), Some(l)) => { Some(hsl(h, s, l)) }
|
||||||
_ => { fail_unrecognized(color) }
|
_ => { fail_unrecognized(color) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc="Parses a color specification in the form hsla(foo,bar,baz,qux)"]
|
#[doc="Parses a color specification in the form hsla(foo,bar,baz,qux)"]
|
||||||
fn parse_hsla(color : ~str) -> option<Color> {
|
fn parse_hsla(color : ~str) -> Option<Color> {
|
||||||
// Shave off the hsla( and the )
|
// Shave off the hsla( and the )
|
||||||
let only_vals = color.substr(5u, color.len() - 6u);
|
let only_vals = color.substr(5u, color.len() - 6u);
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ mod parsing {
|
||||||
|
|
||||||
match (float::from_str(vals[0]), float::from_str(vals[1]),
|
match (float::from_str(vals[0]), float::from_str(vals[1]),
|
||||||
float::from_str(vals[2]), float::from_str(vals[3])) {
|
float::from_str(vals[2]), float::from_str(vals[3])) {
|
||||||
(some(h), some(s), some(l), some(a)) => { some(hsla(h, s, l, a)) }
|
(Some(h), Some(s), Some(l), Some(a)) => { Some(hsla(h, s, l, a)) }
|
||||||
_ => { fail_unrecognized(color) }
|
_ => { fail_unrecognized(color) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ mod parsing {
|
||||||
// Currently colors are supported in rgb(a,b,c) form and also by
|
// Currently colors are supported in rgb(a,b,c) form and also by
|
||||||
// keywords for several common colors.
|
// keywords for several common colors.
|
||||||
// TODO: extend this
|
// TODO: extend this
|
||||||
fn parse_color(color : ~str) -> option<Color> {
|
fn parse_color(color : ~str) -> Option<Color> {
|
||||||
match color {
|
match color {
|
||||||
c if c.starts_with(~"rgb(") => parse_rgb(c),
|
c if c.starts_with(~"rgb(") => parse_rgb(c),
|
||||||
c if c.starts_with(~"rgba(") => parse_rgba(c),
|
c if c.starts_with(~"rgba(") => parse_rgba(c),
|
||||||
|
@ -198,7 +198,7 @@ mod test {
|
||||||
assert navy().eq(unwrap(parse_color(~"NAVY")));
|
assert navy().eq(unwrap(parse_color(~"NAVY")));
|
||||||
assert teal().eq(unwrap(parse_color(~"Teal")));
|
assert teal().eq(unwrap(parse_color(~"Teal")));
|
||||||
assert aqua().eq(unwrap(parse_color(~"Aqua")));
|
assert aqua().eq(unwrap(parse_color(~"Aqua")));
|
||||||
assert none == parse_color(~"foobarbaz");
|
assert None == parse_color(~"foobarbaz");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -210,7 +210,7 @@ mod test {
|
||||||
assert rgb(1u8,2u8,3u8).eq(unwrap(parse_color(~"rgb(1,2,03)")));
|
assert rgb(1u8,2u8,3u8).eq(unwrap(parse_color(~"rgb(1,2,03)")));
|
||||||
assert rgba(15u8,250u8,3u8,0.5).eq(unwrap(parse_color(~"rgba(15,250,3,.5)")));
|
assert rgba(15u8,250u8,3u8,0.5).eq(unwrap(parse_color(~"rgba(15,250,3,.5)")));
|
||||||
assert rgba(15u8,250u8,3u8,0.5).eq(unwrap(parse_color(~"rgba(15,250,3,0.5)")));
|
assert rgba(15u8,250u8,3u8,0.5).eq(unwrap(parse_color(~"rgba(15,250,3,0.5)")));
|
||||||
assert none == parse_color(~"rbga(1,2,3)");
|
assert None == parse_color(~"rbga(1,2,3)");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -232,7 +232,7 @@ mod test {
|
||||||
assert navy().eq(unwrap(parse_color(~"hsl(240.0,1.0,.25)")));
|
assert navy().eq(unwrap(parse_color(~"hsl(240.0,1.0,.25)")));
|
||||||
assert teal().eq(unwrap(parse_color(~"hsl(180.0,1.0,.25)")));
|
assert teal().eq(unwrap(parse_color(~"hsl(180.0,1.0,.25)")));
|
||||||
assert aqua().eq(unwrap(parse_color(~"hsl(180.0,1.0,.5)")));
|
assert aqua().eq(unwrap(parse_color(~"hsl(180.0,1.0,.5)")));
|
||||||
assert none == parse_color(~"hsl(1,2,3,.4)");
|
assert None == parse_color(~"hsl(1,2,3,.4)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
// TODO: Use traits.
|
// TODO: Use traits.
|
||||||
|
|
||||||
type Tree<T> = {
|
type Tree<T> = {
|
||||||
mut parent: option<T>,
|
mut parent: Option<T>,
|
||||||
mut first_child: option<T>,
|
mut first_child: Option<T>,
|
||||||
mut last_child: option<T>,
|
mut last_child: Option<T>,
|
||||||
mut prev_sibling: option<T>,
|
mut prev_sibling: Option<T>,
|
||||||
mut next_sibling: option<T>
|
mut next_sibling: Option<T>
|
||||||
};
|
};
|
||||||
|
|
||||||
trait ReadMethods<T> {
|
trait ReadMethods<T> {
|
||||||
|
@ -22,8 +22,8 @@ fn each_child<T:copy,O:ReadMethods<T>>(ops: O, node: T, f: fn(T) -> bool) {
|
||||||
let mut p = ops.with_tree_fields(node, |f| f.first_child);
|
let mut p = ops.with_tree_fields(node, |f| f.first_child);
|
||||||
loop {
|
loop {
|
||||||
match copy p {
|
match copy p {
|
||||||
none => { return; }
|
None => { return; }
|
||||||
some(c) => {
|
Some(c) => {
|
||||||
if !f(c) { return; }
|
if !f(c) { return; }
|
||||||
p = ops.with_tree_fields(c, |f| f.next_sibling);
|
p = ops.with_tree_fields(c, |f| f.next_sibling);
|
||||||
}
|
}
|
||||||
|
@ -32,45 +32,45 @@ fn each_child<T:copy,O:ReadMethods<T>>(ops: O, node: T, f: fn(T) -> bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty<T>() -> Tree<T> {
|
fn empty<T>() -> Tree<T> {
|
||||||
{mut parent: none,
|
{mut parent: None,
|
||||||
mut first_child: none,
|
mut first_child: None,
|
||||||
mut last_child: none,
|
mut last_child: None,
|
||||||
mut prev_sibling: none,
|
mut prev_sibling: None,
|
||||||
mut next_sibling: none}
|
mut next_sibling: None}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_child<T:copy,O:WriteMethods<T>>(ops: O, parent: T, child: T) {
|
fn add_child<T:copy,O:WriteMethods<T>>(ops: O, parent: T, child: T) {
|
||||||
|
|
||||||
ops.with_tree_fields(child, |child_tf| {
|
ops.with_tree_fields(child, |child_tf| {
|
||||||
match child_tf.parent {
|
match child_tf.parent {
|
||||||
some(_) => { fail ~"Already has a parent"; }
|
Some(_) => { fail ~"Already has a parent"; }
|
||||||
none => { child_tf.parent = some(parent); }
|
None => { child_tf.parent = Some(parent); }
|
||||||
}
|
}
|
||||||
|
|
||||||
assert child_tf.prev_sibling == none;
|
assert child_tf.prev_sibling.is_none();
|
||||||
assert child_tf.next_sibling == none;
|
assert child_tf.next_sibling.is_none();
|
||||||
|
|
||||||
ops.with_tree_fields(parent, |parent_tf| {
|
ops.with_tree_fields(parent, |parent_tf| {
|
||||||
match copy parent_tf.last_child {
|
match copy parent_tf.last_child {
|
||||||
none => {
|
None => {
|
||||||
parent_tf.first_child = some(child);
|
parent_tf.first_child = Some(child);
|
||||||
}
|
}
|
||||||
some(lc) => {
|
Some(lc) => {
|
||||||
let lc = lc; // satisfy alias checker
|
let lc = lc; // satisfy alias checker
|
||||||
ops.with_tree_fields(lc, |lc_tf| {
|
ops.with_tree_fields(lc, |lc_tf| {
|
||||||
assert lc_tf.next_sibling == none;
|
assert lc_tf.next_sibling.is_none();
|
||||||
lc_tf.next_sibling = some(child);
|
lc_tf.next_sibling = Some(child);
|
||||||
});
|
});
|
||||||
child_tf.prev_sibling = some(lc);
|
child_tf.prev_sibling = Some(lc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parent_tf.last_child = some(child);
|
parent_tf.last_child = Some(child);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_parent<T:copy,O:ReadMethods<T>>(ops: O, node: T) -> option<T> {
|
fn get_parent<T:copy,O:ReadMethods<T>>(ops: O, node: T) -> Option<T> {
|
||||||
ops.with_tree_fields(node, |tf| tf.parent)
|
ops.with_tree_fields(node, |tf| tf.parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ export make_url, UrlMap, url_map;
|
||||||
import std::net::url;
|
import std::net::url;
|
||||||
import url::{get_scheme, url};
|
import url::{get_scheme, url};
|
||||||
import std::map::hashmap;
|
import std::map::hashmap;
|
||||||
|
import path::Path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a URL object from a string. Does various helpful browsery things like
|
Create a URL object from a string. Does various helpful browsery things like
|
||||||
|
@ -14,24 +15,24 @@ Create a URL object from a string. Does various helpful browsery things like
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
fn make_url(str_url: ~str, current_url: option<url>) -> url {
|
fn make_url(str_url: ~str, current_url: Option<url>) -> url {
|
||||||
let mut schm = get_scheme(str_url);
|
let mut schm = get_scheme(str_url);
|
||||||
let str_url = if result::is_err(schm) {
|
let str_url = if result::is_err(schm) {
|
||||||
if current_url.is_none() {
|
if current_url.is_none() {
|
||||||
// If all we have is a filename, assume it's a local relative file
|
// If all we have is a filename, assume it's a local relative file
|
||||||
// and build an absolute path with the cwd
|
// and build an absolute path with the cwd
|
||||||
~"file://" + path::connect(os::getcwd(), str_url)
|
~"file://" + os::getcwd().push(str_url).to_str()
|
||||||
} else {
|
} else {
|
||||||
let current_url = current_url.get();
|
let current_url = current_url.get();
|
||||||
#debug("make_url: current_url: %?", current_url);
|
#debug("make_url: current_url: %?", current_url);
|
||||||
if current_url.path.is_empty() || current_url.path.ends_with("/") {
|
if current_url.path.is_empty() || current_url.path.ends_with("/") {
|
||||||
current_url.scheme + "://" + path::connect(current_url.host, str_url)
|
current_url.scheme + "://" + current_url.host + "/" + str_url
|
||||||
} else {
|
} else {
|
||||||
let path = path::split(current_url.path);
|
let path = str::split_char(current_url.path, '/');
|
||||||
let path = path.init();
|
let path = path.init();
|
||||||
let path = path::connect_many(path + ~[copy str_url]);
|
let path = str::connect(path + ~[copy str_url], "/");
|
||||||
|
|
||||||
current_url.scheme + "://" + path::connect(current_url.host, path)
|
current_url.scheme + "://" + current_url.host + "/" + path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,18 +48,18 @@ mod make_url_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn should_create_absolute_file_url_if_current_url_is_none_and_str_url_looks_filey() {
|
fn should_create_absolute_file_url_if_current_url_is_none_and_str_url_looks_filey() {
|
||||||
let file = ~"local.html";
|
let file = ~"local.html";
|
||||||
let url = make_url(file, none);
|
let url = make_url(file, None);
|
||||||
#debug("url: %?", url);
|
#debug("url: %?", url);
|
||||||
assert url.scheme == ~"file";
|
assert url.scheme == ~"file";
|
||||||
assert url.path.contains(os::getcwd());
|
assert url.path.contains(os::getcwd().to_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_create_url_based_on_old_url_1() {
|
fn should_create_url_based_on_old_url_1() {
|
||||||
let old_str = ~"http://example.com";
|
let old_str = ~"http://example.com";
|
||||||
let old_url = make_url(old_str, none);
|
let old_url = make_url(old_str, None);
|
||||||
let new_str = ~"index.html";
|
let new_str = ~"index.html";
|
||||||
let new_url = make_url(new_str, some(old_url));
|
let new_url = make_url(new_str, Some(old_url));
|
||||||
assert new_url.scheme == ~"http";
|
assert new_url.scheme == ~"http";
|
||||||
assert new_url.host == ~"example.com";
|
assert new_url.host == ~"example.com";
|
||||||
assert new_url.path == ~"/index.html";
|
assert new_url.path == ~"/index.html";
|
||||||
|
@ -67,9 +68,9 @@ mod make_url_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn should_create_url_based_on_old_url_2() {
|
fn should_create_url_based_on_old_url_2() {
|
||||||
let old_str = ~"http://example.com/";
|
let old_str = ~"http://example.com/";
|
||||||
let old_url = make_url(old_str, none);
|
let old_url = make_url(old_str, None);
|
||||||
let new_str = ~"index.html";
|
let new_str = ~"index.html";
|
||||||
let new_url = make_url(new_str, some(old_url));
|
let new_url = make_url(new_str, Some(old_url));
|
||||||
assert new_url.scheme == ~"http";
|
assert new_url.scheme == ~"http";
|
||||||
assert new_url.host == ~"example.com";
|
assert new_url.host == ~"example.com";
|
||||||
assert new_url.path == ~"/index.html";
|
assert new_url.path == ~"/index.html";
|
||||||
|
@ -78,9 +79,9 @@ mod make_url_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn should_create_url_based_on_old_url_3() {
|
fn should_create_url_based_on_old_url_3() {
|
||||||
let old_str = ~"http://example.com/index.html";
|
let old_str = ~"http://example.com/index.html";
|
||||||
let old_url = make_url(old_str, none);
|
let old_url = make_url(old_str, None);
|
||||||
let new_str = ~"crumpet.html";
|
let new_str = ~"crumpet.html";
|
||||||
let new_url = make_url(new_str, some(old_url));
|
let new_url = make_url(new_str, Some(old_url));
|
||||||
assert new_url.scheme == ~"http";
|
assert new_url.scheme == ~"http";
|
||||||
assert new_url.host == ~"example.com";
|
assert new_url.host == ~"example.com";
|
||||||
assert new_url.path == ~"/crumpet.html";
|
assert new_url.path == ~"/crumpet.html";
|
||||||
|
@ -89,9 +90,9 @@ mod make_url_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn should_create_url_based_on_old_url_4() {
|
fn should_create_url_based_on_old_url_4() {
|
||||||
let old_str = ~"http://example.com/snarf/index.html";
|
let old_str = ~"http://example.com/snarf/index.html";
|
||||||
let old_url = make_url(old_str, none);
|
let old_url = make_url(old_str, None);
|
||||||
let new_str = ~"crumpet.html";
|
let new_str = ~"crumpet.html";
|
||||||
let new_url = make_url(new_str, some(old_url));
|
let new_url = make_url(new_str, Some(old_url));
|
||||||
assert new_url.scheme == ~"http";
|
assert new_url.scheme == ~"http";
|
||||||
assert new_url.host == ~"example.com";
|
assert new_url.host == ~"example.com";
|
||||||
assert new_url.path == ~"/snarf/crumpet.html";
|
assert new_url.path == ~"/snarf/crumpet.html";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue