servo: Fix reshaping window callback
authorPatrick Walton <pcwalton@mimiga.net>
Thu, 12 Jul 2012 17:28:10 -0700
changeset 470861 10c24d238b693b7f5fccbe30132e9499eaf610d5
parent 470860 57724345d31a424c3ace9cde8504f1f7711c7fcd
child 470862 84127bca3edc80373f49f9d0be7631ab820467b0
push id44079
push userbmo:gps@mozilla.com
push dateSat, 04 Feb 2017 00:14:49 +0000
servo: Fix reshaping window callback Source-Repo: https://github.com/servo/servo Source-Revision: 12a05daa5da455b5888d5b393a924fc1384e7c24
servo/src/servo/content.rs
servo/src/servo/platform/osmain.rs
--- 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 = {