compositing: Fix a couple of bugs that prevented iframes from painting

after navigation.

The first bug was that iframes were not reflowed in their parent DOM
when the child page navigated. This is fixed by simply having the
constellation notify the appropriate script thread when navigation
occurs.

The second bug was that the compositor was unable to adjust the pipeline
for existing iframe layers, only new ones. This patch adds logic to do
that.

Closes #8081.
This commit is contained in:
Patrick Walton 2016-01-12 20:57:23 -08:00 committed by Josh Matthews
parent 80c2911348
commit e5a1af5b7a
9 changed files with 153 additions and 26 deletions

View file

@ -790,6 +790,13 @@ impl<Window: WindowMethods> IOCompositor<Window> {
match self.find_layer_with_pipeline_and_layer_id(pipeline_id, properties.id) {
Some(existing_layer) => {
// If this layer contains a subpage, then create the root layer for that subpage
// now.
if properties.subpage_pipeline_id.is_some() {
self.create_root_layer_for_subpage_if_necessary(properties,
existing_layer.clone())
}
existing_layer.update_layer(properties);
true
}
@ -868,7 +875,30 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
// If this layer contains a subpage, then create the root layer for that subpage now.
if let Some(ref subpage_pipeline_id) = layer_properties.subpage_pipeline_id {
if layer_properties.subpage_pipeline_id.is_some() {
self.create_root_layer_for_subpage_if_necessary(layer_properties,
new_layer.clone())
}
parent_layer.add_child(new_layer.clone());
}
self.dump_layer_tree();
}
fn create_root_layer_for_subpage_if_necessary(&mut self,
layer_properties: LayerProperties,
parent_layer: Rc<Layer<CompositorData>>) {
if parent_layer.children
.borrow()
.iter()
.any(|child| child.extra_data.borrow().subpage_info.is_some()) {
return
}
let subpage_pipeline_id =
layer_properties.subpage_pipeline_id
.expect("create_root_layer_for_subpage() called for non-subpage?!");
let subpage_layer_properties = LayerProperties {
id: LayerId::null(),
parent_id: None,
@ -877,7 +907,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
scroll_policy: ScrollPolicy::Scrollable,
transform: Matrix4::identity(),
perspective: Matrix4::identity(),
subpage_pipeline_id: layer_properties.subpage_pipeline_id,
subpage_pipeline_id: Some(subpage_pipeline_id),
establishes_3d_context: true,
scrolls_overflow_area: true,
};
@ -887,19 +917,13 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} else {
WantsScrollEventsFlag::DoesntWantScrollEvents
};
let subpage_layer = CompositorData::new_layer(*subpage_pipeline_id,
let subpage_layer = CompositorData::new_layer(subpage_pipeline_id,
subpage_layer_properties,
wants_scroll_events,
new_layer.tile_size);
parent_layer.tile_size);
*subpage_layer.masks_to_bounds.borrow_mut() = true;
new_layer.add_child(subpage_layer);
self.pending_subpages.insert(*subpage_pipeline_id);
}
parent_layer.add_child(new_layer.clone());
}
self.dump_layer_tree();
parent_layer.add_child(subpage_layer);
self.pending_subpages.insert(subpage_pipeline_id);
}
fn send_window_size(&self) {

View file

@ -211,6 +211,7 @@ pub enum ScrollEventResult {
impl CompositorLayer for Layer<CompositorData> {
fn update_layer_except_bounds(&self, layer_properties: LayerProperties) {
self.extra_data.borrow_mut().scroll_policy = layer_properties.scroll_policy;
self.extra_data.borrow_mut().subpage_info = layer_properties.subpage_pipeline_id;
*self.transform.borrow_mut() = layer_properties.transform;
*self.perspective.borrow_mut() = layer_properties.perspective;

View file

@ -1325,6 +1325,17 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
fn handle_activate_document_msg(&mut self, pipeline_id: PipelineId) {
debug!("Document ready to activate {:?}", pipeline_id);
if let Some(ref child_pipeline) = self.pipelines.get(&pipeline_id) {
if let Some(ref parent_info) = child_pipeline.parent_info {
if let Some(parent_pipeline) = self.pipelines.get(&parent_info.0) {
let _ = parent_pipeline.script_chan
.send(ConstellationControlMsg::FramedContentChanged(
parent_info.0,
parent_info.1));
}
}
}
// If this pipeline is already part of the current frame tree,
// we don't need to do anything.
if self.pipeline_is_in_current_frame(pipeline_id) {

View file

@ -107,6 +107,7 @@ pub enum ReflowReason {
ImageLoaded,
RequestAnimationFrame,
WebFontLoaded,
FramedContentChanged,
}
pub type ScrollPoint = Point2D<Au>;
@ -1425,6 +1426,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason:
ReflowReason::ImageLoaded => "\tImageLoaded",
ReflowReason::RequestAnimationFrame => "\tRequestAnimationFrame",
ReflowReason::WebFontLoaded => "\tWebFontLoaded",
ReflowReason::FramedContentChanged => "\tFramedContentChanged",
});
println!("{}", debug_msg);

View file

@ -1131,6 +1131,8 @@ impl ScriptThread {
ConstellationControlMsg::DispatchFrameLoadEvent {
target: pipeline_id, parent: containing_id } =>
self.handle_frame_load_event(containing_id, pipeline_id),
ConstellationControlMsg::FramedContentChanged(containing_pipeline_id, subpage_id) =>
self.handle_framed_content_changed(containing_pipeline_id, subpage_id),
ConstellationControlMsg::ReportCSSError(pipeline_id, filename, line, column, msg) =>
self.handle_css_error_reporting(pipeline_id, filename, line, column, msg),
}
@ -1487,6 +1489,22 @@ impl ScriptThread {
}
}
fn handle_framed_content_changed(&self,
parent_pipeline_id: PipelineId,
subpage_id: SubpageId) {
let borrowed_page = self.root_page();
let page = borrowed_page.find(parent_pipeline_id).unwrap();
let doc = page.document();
let frame_element = doc.find_iframe(subpage_id);
if let Some(ref frame_element) = frame_element {
frame_element.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
let window = page.window();
window.reflow(ReflowGoal::ForDisplay,
ReflowQueryType::NoQuery,
ReflowReason::FramedContentChanged);
}
}
/// Handles a mozbrowser event, for example see:
/// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart
fn handle_mozbrowser_event_msg(&self,

View file

@ -143,6 +143,8 @@ pub enum ConstellationControlMsg {
/// The pipeline that contains a frame loading the target pipeline.
parent: PipelineId
},
/// Notifies a parent frame that one of its child frames is now active.
FramedContentChanged(PipelineId, SubpageId),
/// Report an error from a CSS parser for the given pipeline
ReportCSSError(PipelineId, String, u32, u32, String),
}

View file

@ -1688,6 +1688,18 @@
"url": "/_mozilla/css/iframe/multiple_external.html"
}
],
"css/iframe/navigation.html": [
{
"path": "css/iframe/navigation.html",
"references": [
[
"/_mozilla/css/iframe/navigation_ref.html",
"=="
]
],
"url": "/_mozilla/css/iframe/navigation.html"
}
],
"css/iframe/overflow.html": [
{
"path": "css/iframe/overflow.html",
@ -7756,6 +7768,18 @@
"url": "/_mozilla/css/iframe/multiple_external.html"
}
],
"css/iframe/navigation.html": [
{
"path": "css/iframe/navigation.html",
"references": [
[
"/_mozilla/css/iframe/navigation_ref.html",
"=="
]
],
"url": "/_mozilla/css/iframe/navigation.html"
}
],
"css/iframe/overflow.html": [
{
"path": "css/iframe/overflow.html",

View file

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel=match href=navigation_ref.html>
<style>
iframe {
display: block;
border: 1px solid black;
width: 500px;
height: 300px;
margin-left: 10px;
margin-top: 0px;
}
</style>
<body>
<iframe src="data:text/html,Foo"></iframe>
<script>
var iframe = document.getElementsByTagName('iframe')[0];
iframe.addEventListener('load', function first() {
iframe.removeEventListener('load', first);
iframe.src = "data:text/html,Hello%20world";
iframe.addEventListener('load', function() {
document.documentElement.classList.remove("reftest-wait");
}, false);
}, false);
</script>
</body>
</html>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<style>
iframe {
display: block;
border: 1px solid black;
width: 500px;
height: 300px;
margin-left: 10px;
margin-top: 0px;
}
</style>
<body>
<iframe src="data:text/html,Hello%20world"></iframe>
</body>
</html>