mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Incremental Style Recalc
This patch puts in the initial framework for incremental reflow. Nodes' styles are no longer recalculated unless the node has changed. I've been hacking on the general problem of incremental reflow for the past couple weeks, and I've yet to get a full implementation that actually passes all the reftests + wikipedia + cnn. Therefore, I'm going to try to land the different parts of it one by one. This patch only does incremental style recalc, without incremental flow construction, inline-size bubbling, reflow, or display lists. Those will be coming in that order as I finish them. At least with this strategy, I can land a working version of incremental reflow, even if not yet complete. r? @pcwalton
This commit is contained in:
parent
510f8a817f
commit
d12c6e7383
31 changed files with 641 additions and 424 deletions
|
@ -29,9 +29,7 @@ use dom::worker::{Worker, TrustedWorkerAddress};
|
|||
use dom::xmlhttprequest::{TrustedXHRAddress, XMLHttpRequest, XHRProgress};
|
||||
use html::hubbub_html_parser::{InputString, InputUrl, HtmlParserResult, HtmlDiscoveredScript};
|
||||
use html::hubbub_html_parser;
|
||||
use layout_interface::{ScriptLayoutChan, LayoutChan, MatchSelectorsDocumentDamage};
|
||||
use layout_interface::{ReflowDocumentDamage, ReflowForDisplay};
|
||||
use layout_interface::ContentChangedDocumentDamage;
|
||||
use layout_interface::{ScriptLayoutChan, LayoutChan, ReflowForDisplay};
|
||||
use layout_interface;
|
||||
use page::{Page, IterablePage, Frame};
|
||||
|
||||
|
@ -52,6 +50,7 @@ use servo_msg::constellation_msg;
|
|||
use servo_net::image_cache_task::ImageCacheTask;
|
||||
use servo_net::resource_task::ResourceTask;
|
||||
use servo_util::geometry::to_frac_px;
|
||||
use servo_util::smallvec::{SmallVec1, SmallVec};
|
||||
use servo_util::task::spawn_named_with_send_on_failure;
|
||||
|
||||
use geom::point::Point2D;
|
||||
|
@ -66,6 +65,7 @@ use url::Url;
|
|||
use libc::size_t;
|
||||
use std::any::{Any, AnyRefExt};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::comm::{channel, Sender, Receiver, Select};
|
||||
use std::mem::replace;
|
||||
use std::rc::Rc;
|
||||
|
@ -445,7 +445,9 @@ impl ScriptTask {
|
|||
}
|
||||
};
|
||||
|
||||
// Squash any pending resize events in the queue.
|
||||
let mut needs_reflow = HashSet::new();
|
||||
|
||||
// Squash any pending resize and reflow events in the queue.
|
||||
loop {
|
||||
match event {
|
||||
// This has to be handled before the ResizeMsg below,
|
||||
|
@ -459,6 +461,13 @@ impl ScriptTask {
|
|||
let page = page.find(id).expect("resize sent to nonexistent pipeline");
|
||||
page.resize_event.set(Some(size));
|
||||
}
|
||||
FromConstellation(SendEventMsg(id, ReflowEvent(node_addresses))) => {
|
||||
let mut page = self.page.borrow_mut();
|
||||
let inner_page = page.find(id).expect("Reflow sent to nonexistent pipeline");
|
||||
let mut pending = inner_page.pending_dirty_nodes.borrow_mut();
|
||||
pending.push_all_move(node_addresses);
|
||||
needs_reflow.insert(id);
|
||||
}
|
||||
_ => {
|
||||
sequential.push(event);
|
||||
}
|
||||
|
@ -507,6 +516,11 @@ impl ScriptTask {
|
|||
}
|
||||
}
|
||||
|
||||
// Now process any pending reflows.
|
||||
for id in needs_reflow.into_iter() {
|
||||
self.handle_event(id, ReflowEvent(SmallVec1::new()));
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -632,8 +646,7 @@ impl ScriptTask {
|
|||
|
||||
if page.pending_reflows.get() > 0 {
|
||||
page.pending_reflows.set(0);
|
||||
page.damage(MatchSelectorsDocumentDamage);
|
||||
page.reflow(ReflowForDisplay, self.control_chan.clone(), &*self.compositor);
|
||||
self.force_reflow(&*page);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -711,8 +724,7 @@ impl ScriptTask {
|
|||
Some((ref loaded, needs_reflow)) if *loaded == url => {
|
||||
*page.mut_url() = Some((loaded.clone(), false));
|
||||
if needs_reflow {
|
||||
page.damage(ContentChangedDocumentDamage);
|
||||
page.reflow(ReflowForDisplay, self.control_chan.clone(), &*self.compositor);
|
||||
self.force_reflow(&*page);
|
||||
}
|
||||
return;
|
||||
},
|
||||
|
@ -796,7 +808,11 @@ impl ScriptTask {
|
|||
|
||||
// Kick off the initial reflow of the page.
|
||||
debug!("kicking off initial reflow of {}", url);
|
||||
document.content_changed();
|
||||
{
|
||||
let document_js_ref = (&*document).clone();
|
||||
let document_as_node = NodeCast::from_ref(document_js_ref);
|
||||
document.content_changed(document_as_node);
|
||||
}
|
||||
window.flush_layout(ReflowForDisplay);
|
||||
|
||||
{
|
||||
|
@ -856,6 +872,21 @@ impl ScriptTask {
|
|||
self.compositor.scroll_fragment_point(pipeline_id, LayerId::null(), point);
|
||||
}
|
||||
|
||||
fn force_reflow(&self, page: &Page) {
|
||||
{
|
||||
let mut pending = page.pending_dirty_nodes.borrow_mut();
|
||||
let js_runtime = self.js_runtime.deref().ptr;
|
||||
|
||||
for untrusted_node in pending.into_iter() {
|
||||
let node = node::from_untrusted_node_address(js_runtime, untrusted_node).root();
|
||||
node.dirty();
|
||||
}
|
||||
}
|
||||
|
||||
page.damage();
|
||||
page.reflow(ReflowForDisplay, self.control_chan.clone(), &*self.compositor);
|
||||
}
|
||||
|
||||
/// This is the main entry point for receiving and dispatching DOM events.
|
||||
///
|
||||
/// TODO: Actually perform DOM event dispatch.
|
||||
|
@ -870,8 +901,7 @@ impl ScriptTask {
|
|||
|
||||
let frame = page.frame();
|
||||
if frame.is_some() {
|
||||
page.damage(ReflowDocumentDamage);
|
||||
page.reflow(ReflowForDisplay, self.control_chan.clone(), &*self.compositor)
|
||||
self.force_reflow(&*page);
|
||||
}
|
||||
|
||||
let fragment_node =
|
||||
|
@ -906,8 +936,9 @@ impl ScriptTask {
|
|||
}
|
||||
|
||||
// FIXME(pcwalton): This reflows the entire document and is not incremental-y.
|
||||
ReflowEvent => {
|
||||
ReflowEvent(to_dirty) => {
|
||||
debug!("script got reflow event");
|
||||
assert_eq!(to_dirty.len(), 0);
|
||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
||||
let frame = page.frame();
|
||||
if frame.is_some() {
|
||||
|
@ -915,8 +946,7 @@ impl ScriptTask {
|
|||
if in_layout {
|
||||
page.pending_reflows.set(page.pending_reflows.get() + 1);
|
||||
} else {
|
||||
page.damage(MatchSelectorsDocumentDamage);
|
||||
page.reflow(ReflowForDisplay, self.control_chan.clone(), &*self.compositor)
|
||||
self.force_reflow(&*page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1021,8 +1051,7 @@ impl ScriptTask {
|
|||
|
||||
if target_compare {
|
||||
if mouse_over_targets.is_some() {
|
||||
page.damage(MatchSelectorsDocumentDamage);
|
||||
page.reflow(ReflowForDisplay, self.control_chan.clone(), &*self.compositor);
|
||||
self.force_reflow(&*page);
|
||||
}
|
||||
*mouse_over_targets = Some(target_list);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue