--- a/servo/src/servo/content.rs
+++ b/servo/src/servo/content.rs
@@ -8,20 +8,21 @@ export ControlMsg, ExecuteMsg, ParseMsg,
export PingMsg, PongMsg;
export create_content;
import comm::{port, chan, listen, select2};
import task::{spawn, spawn_listener};
import io::{read_whole_file, println};
import result::{ok, err};
-import dom::base::NodeScope;
+import dom::base::{Node, NodeScope};
import dom::event::{Event, ResizeEvent};
import dom::rcu::WriterMethods;
import dom::style;
+import dom::style::Stylesheet;
import gfx::renderer::Sink;
import parser::html_lexer::spawn_html_lexer_task;
import parser::css_builder::build_stylesheet;
import parser::html_builder::build_dom;
import layout::layout_task;
import layout_task::{Layout, BuildMsg};
import jsrt = js::rust::rt;
@@ -51,34 +52,48 @@ fn join_layout(scope: NodeScope, layout:
listen(|response_from_layout| {
layout.send(layout_task::PingMsg(response_from_layout));
response_from_layout.recv();
});
scope.reader_joined();
}
}
+class Document {
+ let root: Node;
+ let css_rules: Stylesheet;
+
+ new(root: Node, +css_rules: Stylesheet) {
+ self.root = root;
+ self.css_rules = css_rules;
+ }
+}
+
class Content<S:Sink send copy> {
let sink: S;
let layout: Layout;
let from_master: port<ControlMsg>;
let event_port: port<Event>;
let scope: NodeScope;
let jsrt: jsrt;
+ let mut document: option<Document>;
+
new(layout: Layout, sink: S, from_master: port<ControlMsg>) {
self.layout = layout;
self.sink = sink;
self.from_master = from_master;
self.event_port = port();
self.scope = NodeScope();
self.jsrt = jsrt();
+ self.document = none;
+
self.sink.add_event_listener(self.event_port.chan());
}
fn start() {
while self.handle_msg(select2(self.from_master, self.event_port)) {
// Go on...
}
}
@@ -98,33 +113,25 @@ class Content<S:Sink send copy> {
alt control_msg {
ParseMsg(filename) {
#debug["content: Received filename `%s` to parse", *filename];
// Note: we can parse the next document in parallel
// with any previous documents.
let stream = spawn_html_lexer_task(copy filename);
let (root, style_port) = build_dom(self.scope, stream);
-
- // Collect the css stylesheet
let css_rules = style_port.recv();
// Apply the css rules to the dom tree:
#debug["%?", css_rules];
- // Now, join the layout so that they will see the latest
- // changes we have made.
- join_layout(self.scope, self.layout);
+ let document = Document(root, css_rules);
+ self.relayout(document);
+ self.document = some(document);
- // Send new document and relevant styles to layout
- self.layout.send(BuildMsg(root, css_rules));
-
- // Indicate that reader was forked so any further
- // changes will be isolated.
- self.scope.reader_forked();
ret true;
}
ExecuteMsg(filename) {
#debug["content: Received filename `%s` to execute", *filename];
alt read_whole_file(*filename) {
err(msg) {
@@ -145,20 +152,44 @@ class Content<S:Sink send copy> {
ExitMsg {
self.layout.send(layout_task::ExitMsg);
ret false;
}
}
}
+ fn relayout(document: Document) {
+ #debug("content: performing relayout");
+
+ // Now, join the layout so that they will see the latest
+ // changes we have made.
+ join_layout(self.scope, self.layout);
+
+ // Send new document and relevant styles to layout
+ // FIXME: Put CSS rules in an arc or something.
+ self.layout.send(BuildMsg(document.root, document.css_rules));
+
+ // Indicate that reader was forked so any further
+ // changes will be isolated.
+ self.scope.reader_forked();
+ }
+
fn handle_event(event: Event) -> bool {
alt event {
ResizeEvent(new_width, new_height) {
#debug("content got resize event: %d, %d", new_width, new_height);
+ alt copy self.document {
+ none {
+ // Nothing to do.
+ }
+ some(document) {
+ self.relayout(document);
+ }
+ }
ret true;
}
}
}
}
fn create_content<S: Sink send copy>(layout: Layout, sink: S) -> chan<ControlMsg> {
do spawn_listener::<ControlMsg> |from_master| {
--- a/servo/src/servo/platform/osmain.rs
+++ b/servo/src/servo/platform/osmain.rs
@@ -29,88 +29,100 @@ fn OSMain() -> OSMain {
do platform::runmain {
#debug("preparing to enter main loop");
mainloop(po);
}
}
}
fn mainloop(po: port<Msg>) {
- let mut key_handlers: [chan<()>] = [];
+ let key_handlers: @dvec<chan<()>> = @dvec();
let event_listeners: @dvec<chan<Event>> = @dvec();
glut::init();
glut::init_display_mode(glut::DOUBLE);
- let surfaces = surface_set();
+ let surfaces = @surface_set();
let window = glut::create_window("Servo");
glut::reshape_window(window, 800, 600);
let context = layers::rendergl::init_render_context();
let image = @layers::layers::Image(0, 0, layers::layers::RGB24Format, ~[]);
let image_layer = @layers::layers::ImageLayer(image);
image_layer.common.set_transform
(image_layer.common.transform.scale(800.0f32, 600.0f32, 1.0f32));
let scene = @mut layers::scene::Scene(layers::layers::ImageLayerKind(image_layer),
Size2D(800.0f32, 600.0f32));
- do glut::reshape_func(window) |width, height| {
- #debug("osmain: window resized to %d,%d", width as int, height as int);
- for event_listeners.each |event_listener| {
- event_listener.send(ResizeEvent(width as int, height as int));
- }
- }
-
- loop {
- do glut::display_func() {
- #debug("osmain: drawing to screen");
+ let done = @mut false;
- layers::rendergl::render_scene(context, *scene);
- glut::swap_buffers();
- glut::post_redisplay();
- }
-
+ let check_for_messages = fn@() {
// Handle messages
+ #debug("osmain: peeking");
if po.peek() {
- alt check po.recv() {
+ alt po.recv() {
AddKeyHandler(key_ch) {
- key_handlers += [key_ch];
+ key_handlers.push(key_ch);
}
AddEventListener(event_listener) {
event_listeners.push(event_listener);
}
BeginDrawing(sender) {
- lend_surface(surfaces, sender);
+ lend_surface(*surfaces, sender);
}
Draw(sender, dt) {
- return_surface(surfaces, dt);
- lend_surface(surfaces, sender);
+ #debug("osmain: received new frame");
+ return_surface(*surfaces, dt);
+ lend_surface(*surfaces, sender);
let mut image_data;
unsafe {
let buffer = cairo_image_surface_get_data(surfaces.s1.surf.cairo_surf);
image_data = vec::unsafe::from_buf(buffer, 800 * 600 * 4);
}
let image =
@layers::layers::Image(800, 600, layers::layers::RGB24Format,
layers::util::convert_rgb32_to_rgb24(image_data));
image_layer.set_image(image);
-
- glut::post_redisplay();
}
- exit { break; }
+ exit {
+ *done = true;
+ }
}
}
+ };
+ do glut::reshape_func(window) |width, height| {
+ check_for_messages();
+
+ #debug("osmain: window resized to %d,%d", width as int, height as int);
+ for event_listeners.each |event_listener| {
+ event_listener.send(ResizeEvent(width as int, height as int));
+ }
+ }
+
+ do glut::display_func() {
+ check_for_messages();
+
+ #debug("osmain: drawing to screen");
+
+ layers::rendergl::render_scene(context, *scene);
+ glut::swap_buffers();
+ glut::post_redisplay();
+ }
+
+ while !*done {
+ #debug("osmain: running GLUT check loop");
glut::check_loop();
}
+
destroy_surface(surfaces.s1.surf);
destroy_surface(surfaces.s2.surf);
}
#[doc = "
Implementation to allow the osmain channel to be used as a graphics
sink for the renderer
"]
@@ -194,17 +206,17 @@ fn mk_surface() -> surface {
assert !ptr::is_null(azure_target);
{
cairo_surf: cairo_surf,
az_target: azure_target
}
}
-fn destroy_surface(surface: surface) {
+fn destroy_surface(+surface: surface) {
AzReleaseDrawTarget(surface.az_target);
cairo_surface_destroy(surface.cairo_surf);
}
#[doc = "A function for spawning into the platform's main thread"]
fn on_osmain<T: send>(+f: fn~(comm::port<T>)) -> comm::chan<T> {
let builder = task::builder();
let opts = {