mirror of
https://github.com/servo/servo.git
synced 2025-06-10 01:23:13 +00:00
Merge pull request #3358 from jdm/thespicemustnotreflow
Delay initiating layout operations for as long as possible.
This commit is contained in:
commit
75caade828
4 changed files with 46 additions and 13 deletions
|
@ -589,7 +589,7 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> {
|
||||||
let page = window.deref().page();
|
let page = window.deref().page();
|
||||||
let addr = self.to_trusted_node_address();
|
let addr = self.to_trusted_node_address();
|
||||||
|
|
||||||
let ContentBoxResponse(rect) = page.layout_rpc.content_box(addr);
|
let ContentBoxResponse(rect) = page.layout().content_box(addr);
|
||||||
rect
|
rect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,7 +597,7 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> {
|
||||||
let window = window_from_node(self).root();
|
let window = window_from_node(self).root();
|
||||||
let page = window.deref().page();
|
let page = window.deref().page();
|
||||||
let addr = self.to_trusted_node_address();
|
let addr = self.to_trusted_node_address();
|
||||||
let ContentBoxesResponse(rects) = page.layout_rpc.content_boxes(addr);
|
let ContentBoxesResponse(rects) = page.layout().content_boxes(addr);
|
||||||
rects
|
rects
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ use dom::location::Location;
|
||||||
use dom::navigator::Navigator;
|
use dom::navigator::Navigator;
|
||||||
use dom::performance::Performance;
|
use dom::performance::Performance;
|
||||||
use dom::screen::Screen;
|
use dom::screen::Screen;
|
||||||
use layout_interface::{ReflowForDisplay, DocumentDamageLevel};
|
use layout_interface::{ReflowGoal, DocumentDamageLevel};
|
||||||
use page::Page;
|
use page::Page;
|
||||||
use script_task::{ExitWindowMsg, FireTimerMsg, ScriptChan, TriggerLoadMsg, TriggerFragmentMsg};
|
use script_task::{ExitWindowMsg, FireTimerMsg, ScriptChan, TriggerLoadMsg, TriggerFragmentMsg};
|
||||||
use script_traits::ScriptControlChan;
|
use script_traits::ScriptControlChan;
|
||||||
|
@ -78,14 +78,14 @@ impl TimerHandle {
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
eventtarget: EventTarget,
|
eventtarget: EventTarget,
|
||||||
pub script_chan: ScriptChan,
|
pub script_chan: ScriptChan,
|
||||||
control_chan: ScriptControlChan,
|
pub control_chan: ScriptControlChan,
|
||||||
console: Cell<Option<JS<Console>>>,
|
console: Cell<Option<JS<Console>>>,
|
||||||
location: Cell<Option<JS<Location>>>,
|
location: Cell<Option<JS<Location>>>,
|
||||||
navigator: Cell<Option<JS<Navigator>>>,
|
navigator: Cell<Option<JS<Navigator>>>,
|
||||||
pub image_cache_task: ImageCacheTask,
|
pub image_cache_task: ImageCacheTask,
|
||||||
pub active_timers: Traceable<RefCell<HashMap<TimerId, TimerHandle>>>,
|
pub active_timers: Traceable<RefCell<HashMap<TimerId, TimerHandle>>>,
|
||||||
next_timer_handle: Traceable<Cell<i32>>,
|
next_timer_handle: Traceable<Cell<i32>>,
|
||||||
compositor: Untraceable<Box<ScriptListener>>,
|
pub compositor: Untraceable<Box<ScriptListener>>,
|
||||||
pub browser_context: Traceable<RefCell<Option<BrowserContext>>>,
|
pub browser_context: Traceable<RefCell<Option<BrowserContext>>>,
|
||||||
pub page: Rc<Page>,
|
pub page: Rc<Page>,
|
||||||
performance: Cell<Option<JS<Performance>>>,
|
performance: Cell<Option<JS<Performance>>>,
|
||||||
|
@ -365,6 +365,7 @@ impl Reflectable for Window {
|
||||||
|
|
||||||
pub trait WindowHelpers {
|
pub trait WindowHelpers {
|
||||||
fn damage_and_reflow(&self, damage: DocumentDamageLevel);
|
fn damage_and_reflow(&self, damage: DocumentDamageLevel);
|
||||||
|
fn flush_layout(&self, goal: ReflowGoal);
|
||||||
fn wait_until_safe_to_modify_dom(&self);
|
fn wait_until_safe_to_modify_dom(&self);
|
||||||
fn init_browser_context(&self, doc: &JSRef<Document>);
|
fn init_browser_context(&self, doc: &JSRef<Document>);
|
||||||
fn load_url(&self, href: DOMString);
|
fn load_url(&self, href: DOMString);
|
||||||
|
@ -397,11 +398,12 @@ impl<'a> WindowHelpers for JSRef<'a, Window> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
|
fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
|
||||||
// FIXME This should probably be ReflowForQuery, not Display. All queries currently
|
|
||||||
// currently rely on the display list, which means we can't destroy it by
|
|
||||||
// doing a query reflow.
|
|
||||||
self.page().damage(damage);
|
self.page().damage(damage);
|
||||||
self.page().reflow(ReflowForDisplay, self.control_chan.clone(), *self.compositor);
|
self.page().avoided_reflows.set(self.page().avoided_reflows.get() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_layout(&self, goal: ReflowGoal) {
|
||||||
|
self.page().flush_layout(goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_until_safe_to_modify_dom(&self) {
|
fn wait_until_safe_to_modify_dom(&self) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use dom::document::{Document, DocumentHelpers};
|
||||||
use dom::element::{Element, AttributeHandlers};
|
use dom::element::{Element, AttributeHandlers};
|
||||||
use dom::node::{Node, NodeHelpers};
|
use dom::node::{Node, NodeHelpers};
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use layout_interface::{DocumentDamage};
|
use layout_interface::{DocumentDamage, ReflowForDisplay};
|
||||||
use layout_interface::{DocumentDamageLevel, HitTestResponse, MouseOverResponse};
|
use layout_interface::{DocumentDamageLevel, HitTestResponse, MouseOverResponse};
|
||||||
use layout_interface::{GetRPCMsg, LayoutChan, LayoutRPC};
|
use layout_interface::{GetRPCMsg, LayoutChan, LayoutRPC};
|
||||||
use layout_interface::{Reflow, ReflowGoal, ReflowMsg};
|
use layout_interface::{Reflow, ReflowGoal, ReflowMsg};
|
||||||
|
@ -57,7 +57,7 @@ pub struct Page {
|
||||||
pub layout_chan: Untraceable<LayoutChan>,
|
pub layout_chan: Untraceable<LayoutChan>,
|
||||||
|
|
||||||
/// A handle to perform RPC calls into the layout, quickly.
|
/// A handle to perform RPC calls into the layout, quickly.
|
||||||
pub layout_rpc: Untraceable<Box<LayoutRPC>>,
|
layout_rpc: Untraceable<Box<LayoutRPC>>,
|
||||||
|
|
||||||
/// The port that we will use to join layout. If this is `None`, then layout is not running.
|
/// The port that we will use to join layout. If this is `None`, then layout is not running.
|
||||||
pub layout_join_port: Untraceable<RefCell<Option<Receiver<()>>>>,
|
pub layout_join_port: Untraceable<RefCell<Option<Receiver<()>>>>,
|
||||||
|
@ -95,6 +95,9 @@ pub struct Page {
|
||||||
|
|
||||||
/// Number of pending reflows that were sent while layout was active.
|
/// Number of pending reflows that were sent while layout was active.
|
||||||
pub pending_reflows: Cell<int>,
|
pub pending_reflows: Cell<int>,
|
||||||
|
|
||||||
|
/// Number of unnecessary potential reflows that were skipped since the last reflow
|
||||||
|
pub avoided_reflows: Cell<int>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PageIterator {
|
pub struct PageIterator {
|
||||||
|
@ -159,9 +162,31 @@ impl Page {
|
||||||
constellation_chan: Untraceable::new(constellation_chan),
|
constellation_chan: Untraceable::new(constellation_chan),
|
||||||
children: Traceable::new(RefCell::new(vec!())),
|
children: Traceable::new(RefCell::new(vec!())),
|
||||||
pending_reflows: Cell::new(0),
|
pending_reflows: Cell::new(0),
|
||||||
|
avoided_reflows: Cell::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flush_layout(&self, goal: ReflowGoal) {
|
||||||
|
let damaged = self.damage.borrow().is_some();
|
||||||
|
if damaged {
|
||||||
|
let frame = self.frame();
|
||||||
|
let window = frame.get_ref().window.root();
|
||||||
|
self.reflow(goal, window.control_chan.clone(), *window.compositor);
|
||||||
|
} else {
|
||||||
|
self.avoided_reflows.set(self.avoided_reflows.get() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn layout(&self) -> &LayoutRPC {
|
||||||
|
// FIXME This should probably be ReflowForQuery, not Display. All queries currently
|
||||||
|
// currently rely on the display list, which means we can't destroy it by
|
||||||
|
// doing a query reflow.
|
||||||
|
self.flush_layout(ReflowForDisplay);
|
||||||
|
self.join_layout(); //FIXME: is this necessary, or is layout_rpc's mutex good enough?
|
||||||
|
let layout_rpc: &LayoutRPC = *self.layout_rpc;
|
||||||
|
layout_rpc
|
||||||
|
}
|
||||||
|
|
||||||
// must handle root case separately
|
// must handle root case separately
|
||||||
pub fn remove(&self, id: PipelineId) -> Option<Rc<Page>> {
|
pub fn remove(&self, id: PipelineId) -> Option<Rc<Page>> {
|
||||||
let remove_idx = {
|
let remove_idx = {
|
||||||
|
@ -323,6 +348,9 @@ impl Page {
|
||||||
match root.root() {
|
match root.root() {
|
||||||
None => {},
|
None => {},
|
||||||
Some(root) => {
|
Some(root) => {
|
||||||
|
debug!("avoided {:d} reflows", self.avoided_reflows.get());
|
||||||
|
self.avoided_reflows.set(0);
|
||||||
|
|
||||||
debug!("script: performing reflow for goal {:?}", goal);
|
debug!("script: performing reflow for goal {:?}", goal);
|
||||||
|
|
||||||
// Now, join the layout so that they will see the latest changes we have made.
|
// Now, join the layout so that they will see the latest changes we have made.
|
||||||
|
@ -393,7 +421,7 @@ impl Page {
|
||||||
}
|
}
|
||||||
let root = root.unwrap();
|
let root = root.unwrap();
|
||||||
let root: &JSRef<Node> = NodeCast::from_ref(&*root);
|
let root: &JSRef<Node> = NodeCast::from_ref(&*root);
|
||||||
let address = match self.layout_rpc.hit_test(root.to_trusted_node_address(), *point) {
|
let address = match self.layout().hit_test(root.to_trusted_node_address(), *point) {
|
||||||
Ok(HitTestResponse(node_address)) => {
|
Ok(HitTestResponse(node_address)) => {
|
||||||
Some(node_address)
|
Some(node_address)
|
||||||
}
|
}
|
||||||
|
@ -414,7 +442,7 @@ impl Page {
|
||||||
}
|
}
|
||||||
let root = root.unwrap();
|
let root = root.unwrap();
|
||||||
let root: &JSRef<Node> = NodeCast::from_ref(&*root);
|
let root: &JSRef<Node> = NodeCast::from_ref(&*root);
|
||||||
let address = match self.layout_rpc.mouse_over(root.to_trusted_node_address(), *point) {
|
let address = match self.layout().mouse_over(root.to_trusted_node_address(), *point) {
|
||||||
Ok(MouseOverResponse(node_address)) => {
|
Ok(MouseOverResponse(node_address)) => {
|
||||||
Some(node_address)
|
Some(node_address)
|
||||||
}
|
}
|
||||||
|
|
|
@ -687,6 +687,7 @@ impl ScriptTask {
|
||||||
// Kick off the initial reflow of the page.
|
// Kick off the initial reflow of the page.
|
||||||
debug!("kicking off initial reflow of {}", url);
|
debug!("kicking off initial reflow of {}", url);
|
||||||
document.deref().content_changed();
|
document.deref().content_changed();
|
||||||
|
window.flush_layout(ReflowForDisplay);
|
||||||
|
|
||||||
let fragment = url.fragment.as_ref().map(|ref fragment| fragment.to_string());
|
let fragment = url.fragment.as_ref().map(|ref fragment| fragment.to_string());
|
||||||
|
|
||||||
|
@ -716,6 +717,8 @@ impl ScriptTask {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(_) => println!("evaluate_script failed")
|
Err(_) => println!("evaluate_script failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.flush_layout(ReflowForDisplay);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue