Send information to script as part of finishing layout.

This avoids the need for multiple layout RPC operations immediately
following return of control to script. This means that layout and
script can continue to operate in parallel at this point, rather
than one potentially waiting on the shared mutex to be unlocked.
This commit is contained in:
Josh Matthews 2017-04-10 17:47:20 +10:00
parent c3b9714ab7
commit 9134918844
5 changed files with 60 additions and 51 deletions

View file

@ -81,7 +81,8 @@ use profile_traits::mem::{self, Report, ReportKind, ReportsChan};
use profile_traits::time::{self, TimerMetadata, profile};
use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
use script::layout_wrapper::{ServoLayoutElement, ServoLayoutDocument, ServoLayoutNode};
use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow};
use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType};
use script_layout_interface::message::{ScriptReflow, ReflowComplete};
use script_layout_interface::reporter::CSSErrorReporter;
use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowResponse, OffsetParentResponse};
use script_layout_interface::rpc::TextIndexResponse;
@ -292,6 +293,37 @@ impl LayoutThreadFactory for LayoutThread {
}
}
struct ScriptReflowResult {
script_reflow: ScriptReflow,
result: RefCell<Option<ReflowComplete>>,
}
impl Deref for ScriptReflowResult {
type Target = ScriptReflow;
fn deref(&self) -> &ScriptReflow {
&self.script_reflow
}
}
impl ScriptReflowResult {
fn new(script_reflow: ScriptReflow) -> ScriptReflowResult {
ScriptReflowResult {
script_reflow: script_reflow,
result: RefCell::new(Some(Default::default())),
}
}
}
impl Drop for ScriptReflowResult {
fn drop(&mut self) {
self.script_reflow.script_join_chan.send(
self.result
.borrow_mut()
.take()
.unwrap()).unwrap();
}
}
/// The `LayoutThread` `rw_data` lock must remain locked until the first reflow,
/// as RPC calls don't make sense until then. Use this in combination with
/// `LayoutThread::lock_rw_data` and `LayoutThread::return_rw_data`.
@ -476,9 +508,7 @@ impl LayoutThread {
margin_style_response: MarginStyleResponse::empty(),
stacking_context_scroll_offsets: HashMap::new(),
text_index_response: TextIndexResponse(None),
pending_images: vec![],
nodes_from_point_response: vec![],
newly_transitioning_nodes: vec![],
})),
error_reporter: CSSErrorReporter {
pipelineid: id,
@ -616,10 +646,11 @@ impl LayoutThread {
Box<LayoutRPC + Send>).unwrap();
},
Msg::Reflow(data) => {
let mut data = ScriptReflowResult::new(data);
profile(time::ProfilerCategory::LayoutPerform,
self.profiler_metadata(),
self.time_profiler_chan.clone(),
|| self.handle_reflow(&data, possibly_locked_rw_data));
|| self.handle_reflow(&mut data, possibly_locked_rw_data));
},
Msg::TickAnimations => self.tick_all_animations(possibly_locked_rw_data),
Msg::SetStackingContextScrollStates(new_scroll_states) => {
@ -955,7 +986,7 @@ impl LayoutThread {
/// The high-level routine that performs layout threads.
fn handle_reflow<'a, 'b>(&mut self,
data: &ScriptReflow,
data: &mut ScriptReflowResult,
possibly_locked_rw_data: &mut RwData<'a, 'b>) {
let document = unsafe { ServoLayoutNode::new(&data.document) };
let document = document.as_document().unwrap();
@ -1240,24 +1271,26 @@ impl LayoutThread {
self.respond_to_query_if_necessary(&data.query_type,
&mut *rw_data,
&mut layout_context);
&mut layout_context,
data.result.borrow_mut().as_mut().unwrap());
}
fn respond_to_query_if_necessary(&self,
query_type: &ReflowQueryType,
rw_data: &mut LayoutThreadData,
context: &mut LayoutContext) {
context: &mut LayoutContext,
reflow_result: &mut ReflowComplete) {
let pending_images = match context.pending_images {
Some(ref pending) => std_mem::replace(&mut *pending.lock().unwrap(), vec![]),
None => vec![],
};
rw_data.pending_images = pending_images;
reflow_result.pending_images = pending_images;
let newly_transitioning_nodes = match context.newly_transitioning_nodes {
Some(ref nodes) => std_mem::replace(&mut *nodes.lock().unwrap(), vec![]),
None => vec![],
};
rw_data.newly_transitioning_nodes = newly_transitioning_nodes;
reflow_result.newly_transitioning_nodes = newly_transitioning_nodes;
let mut root_flow = match self.root_flow.borrow().clone() {
Some(root_flow) => root_flow,