Make servo build again

This commit is contained in:
Brian Anderson 2012-08-30 17:39:45 -07:00
parent 56bf2aaafe
commit 00cd6f8909
50 changed files with 746 additions and 593 deletions

View file

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

View file

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

View file

@ -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"),

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(&current_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"
}; };

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 */ }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(_) => (),

View file

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

View file

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

View file

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

View file

@ -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")]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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