Auto merge of #9832 - metajack:suppress-reflows, r=mbrubeck

Suppress reflows before RefreshTick or FirstLoad

This fixes a bug where partially loaded content is displayed to the user
before it should be, usually before stylesheets have loaded. This commit
supresses reflows until either FirstLoad or RefreshTick, whichever comes
first.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.svg" height="40" alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9832)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-03-04 04:00:30 +05:30
commit 37bcc161fe
9 changed files with 91 additions and 78 deletions

View file

@ -22,7 +22,7 @@ use euclid::size::Size2D;
use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
use flow_ref::{self, FlowRef};
use fnv::FnvHasher;
use gfx::display_list::{ClippingRegion, DisplayList, LayerInfo};
use gfx::display_list::{ClippingRegion, DisplayItemMetadata, DisplayList, LayerInfo};
use gfx::display_list::{OpaqueNode, StackingContext, StackingContextId, StackingContextType};
use gfx::font;
use gfx::font_cache_thread::FontCacheThread;
@ -114,6 +114,9 @@ pub struct LayoutThreadData {
/// A queued response for the client {top, left, width, height} of a node in pixels.
pub client_rect_response: Rect<i32>,
/// A queued response for the node at a given point
pub hit_test_response: (Option<DisplayItemMetadata>, bool),
/// A queued response for the resolved style property of an element.
pub resolved_style_response: Option<String>,
@ -458,6 +461,7 @@ impl LayoutThread {
content_box_response: Rect::zero(),
content_boxes_response: Vec::new(),
client_rect_response: Rect::zero(),
hit_test_response: (None, false),
resolved_style_response: None,
offset_parent_response: OffsetParentResponse::empty(),
margin_style_response: MarginStyleResponse::empty(),
@ -977,6 +981,9 @@ impl LayoutThread {
ReflowQueryType::ContentBoxesQuery(_) => {
rw_data.content_boxes_response = Vec::new();
},
ReflowQueryType::HitTestQuery(_, _) => {
rw_data.hit_test_response = (None, false);
},
ReflowQueryType::NodeGeometryQuery(_) => {
rw_data.client_rect_response = Rect::zero();
},
@ -1119,6 +1126,18 @@ impl LayoutThread {
let node = unsafe { ServoLayoutNode::new(&node) };
rw_data.content_boxes_response = process_content_boxes_request(node, &mut root_flow);
},
ReflowQueryType::HitTestQuery(point, update_cursor) => {
let point = Point2D::new(Au::from_f32_px(point.x), Au::from_f32_px(point.y));
let result = match rw_data.display_list {
None => panic!("Tried to hit test with no display list"),
Some(ref dl) => dl.hit_test(point),
};
rw_data.hit_test_response = if result.len() > 0 {
(Some(result[0]), update_cursor)
} else {
(None, update_cursor)
};
},
ReflowQueryType::NodeGeometryQuery(node) => {
let node = unsafe { ServoLayoutNode::new(&node) };
rw_data.client_rect_response = process_node_geometry_request(node, &mut root_flow);

View file

@ -51,6 +51,25 @@ impl LayoutRPC for LayoutRPCImpl {
ContentBoxesResponse(rw_data.content_boxes_response.clone())
}
/// Requests the node containing the point of interest.
fn hit_test(&self) -> HitTestResponse {
let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap();
let &(ref result, update_cursor) = &rw_data.hit_test_response;
if update_cursor {
// Compute the new cursor.
let cursor = match *result {
None => Cursor::DefaultCursor,
Some(dim) => dim.pointing.unwrap(),
};
let ConstellationChan(ref constellation_chan) = rw_data.constellation_chan;
constellation_chan.send(ConstellationMsg::SetCursor(cursor)).unwrap();
}
HitTestResponse {
node_address: result.map(|dim| dim.node.to_untrusted_node_address()),
}
}
fn node_geometry(&self) -> NodeGeometryResponse {
let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap();
@ -66,33 +85,6 @@ impl LayoutRPC for LayoutRPCImpl {
ResolvedStyleResponse(rw_data.resolved_style_response.clone())
}
/// Requests the node containing the point of interest.
fn hit_test(&self, point: Point2D<f32>, update_cursor: bool) -> Result<HitTestResponse, ()> {
let point = Point2D::new(Au::from_f32_px(point.x), Au::from_f32_px(point.y));
let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap();
let display_list = rw_data.display_list.as_ref().expect("Tried to hit test without a DisplayList!");
let result = display_list.hit_test(point);
if update_cursor {
let cursor = if !result.is_empty() {
result[0].pointing.unwrap()
} else {
Cursor::DefaultCursor
};
let ConstellationChan(ref constellation_chan) = rw_data.constellation_chan;
constellation_chan.send(ConstellationMsg::SetCursor(cursor)).unwrap();
};
if !result.is_empty() {
Ok(HitTestResponse(result[0].node.to_untrusted_node_address()))
} else {
Err(())
}
}
fn offset_parent(&self) -> OffsetParentResponse {
let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap();