mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
layout: Make the compositor rather than layout determine the position of
each iframe. The old code that attempted to do this during layout wasn't able to work for multiple reasons: it couldn't know where the iframe was going to be on the page (because of nested iframes), and at the time it was building the display list for a fragment it couldn't know where that fragment was going to be in page coordinates. This patch rewrites that code so that both the sizes and positions of iframes are determined by the compositor. Layout layerizes all iframes and marks the iframe layers with the appropriate pipeline and subpage IDs so that the compositor can place them correctly. This approach is similar in spirit to Gecko's `RefLayer` infrastructure. The logic that determines when it is time to take the screenshot for reftests has been significantly revamped to deal with this change in delegation of responsibility. Additionally, this code removes the infrastructure that sends layout data back to the layout task to be destroyed, since it is now all thread-safe and can be destroyed on the script task. The failing tests now fail because of a pre-existing bug related to intrinsic heights and borders on inline replaced elements. They happened to pass before because we never rendered the iframes at all, which meant they never had a chance to draw the red border the tests expect to not render! Closes #7377.
This commit is contained in:
parent
ed0d70e234
commit
c72d0c2ed0
20 changed files with 602 additions and 389 deletions
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use compositor_layer::{CompositorData, CompositorLayer, WantsScrollEventsFlag};
|
||||
use compositor_layer::{CompositorData, CompositorLayer, RcCompositorLayer, WantsScrollEventsFlag};
|
||||
use compositor_task::{CompositorEventListener, CompositorProxy};
|
||||
use compositor_task::{CompositorReceiver, InitialCompositorState, Msg};
|
||||
use constellation::SendableFrameTree;
|
||||
|
@ -28,17 +28,16 @@ use msg::compositor_msg::{Epoch, FrameTreeId, LayerId, LayerKind};
|
|||
use msg::compositor_msg::{LayerProperties, ScrollPolicy};
|
||||
use msg::constellation_msg::AnimationState;
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::{ConstellationChan, NavigationDirection};
|
||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
|
||||
use msg::constellation_msg::{PipelineId, WindowSizeData};
|
||||
use msg::constellation_msg::{ConstellationChan, Key, KeyModifiers, KeyState, LoadData};
|
||||
use msg::constellation_msg::{NavigationDirection, PipelineId, SubpageId, WindowSizeData};
|
||||
use pipeline::CompositionPipeline;
|
||||
use png;
|
||||
use profile_traits::mem::{self, ReportKind, Reporter, ReporterRequest};
|
||||
use profile_traits::time::{self, ProfilerCategory, profile};
|
||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
|
||||
use scrolling::ScrollingTimerProxy;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::mem as std_mem;
|
||||
use std::rc::Rc;
|
||||
use std::slice::bytes::copy_memory;
|
||||
|
@ -49,8 +48,7 @@ use time::{precise_time_ns, precise_time_s};
|
|||
use url::Url;
|
||||
use util::geometry::{Au, PagePx, ScreenPx, ViewportPx};
|
||||
use util::opts;
|
||||
use windowing;
|
||||
use windowing::{MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
|
||||
use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
|
||||
|
||||
const BUFFER_MAP_SIZE: usize = 10000000;
|
||||
|
||||
|
@ -164,6 +162,14 @@ pub struct IOCompositor<Window: WindowMethods> {
|
|||
|
||||
/// A data structure to cache unused NativeSurfaces.
|
||||
surface_map: SurfaceMap,
|
||||
|
||||
/// Information about subpage layers that are pending. The keys in this map are the
|
||||
/// pipeline/subpage IDs of the parent.
|
||||
pending_subpage_layers: HashMap<(PipelineId, SubpageId), PendingSubpageLayerInfo>,
|
||||
|
||||
/// Pipeline IDs of subpages that the compositor has seen in a layer tree but which have not
|
||||
/// yet been painted.
|
||||
pending_subpages: HashSet<PipelineId>,
|
||||
}
|
||||
|
||||
pub struct ScrollEvent {
|
||||
|
@ -308,6 +314,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
has_seen_quit_event: false,
|
||||
ready_to_save_state: ReadyState::Unknown,
|
||||
surface_map: SurfaceMap::new(BUFFER_MAP_SIZE),
|
||||
pending_subpage_layers: HashMap::new(),
|
||||
pending_subpages: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,6 +377,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
(Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
self.pipeline_details(pipeline_id).current_epoch = epoch;
|
||||
|
||||
self.collect_old_layers(pipeline_id, &properties);
|
||||
for (index, layer_properties) in properties.iter().enumerate() {
|
||||
if index == 0 {
|
||||
|
@ -377,6 +386,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.create_or_update_descendant_layer(pipeline_id, *layer_properties);
|
||||
}
|
||||
}
|
||||
|
||||
self.send_buffer_requests_for_all_layers();
|
||||
}
|
||||
|
||||
|
@ -385,13 +395,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
chan.send(Some(self.native_display.clone())).unwrap();
|
||||
}
|
||||
|
||||
(Msg::SetLayerRect(pipeline_id, layer_id, rect),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
self.set_layer_rect(pipeline_id, layer_id, &rect);
|
||||
}
|
||||
|
||||
(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
self.pending_subpages.remove(&pipeline_id);
|
||||
|
||||
for (layer_id, new_layer_buffer_set) in replies {
|
||||
self.assign_painted_buffers(pipeline_id,
|
||||
layer_id,
|
||||
|
@ -509,6 +516,15 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.window.head_parsed();
|
||||
}
|
||||
|
||||
(Msg::CreateLayerForSubpage(parent_pipeline_id,
|
||||
parent_subpage_id,
|
||||
subpage_pipeline_id),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
self.create_layer_for_subpage(parent_pipeline_id,
|
||||
parent_subpage_id,
|
||||
subpage_pipeline_id);
|
||||
}
|
||||
|
||||
(Msg::CollectMemoryReports(reports_chan), ShutdownState::NotShuttingDown) => {
|
||||
let mut reports = vec![];
|
||||
let name = "compositor-task";
|
||||
|
@ -527,6 +543,15 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
reports_chan.send(reports);
|
||||
}
|
||||
|
||||
(Msg::PipelineExited(pipeline_id), _) => {
|
||||
self.pending_subpages.remove(&pipeline_id);
|
||||
|
||||
// FIXME(pcwalton): This is a total hack. But it'll get complicated to do this
|
||||
// properly, since we need to get rid of the pending subpage layers if either the
|
||||
// parent or the child layer goes away.
|
||||
self.pending_subpage_layers.clear();
|
||||
}
|
||||
|
||||
// When we are shutting_down, we need to avoid performing operations
|
||||
// such as Paint that may crash because we have begun tearing down
|
||||
// the rest of our resources.
|
||||
|
@ -573,16 +598,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
return self.pipeline_details.get_mut(&pipeline_id).unwrap();
|
||||
}
|
||||
|
||||
pub fn pipeline<'a>(&'a self, pipeline_id: PipelineId) -> &'a CompositionPipeline {
|
||||
pub fn pipeline<'a>(&'a self, pipeline_id: PipelineId) -> Option<&'a CompositionPipeline> {
|
||||
match self.pipeline_details.get(&pipeline_id) {
|
||||
Some(ref details) => {
|
||||
match details.pipeline {
|
||||
Some(ref pipeline) => pipeline,
|
||||
None => panic!("Compositor layer has an unitialized pipeline ({:?}).",
|
||||
pipeline_id),
|
||||
|
||||
}
|
||||
}
|
||||
Some(ref details) => details.pipeline.as_ref(),
|
||||
None => panic!("Compositor layer has an unknown pipeline ({:?}).", pipeline_id),
|
||||
}
|
||||
}
|
||||
|
@ -606,6 +624,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
new_constellation_chan: ConstellationChan) {
|
||||
response_chan.send(()).unwrap();
|
||||
|
||||
// There are now no more pending iframes.
|
||||
self.pending_subpages.clear();
|
||||
|
||||
self.root_pipeline = Some(frame_tree.pipeline.clone());
|
||||
|
||||
// If we have an old root layer, release all old tiles before replacing it.
|
||||
|
@ -614,9 +635,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
old_root_layer.clear_all_tiles(self)
|
||||
}
|
||||
|
||||
self.scene.root = Some(self.create_frame_tree_root_layers(frame_tree, None));
|
||||
self.scene.root = Some(self.create_root_layer_for_pipeline_and_size(&frame_tree.pipeline,
|
||||
None));
|
||||
self.scene.set_root_layer_size(self.window_size.as_f32());
|
||||
|
||||
self.create_pipeline_details_for_frame_tree(&frame_tree);
|
||||
|
||||
// Initialize the new constellation channel by sending it the root window size.
|
||||
self.constellation_chan = new_constellation_chan;
|
||||
self.send_window_size();
|
||||
|
@ -625,9 +649,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.composite_if_necessary(CompositingReason::NewFrameTree);
|
||||
}
|
||||
|
||||
fn create_root_layer_for_pipeline_and_rect(&mut self,
|
||||
fn create_root_layer_for_pipeline_and_size(&mut self,
|
||||
pipeline: &CompositionPipeline,
|
||||
frame_rect: Option<TypedRect<PagePx, f32>>)
|
||||
frame_size: Option<TypedSize2D<PagePx, f32>>)
|
||||
-> Rc<Layer<CompositorData>> {
|
||||
let layer_properties = LayerProperties {
|
||||
id: LayerId::null(),
|
||||
|
@ -637,6 +661,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
scroll_policy: ScrollPolicy::Scrollable,
|
||||
transform: Matrix4::identity(),
|
||||
perspective: Matrix4::identity(),
|
||||
subpage_layer_info: None,
|
||||
establishes_3d_context: true,
|
||||
scrolls_overflow_area: false,
|
||||
};
|
||||
|
@ -651,24 +676,20 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
// All root layers mask to bounds.
|
||||
*root_layer.masks_to_bounds.borrow_mut() = true;
|
||||
|
||||
if let Some(ref frame_rect) = frame_rect {
|
||||
let frame_rect = frame_rect.to_untyped();
|
||||
*root_layer.bounds.borrow_mut() = Rect::from_untyped(&frame_rect);
|
||||
if let Some(ref frame_size) = frame_size {
|
||||
let frame_size = frame_size.to_untyped();
|
||||
root_layer.bounds.borrow_mut().size = Size2D::from_untyped(&frame_size);
|
||||
}
|
||||
|
||||
return root_layer;
|
||||
}
|
||||
|
||||
fn create_frame_tree_root_layers(&mut self,
|
||||
frame_tree: &SendableFrameTree,
|
||||
frame_rect: Option<TypedRect<PagePx, f32>>)
|
||||
-> Rc<Layer<CompositorData>> {
|
||||
let root_layer = self.create_root_layer_for_pipeline_and_rect(&frame_tree.pipeline,
|
||||
frame_rect);
|
||||
fn create_pipeline_details_for_frame_tree(&mut self, frame_tree: &SendableFrameTree) {
|
||||
self.pipeline_details(frame_tree.pipeline.id).pipeline = Some(frame_tree.pipeline.clone());
|
||||
|
||||
for kid in &frame_tree.children {
|
||||
root_layer.add_child(self.create_frame_tree_root_layers(kid, kid.rect));
|
||||
self.create_pipeline_details_for_frame_tree(kid);
|
||||
}
|
||||
return root_layer;
|
||||
}
|
||||
|
||||
fn find_pipeline_root_layer(&self, pipeline_id: PipelineId)
|
||||
|
@ -687,7 +708,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
None => return,
|
||||
};
|
||||
|
||||
root_layer.collect_old_layers(self, pipeline_id, new_layers);
|
||||
let mut pipelines_removed = Vec::new();
|
||||
root_layer.collect_old_layers(self, pipeline_id, new_layers, &mut pipelines_removed);
|
||||
|
||||
for pipeline_removed in pipelines_removed.into_iter() {
|
||||
self.pending_subpage_layers.remove(&(pipeline_removed.parent_pipeline_id,
|
||||
pipeline_removed.parent_subpage_id));
|
||||
self.pending_subpages.remove(&pipeline_removed.child_pipeline_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_pipeline_root_layer(&mut self, pipeline_id: PipelineId) {
|
||||
|
@ -702,7 +730,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.pipeline_details.remove(&pipeline_id);
|
||||
}
|
||||
|
||||
fn update_layer_if_exists(&mut self, pipeline_id: PipelineId, properties: LayerProperties) -> bool {
|
||||
fn update_layer_if_exists(&mut self, pipeline_id: PipelineId, properties: LayerProperties)
|
||||
-> bool {
|
||||
match self.find_layer_with_pipeline_and_layer_id(pipeline_id, properties.id) {
|
||||
Some(existing_layer) => {
|
||||
existing_layer.update_layer(properties);
|
||||
|
@ -748,19 +777,23 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
layer_properties.id);
|
||||
}
|
||||
|
||||
fn create_or_update_descendant_layer(&mut self, pipeline_id: PipelineId, layer_properties: LayerProperties) {
|
||||
fn create_or_update_descendant_layer(&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
layer_properties: LayerProperties) {
|
||||
debug_assert!(layer_properties.parent_id.is_some());
|
||||
|
||||
if !self.update_layer_if_exists(pipeline_id, layer_properties) {
|
||||
self.create_descendant_layer(pipeline_id, layer_properties);
|
||||
}
|
||||
self.update_subpage_size_if_necessary(&layer_properties);
|
||||
self.scroll_layer_to_fragment_point_if_necessary(pipeline_id,
|
||||
layer_properties.id);
|
||||
}
|
||||
|
||||
fn create_descendant_layer(&self, pipeline_id: PipelineId, layer_properties: LayerProperties) {
|
||||
fn create_descendant_layer(&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
layer_properties: LayerProperties) {
|
||||
let parent_id = layer_properties.parent_id.unwrap();
|
||||
|
||||
if let Some(parent_layer) = self.find_layer_with_pipeline_and_layer_id(pipeline_id,
|
||||
parent_id) {
|
||||
let wants_scroll_events = if layer_properties.scrolls_overflow_area {
|
||||
|
@ -778,7 +811,69 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
*new_layer.masks_to_bounds.borrow_mut() = true
|
||||
}
|
||||
|
||||
parent_layer.add_child(new_layer);
|
||||
// If this layer contains a subpage, then create the root layer for that subpage now.
|
||||
if let Some(ref subpage_layer_info) = layer_properties.subpage_layer_info {
|
||||
let subpage_layer_properties = LayerProperties {
|
||||
id: LayerId::null(),
|
||||
parent_id: None,
|
||||
rect: Rect::new(Point2D::new(subpage_layer_info.origin.x.to_f32_px(),
|
||||
subpage_layer_info.origin.y.to_f32_px()),
|
||||
layer_properties.rect.size),
|
||||
background_color: layer_properties.background_color,
|
||||
scroll_policy: ScrollPolicy::Scrollable,
|
||||
transform: Matrix4::identity(),
|
||||
perspective: Matrix4::identity(),
|
||||
subpage_layer_info: layer_properties.subpage_layer_info,
|
||||
establishes_3d_context: true,
|
||||
scrolls_overflow_area: true,
|
||||
};
|
||||
|
||||
// We need to map from the (pipeline ID, subpage ID) pair to the pipeline ID of
|
||||
// the subpage itself. The constellation is the source of truth for that
|
||||
// information, so go ask it. In the meantime, store the information in the list of
|
||||
// pending subpage layers.
|
||||
self.pending_subpage_layers.insert((pipeline_id, subpage_layer_info.subpage_id),
|
||||
PendingSubpageLayerInfo {
|
||||
subpage_layer_properties: subpage_layer_properties,
|
||||
container_layer_id: layer_properties.id,
|
||||
});
|
||||
self.constellation_chan.0.send(ConstellationMsg::PrepareForSubpageLayerCreation(
|
||||
pipeline_id,
|
||||
subpage_layer_info.subpage_id)).unwrap();
|
||||
}
|
||||
|
||||
parent_layer.add_child(new_layer.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn create_layer_for_subpage(&mut self,
|
||||
parent_pipeline_id: PipelineId,
|
||||
parent_subpage_id: SubpageId,
|
||||
subpage_pipeline_id: Option<PipelineId>) {
|
||||
let subpage_pipeline_id = match subpage_pipeline_id {
|
||||
Some(subpage_pipeline_id) => subpage_pipeline_id,
|
||||
None => return,
|
||||
};
|
||||
if let Some(PendingSubpageLayerInfo {
|
||||
subpage_layer_properties,
|
||||
container_layer_id
|
||||
}) = self.pending_subpage_layers.remove(&(parent_pipeline_id, parent_subpage_id)) {
|
||||
if let Some(container_layer) =
|
||||
self.find_layer_with_pipeline_and_layer_id(parent_pipeline_id,
|
||||
container_layer_id) {
|
||||
let wants_scroll_events = if subpage_layer_properties.scrolls_overflow_area {
|
||||
WantsScrollEventsFlag::WantsScrollEvents
|
||||
} else {
|
||||
WantsScrollEventsFlag::DoesntWantScrollEvents
|
||||
};
|
||||
let subpage_layer = CompositorData::new_layer(subpage_pipeline_id,
|
||||
subpage_layer_properties,
|
||||
wants_scroll_events,
|
||||
container_layer.tile_size);
|
||||
*subpage_layer.masks_to_bounds.borrow_mut() = true;
|
||||
container_layer.add_child(subpage_layer);
|
||||
self.pending_subpages.insert(subpage_pipeline_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -795,6 +890,20 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
})).unwrap()
|
||||
}
|
||||
|
||||
/// Sends the size of the given subpage up to the constellation. This will often trigger a
|
||||
/// reflow of that subpage.
|
||||
fn update_subpage_size_if_necessary(&self, layer_properties: &LayerProperties) {
|
||||
let subpage_layer_info = match layer_properties.subpage_layer_info {
|
||||
Some(ref subpage_layer_info) => *subpage_layer_info,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let ConstellationChan(ref chan) = self.constellation_chan;
|
||||
chan.send(ConstellationMsg::FrameSize(subpage_layer_info.pipeline_id,
|
||||
subpage_layer_info.subpage_id,
|
||||
layer_properties.rect.size)).unwrap();
|
||||
}
|
||||
|
||||
pub fn move_layer(&self,
|
||||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId,
|
||||
|
@ -835,21 +944,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.composition_request = CompositionRequest::CompositeOnScrollTimeout(timestamp);
|
||||
}
|
||||
|
||||
fn set_layer_rect(&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId,
|
||||
new_rect: &Rect<f32>) {
|
||||
match self.find_layer_with_pipeline_and_layer_id(pipeline_id, layer_id) {
|
||||
Some(ref layer) => {
|
||||
*layer.bounds.borrow_mut() = Rect::from_untyped(new_rect)
|
||||
}
|
||||
None => panic!("Compositor received SetLayerRect for nonexistent \
|
||||
layer: {:?}", pipeline_id),
|
||||
};
|
||||
|
||||
self.send_buffer_requests_for_all_layers();
|
||||
}
|
||||
|
||||
fn assign_painted_buffers(&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId,
|
||||
|
@ -862,7 +956,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
// loaded and the frame tree changes. This can result in the compositor thinking it
|
||||
// has already drawn the most recently painted buffer, and missing a frame.
|
||||
if frame_tree_id == self.frame_tree_id {
|
||||
if let Some(layer) = self.find_layer_with_pipeline_and_layer_id(pipeline_id, layer_id) {
|
||||
if let Some(layer) = self.find_layer_with_pipeline_and_layer_id(pipeline_id,
|
||||
layer_id) {
|
||||
let requested_epoch = layer.extra_data.borrow().requested_epoch;
|
||||
if requested_epoch == epoch {
|
||||
self.assign_painted_buffers_to_layer(layer, new_layer_buffer_set, epoch);
|
||||
|
@ -1250,7 +1345,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
|
||||
for (layer, mut layer_requests) in requests {
|
||||
let pipeline_id = layer.pipeline_id();
|
||||
let current_epoch = self.pipeline_details.get(&pipeline_id).unwrap().current_epoch;
|
||||
let current_epoch = self.pipeline_details(pipeline_id).current_epoch;
|
||||
layer.extra_data.borrow_mut().requested_epoch = current_epoch;
|
||||
let vec = match results.entry(pipeline_id) {
|
||||
Occupied(entry) => {
|
||||
|
@ -1291,8 +1386,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
if layer.extra_data.borrow().id == LayerId::null() {
|
||||
let layer_rect = Rect::new(-layer.extra_data.borrow().scroll_offset.to_untyped(),
|
||||
layer.bounds.borrow().size.to_untyped());
|
||||
let pipeline = self.pipeline(layer.pipeline_id());
|
||||
pipeline.script_chan.send(ConstellationControlMsg::Viewport(pipeline.id.clone(), layer_rect)).unwrap();
|
||||
if let Some(pipeline) = self.pipeline(layer.pipeline_id()) {
|
||||
pipeline.script_chan.send(ConstellationControlMsg::Viewport(pipeline.id.clone(),
|
||||
layer_rect)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
for kid in &*layer.children() {
|
||||
|
@ -1333,7 +1430,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
|
||||
for (pipeline_id, requests) in pipeline_requests {
|
||||
let msg = ChromeToPaintMsg::Paint(requests, self.frame_tree_id);
|
||||
let _ = self.pipeline(pipeline_id).chrome_to_paint_chan.send(msg);
|
||||
if let Some(pipeline) = self.pipeline(pipeline_id) {
|
||||
pipeline.chrome_to_paint_chan.send(msg).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
|
@ -1341,9 +1440,13 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
|
||||
/// Check if a layer (or its children) have any outstanding paint
|
||||
/// results to arrive yet.
|
||||
fn does_layer_have_outstanding_paint_messages(&self, layer: &Rc<Layer<CompositorData>>) -> bool {
|
||||
fn does_layer_have_outstanding_paint_messages(&self, layer: &Rc<Layer<CompositorData>>)
|
||||
-> bool {
|
||||
let layer_data = layer.extra_data.borrow();
|
||||
let current_epoch = self.pipeline_details.get(&layer_data.pipeline_id).unwrap().current_epoch;
|
||||
let current_epoch = match self.pipeline_details.get(&layer_data.pipeline_id) {
|
||||
None => return false,
|
||||
Some(ref details) => details.current_epoch,
|
||||
};
|
||||
|
||||
// Only check layers that have requested the current epoch, as there may be
|
||||
// layers that are not visible in the current viewport, and therefore
|
||||
|
@ -1390,6 +1493,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if there are any pending frames. If so, the image is not stable yet.
|
||||
if self.pending_subpage_layers.len() > 0 || self.pending_subpages.len() > 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Collect the currently painted epoch of each pipeline that is
|
||||
// complete (i.e. has *all* layers painted to the requested epoch).
|
||||
// This gets sent to the constellation for comparison with the current
|
||||
|
@ -1805,3 +1913,16 @@ pub enum CompositingReason {
|
|||
/// The window has been zoomed.
|
||||
Zoom,
|
||||
}
|
||||
|
||||
struct PendingSubpageLayerInfo {
|
||||
subpage_layer_properties: LayerProperties,
|
||||
container_layer_id: LayerId,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct RemovedPipelineInfo {
|
||||
pub parent_pipeline_id: PipelineId,
|
||||
pub parent_subpage_id: SubpageId,
|
||||
pub child_pipeline_id: PipelineId,
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use azure::azure_hl;
|
||||
use compositor::IOCompositor;
|
||||
use compositor::{IOCompositor, RemovedPipelineInfo};
|
||||
use euclid::length::Length;
|
||||
use euclid::point::{Point2D, TypedPoint2D};
|
||||
use euclid::rect::Rect;
|
||||
|
@ -12,7 +12,7 @@ use layers::color::Color;
|
|||
use layers::geometry::LayerPixel;
|
||||
use layers::layers::{Layer, LayerBufferSet};
|
||||
use msg::compositor_msg::{Epoch, LayerId, LayerProperties, ScrollPolicy};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use msg::constellation_msg::{PipelineId, SubpageId};
|
||||
use script_traits::CompositorEvent::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent};
|
||||
use script_traits::ConstellationControlMsg;
|
||||
use std::rc::Rc;
|
||||
|
@ -42,6 +42,9 @@ pub struct CompositorData {
|
|||
/// The scroll offset originating from this scrolling root. This allows scrolling roots
|
||||
/// to track their current scroll position even while their content_offset does not change.
|
||||
pub scroll_offset: TypedPoint2D<LayerPixel, f32>,
|
||||
|
||||
/// The pipeline ID and subpage ID of this layer, if it represents a subpage.
|
||||
pub subpage_info: Option<(PipelineId, SubpageId)>,
|
||||
}
|
||||
|
||||
impl CompositorData {
|
||||
|
@ -58,6 +61,9 @@ impl CompositorData {
|
|||
requested_epoch: Epoch(0),
|
||||
painted_epoch: Epoch(0),
|
||||
scroll_offset: Point2D::typed(0., 0.),
|
||||
subpage_info: layer_properties.subpage_layer_info.map(|subpage_layer_info| {
|
||||
(subpage_layer_info.pipeline_id, subpage_layer_info.subpage_id)
|
||||
}),
|
||||
};
|
||||
|
||||
Rc::new(Layer::new(Rect::from_untyped(&layer_properties.rect),
|
||||
|
@ -97,14 +103,6 @@ pub trait CompositorLayer {
|
|||
pipeline_id: PipelineId)
|
||||
where Window: WindowMethods;
|
||||
|
||||
/// Traverses the existing layer hierarchy and removes any layers that
|
||||
/// currently exist but which are no longer required.
|
||||
fn collect_old_layers<Window>(&self,
|
||||
compositor: &mut IOCompositor<Window>,
|
||||
pipeline_id: PipelineId,
|
||||
new_layers: &[LayerProperties])
|
||||
where Window: WindowMethods;
|
||||
|
||||
/// Destroys all tiles of all layers, including children, *without* sending them back to the
|
||||
/// painter. You must call this only when the paint task is destined to be going down;
|
||||
/// otherwise, you will leak tiles.
|
||||
|
@ -151,6 +149,17 @@ pub trait CompositorLayer {
|
|||
fn pipeline_id(&self) -> PipelineId;
|
||||
}
|
||||
|
||||
pub trait RcCompositorLayer {
|
||||
/// Traverses the existing layer hierarchy and removes any layers that
|
||||
/// currently exist but which are no longer required.
|
||||
fn collect_old_layers<Window>(&self,
|
||||
compositor: &mut IOCompositor<Window>,
|
||||
pipeline_id: PipelineId,
|
||||
new_layers: &[LayerProperties],
|
||||
pipelines_removed: &mut Vec<RemovedPipelineInfo>)
|
||||
where Window: WindowMethods;
|
||||
}
|
||||
|
||||
#[derive(Copy, PartialEq, Clone, Debug)]
|
||||
pub enum WantsScrollEventsFlag {
|
||||
WantsScrollEvents,
|
||||
|
@ -279,43 +288,6 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_old_layers<Window>(&self,
|
||||
compositor: &mut IOCompositor<Window>,
|
||||
pipeline_id: PipelineId,
|
||||
new_layers: &[LayerProperties])
|
||||
where Window: WindowMethods {
|
||||
// Traverse children first so that layers are removed
|
||||
// bottom up - allowing each layer being removed to properly
|
||||
// clean up any tiles it owns.
|
||||
for kid in &*self.children() {
|
||||
kid.collect_old_layers(compositor, pipeline_id, new_layers);
|
||||
}
|
||||
|
||||
// Retain child layers that also exist in the new layer list.
|
||||
self.children().retain(|child| {
|
||||
let extra_data = child.extra_data.borrow();
|
||||
|
||||
// Never remove root layers or layers from other pipelines.
|
||||
if pipeline_id != extra_data.pipeline_id ||
|
||||
extra_data.id == LayerId::null() {
|
||||
true
|
||||
} else {
|
||||
// Keep this layer if it exists in the new layer list.
|
||||
let keep_layer = new_layers.iter().any(|properties| {
|
||||
properties.id == extra_data.id
|
||||
});
|
||||
|
||||
// When removing a layer, clear any tiles and surfaces
|
||||
// associated with the layer.
|
||||
if !keep_layer {
|
||||
child.clear_all_tiles(compositor);
|
||||
}
|
||||
|
||||
keep_layer
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Destroys all tiles of all layers, including children, *without* sending them back to the
|
||||
/// painter. You must call this only when the paint task is destined to be going down;
|
||||
/// otherwise, you will leak tiles.
|
||||
|
@ -403,8 +375,11 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
MouseUpEvent(button, event_point),
|
||||
};
|
||||
|
||||
let pipeline = compositor.pipeline(self.pipeline_id());
|
||||
let _ = pipeline.script_chan.send(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message));
|
||||
if let Some(pipeline) = compositor.pipeline(self.pipeline_id()) {
|
||||
pipeline.script_chan
|
||||
.send(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn send_mouse_move_event<Window>(&self,
|
||||
|
@ -412,8 +387,11 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
cursor: TypedPoint2D<LayerPixel, f32>)
|
||||
where Window: WindowMethods {
|
||||
let message = MouseMoveEvent(cursor.to_untyped());
|
||||
let pipeline = compositor.pipeline(self.pipeline_id());
|
||||
let _ = pipeline.script_chan.send(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message));
|
||||
if let Some(pipeline) = compositor.pipeline(self.pipeline_id()) {
|
||||
pipeline.script_chan
|
||||
.send(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_layer_and_all_child_layers(&self, new_offset: TypedPoint2D<LayerPixel, f32>)
|
||||
|
@ -443,3 +421,97 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
self.extra_data.borrow().pipeline_id
|
||||
}
|
||||
}
|
||||
|
||||
impl RcCompositorLayer for Rc<Layer<CompositorData>> {
|
||||
fn collect_old_layers<Window>(&self,
|
||||
compositor: &mut IOCompositor<Window>,
|
||||
pipeline_id: PipelineId,
|
||||
new_layers: &[LayerProperties],
|
||||
pipelines_removed: &mut Vec<RemovedPipelineInfo>)
|
||||
where Window: WindowMethods {
|
||||
fn find_root_layer_for_pipeline(layer: &Rc<Layer<CompositorData>>, pipeline_id: PipelineId)
|
||||
-> Option<Rc<Layer<CompositorData>>> {
|
||||
let extra_data = layer.extra_data.borrow();
|
||||
if extra_data.pipeline_id == pipeline_id {
|
||||
return Some((*layer).clone())
|
||||
}
|
||||
|
||||
for kid in &*layer.children() {
|
||||
if let Some(layer) = find_root_layer_for_pipeline(kid, pipeline_id) {
|
||||
return Some(layer.clone())
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn collect_old_layers_for_pipeline<Window>(
|
||||
layer: &Layer<CompositorData>,
|
||||
compositor: &mut IOCompositor<Window>,
|
||||
pipeline_id: PipelineId,
|
||||
new_layers: &[LayerProperties],
|
||||
pipelines_removed: &mut Vec<RemovedPipelineInfo>)
|
||||
where Window: WindowMethods {
|
||||
// Traverse children first so that layers are removed
|
||||
// bottom up - allowing each layer being removed to properly
|
||||
// clean up any tiles it owns.
|
||||
for kid in &*layer.children() {
|
||||
collect_old_layers_for_pipeline(kid,
|
||||
compositor,
|
||||
pipeline_id,
|
||||
new_layers,
|
||||
pipelines_removed);
|
||||
}
|
||||
|
||||
// Retain child layers that also exist in the new layer list.
|
||||
layer.children().retain(|child| {
|
||||
let extra_data = child.extra_data.borrow();
|
||||
if pipeline_id == extra_data.pipeline_id {
|
||||
// Never remove our own root layer.
|
||||
if extra_data.id == LayerId::null() {
|
||||
return true
|
||||
}
|
||||
|
||||
// Keep this layer if it exists in the new layer list.
|
||||
return new_layers.iter().any(|properties| properties.id == extra_data.id);
|
||||
}
|
||||
|
||||
if let Some(ref subpage_info_for_this_layer) = extra_data.subpage_info {
|
||||
for layer_properties in new_layers.iter() {
|
||||
// Keep this layer if a reference to it exists.
|
||||
if let Some(ref subpage_layer_info) = layer_properties.subpage_layer_info {
|
||||
if subpage_layer_info.pipeline_id == subpage_info_for_this_layer.0 &&
|
||||
subpage_layer_info.subpage_id ==
|
||||
subpage_info_for_this_layer.1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pipelines_removed.push(RemovedPipelineInfo {
|
||||
parent_pipeline_id: subpage_info_for_this_layer.0,
|
||||
parent_subpage_id: subpage_info_for_this_layer.1,
|
||||
child_pipeline_id: extra_data.pipeline_id,
|
||||
});
|
||||
}
|
||||
|
||||
// When removing a layer, clear any tiles and surfaces associated with the layer.
|
||||
child.clear_all_tiles(compositor);
|
||||
false
|
||||
});
|
||||
}
|
||||
|
||||
// First, find the root layer with the given pipeline ID.
|
||||
let root_layer = match find_root_layer_for_pipeline(self, pipeline_id) {
|
||||
Some(root_layer) => root_layer,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Then collect all old layers underneath that layer.
|
||||
collect_old_layers_for_pipeline(&root_layer,
|
||||
compositor,
|
||||
pipeline_id,
|
||||
new_layers,
|
||||
pipelines_removed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
//! Communication with the compositor task.
|
||||
|
||||
use compositor;
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
use euclid::{Point2D, Size2D};
|
||||
use headless;
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
use layers::layers::{BufferRequest, LayerBufferSet};
|
||||
use layers::platform::surface::{NativeDisplay, NativeSurface};
|
||||
use msg::compositor_msg::{Epoch, FrameTreeId, LayerId, LayerProperties};
|
||||
use msg::compositor_msg::{PaintListener, ScriptToCompositorMsg};
|
||||
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
|
||||
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId, SubpageId};
|
||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||
use png;
|
||||
use profile_traits::mem;
|
||||
|
@ -64,7 +64,10 @@ pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'stati
|
|||
while let Ok(msg) = receiver.recv() {
|
||||
match msg {
|
||||
ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth) => {
|
||||
compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth));
|
||||
compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id,
|
||||
layer_id,
|
||||
point,
|
||||
_smooth));
|
||||
}
|
||||
|
||||
ScriptToCompositorMsg::GetClientWindow(send) => {
|
||||
|
@ -165,8 +168,6 @@ pub enum Msg {
|
|||
/// Tells the compositor to create or update the layers for a pipeline if necessary
|
||||
/// (i.e. if no layer with that ID exists).
|
||||
InitializeLayersForPipeline(PipelineId, Epoch, Vec<LayerProperties>),
|
||||
/// Alerts the compositor that the specified layer's rect has changed.
|
||||
SetLayerRect(PipelineId, LayerId, Rect<f32>),
|
||||
/// Scroll a page in a window
|
||||
ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
|
||||
/// Requests that the compositor assign the painted buffers to the given layers.
|
||||
|
@ -216,6 +217,12 @@ pub enum Msg {
|
|||
MoveTo(Point2D<i32>),
|
||||
/// Resize the window to size
|
||||
ResizeTo(Size2D<u32>),
|
||||
/// A pipeline was shut down.
|
||||
PipelineExited(PipelineId),
|
||||
/// The layer for a subpage should be created. The first two IDs are the IDs of the *parent*
|
||||
/// pipeline and subpage, respectively, while the last ID is the pipeline ID of the subpage
|
||||
/// itself (or `None` if it has shut down).
|
||||
CreateLayerForSubpage(PipelineId, SubpageId, Option<PipelineId>),
|
||||
}
|
||||
|
||||
impl Debug for Msg {
|
||||
|
@ -225,7 +232,6 @@ impl Debug for Msg {
|
|||
Msg::ShutdownComplete(..) => write!(f, "ShutdownComplete"),
|
||||
Msg::GetNativeDisplay(..) => write!(f, "GetNativeDisplay"),
|
||||
Msg::InitializeLayersForPipeline(..) => write!(f, "InitializeLayersForPipeline"),
|
||||
Msg::SetLayerRect(..) => write!(f, "SetLayerRect"),
|
||||
Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"),
|
||||
Msg::AssignPaintedBuffers(..) => write!(f, "AssignPaintedBuffers"),
|
||||
Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"),
|
||||
|
@ -250,6 +256,8 @@ impl Debug for Msg {
|
|||
Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
|
||||
Msg::MoveTo(..) => write!(f, "MoveTo"),
|
||||
Msg::ResizeTo(..) => write!(f, "ResizeTo"),
|
||||
Msg::PipelineExited(..) => write!(f, "PipelineExited"),
|
||||
Msg::CreateLayerForSubpage(..) => write!(f, "CreateLayerForSubpage"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,12 @@ use clipboard::ClipboardContext;
|
|||
use compositor_task::CompositorProxy;
|
||||
use compositor_task::Msg as CompositorMsg;
|
||||
use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
|
||||
use euclid::point::Point2D;
|
||||
use euclid::rect::{Rect, TypedRect};
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::Size2D;
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
use gfx::font_cache_task::FontCacheTask;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use layout_traits::{LayoutControlChan, LayoutTaskFactory};
|
||||
use msg::compositor_msg::{Epoch, LayerId};
|
||||
use msg::compositor_msg::Epoch;
|
||||
use msg::constellation_msg::AnimationState;
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::WebDriverCommandMsg;
|
||||
|
@ -136,6 +134,10 @@ pub struct Constellation<LTF, STF> {
|
|||
|
||||
/// A list of in-process senders to `WebGLPaintTask`s.
|
||||
webgl_paint_tasks: Vec<Sender<CanvasMsg>>,
|
||||
|
||||
/// A list of senders that are waiting to be notified whenever a pipeline or subpage ID comes
|
||||
/// in.
|
||||
subpage_id_senders: HashMap<(PipelineId, SubpageId), Vec<IpcSender<PipelineId>>>,
|
||||
}
|
||||
|
||||
/// State needed to construct a constellation.
|
||||
|
@ -217,7 +219,7 @@ impl<'a> Iterator for FrameTreeIterator<'a> {
|
|||
|
||||
pub struct SendableFrameTree {
|
||||
pub pipeline: CompositionPipeline,
|
||||
pub rect: Option<TypedRect<PagePx, f32>>,
|
||||
pub size: Option<TypedSize2D<PagePx, f32>>,
|
||||
pub children: Vec<SendableFrameTree>,
|
||||
}
|
||||
|
||||
|
@ -280,6 +282,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
webdriver: WebDriverData::new(),
|
||||
canvas_paint_tasks: Vec::new(),
|
||||
webgl_paint_tasks: Vec::new(),
|
||||
subpage_id_senders: HashMap::new(),
|
||||
};
|
||||
constellation.run();
|
||||
});
|
||||
|
@ -298,7 +301,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
/// Helper function for creating a pipeline
|
||||
fn new_pipeline(&mut self,
|
||||
parent_info: Option<(PipelineId, SubpageId)>,
|
||||
initial_window_rect: Option<TypedRect<PagePx, f32>>,
|
||||
initial_window_size: Option<TypedSize2D<PagePx, f32>>,
|
||||
script_channel: Option<Sender<ConstellationControlMsg>>,
|
||||
load_data: LoadData)
|
||||
-> PipelineId {
|
||||
|
@ -320,7 +323,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
storage_task: self.storage_task.clone(),
|
||||
time_profiler_chan: self.time_profiler_chan.clone(),
|
||||
mem_profiler_chan: self.mem_profiler_chan.clone(),
|
||||
window_rect: initial_window_rect,
|
||||
window_size: initial_window_size,
|
||||
script_chan: script_channel,
|
||||
load_data: load_data,
|
||||
device_pixel_ratio: self.window_size.device_pixel_ratio,
|
||||
|
@ -396,11 +399,11 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
debug!("constellation got init load URL message");
|
||||
self.handle_init_load(url);
|
||||
}
|
||||
// A layout assigned a size and position to a subframe. This needs to be reflected by
|
||||
// all frame trees in the navigation context containing the subframe.
|
||||
ConstellationMsg::FrameRect(pipeline_id, subpage_id, rect) => {
|
||||
debug!("constellation got frame rect message");
|
||||
self.handle_frame_rect_msg(pipeline_id, subpage_id, Rect::from_untyped(&rect));
|
||||
// The compositor discovered the size of a subframe. This needs to be reflected by all
|
||||
// frame trees in the navigation context containing the subframe.
|
||||
ConstellationMsg::FrameSize(pipeline_id, subpage_id, size) => {
|
||||
debug!("constellation got frame size message");
|
||||
self.handle_frame_size_msg(pipeline_id, subpage_id, &Size2D::from_untyped(&size));
|
||||
}
|
||||
ConstellationMsg::ScriptLoadedURLInIFrame(url,
|
||||
source_pipeline_id,
|
||||
|
@ -417,7 +420,9 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
old_subpage_id,
|
||||
sandbox);
|
||||
}
|
||||
ConstellationMsg::SetCursor(cursor) => self.handle_set_cursor_msg(cursor),
|
||||
ConstellationMsg::SetCursor(cursor) => {
|
||||
self.handle_set_cursor_msg(cursor)
|
||||
}
|
||||
ConstellationMsg::ChangeRunningAnimationsState(pipeline_id, animation_state) => {
|
||||
self.handle_change_running_animations_state(pipeline_id, animation_state)
|
||||
}
|
||||
|
@ -537,6 +542,12 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
debug!("constellation got NodeStatus message");
|
||||
self.compositor_proxy.send(CompositorMsg::Status(message));
|
||||
}
|
||||
ConstellationMsg::PrepareForSubpageLayerCreation(pipeline_id, subpage_id) => {
|
||||
self.compositor_proxy.send(CompositorMsg::CreateLayerForSubpage(
|
||||
pipeline_id,
|
||||
subpage_id,
|
||||
self.subpage_map.get(&(pipeline_id, subpage_id)).map(|x| *x)))
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -585,10 +596,10 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
}
|
||||
debug!("creating replacement pipeline for about:failure");
|
||||
|
||||
let window_rect = self.pipeline(pipeline_id).rect;
|
||||
let window_size = self.pipeline(pipeline_id).size;
|
||||
let new_pipeline_id =
|
||||
self.new_pipeline(parent_info,
|
||||
window_rect,
|
||||
window_size,
|
||||
None,
|
||||
LoadData::new(Url::parse("about:failure").unwrap()));
|
||||
|
||||
|
@ -596,44 +607,39 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
}
|
||||
|
||||
fn handle_init_load(&mut self, url: Url) {
|
||||
let window_rect = Rect::new(Point2D::zero(), self.window_size.visible_viewport);
|
||||
let window_size = self.window_size.visible_viewport;
|
||||
let root_pipeline_id =
|
||||
self.new_pipeline(None, Some(window_rect), None, LoadData::new(url.clone()));
|
||||
self.new_pipeline(None, Some(window_size), None, LoadData::new(url.clone()));
|
||||
self.handle_load_start_msg(&root_pipeline_id);
|
||||
self.push_pending_frame(root_pipeline_id, None);
|
||||
self.compositor_proxy.send(CompositorMsg::ChangePageUrl(root_pipeline_id, url));
|
||||
}
|
||||
|
||||
fn handle_frame_rect_msg(&mut self, containing_pipeline_id: PipelineId, subpage_id: SubpageId,
|
||||
rect: TypedRect<PagePx, f32>) {
|
||||
fn handle_frame_size_msg(&mut self,
|
||||
containing_pipeline_id: PipelineId,
|
||||
subpage_id: SubpageId,
|
||||
size: &TypedSize2D<PagePx, f32>) {
|
||||
// Store the new rect inside the pipeline
|
||||
let (pipeline_id, script_chan) = {
|
||||
// Find the pipeline that corresponds to this rectangle. It's possible that this
|
||||
// pipeline may have already exited before we process this message, so just
|
||||
// early exit if that occurs.
|
||||
let pipeline_id = self.subpage_map.get(&(containing_pipeline_id, subpage_id)).map(|id| *id);
|
||||
let pipeline_id = self.subpage_map
|
||||
.get(&(containing_pipeline_id, subpage_id))
|
||||
.map(|id| *id);
|
||||
let pipeline = match pipeline_id {
|
||||
Some(pipeline_id) => self.mut_pipeline(pipeline_id),
|
||||
None => return,
|
||||
};
|
||||
pipeline.rect = Some(rect);
|
||||
pipeline.size = Some(*size);
|
||||
(pipeline.id, pipeline.script_chan.clone())
|
||||
};
|
||||
|
||||
script_chan.send(ConstellationControlMsg::Resize(pipeline_id, WindowSizeData {
|
||||
visible_viewport: rect.size,
|
||||
initial_viewport: rect.size * ScaleFactor::new(1.0),
|
||||
visible_viewport: *size,
|
||||
initial_viewport: *size * ScaleFactor::new(1.0),
|
||||
device_pixel_ratio: self.window_size.device_pixel_ratio,
|
||||
})).unwrap();
|
||||
|
||||
// If this pipeline is in the current frame tree,
|
||||
// send the updated rect to the script and compositor tasks
|
||||
if self.pipeline_is_in_current_frame(pipeline_id) {
|
||||
self.compositor_proxy.send(CompositorMsg::SetLayerRect(
|
||||
pipeline_id,
|
||||
LayerId::null(),
|
||||
rect.to_untyped()));
|
||||
}
|
||||
}
|
||||
|
||||
// The script task associated with pipeline_id has loaded a URL in an iframe via script. This
|
||||
|
@ -674,14 +680,24 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
let old_pipeline_id = old_subpage_id.map(|old_subpage_id| {
|
||||
self.find_subpage(containing_pipeline_id, old_subpage_id).id
|
||||
});
|
||||
let window_rect = old_pipeline_id.and_then(|old_pipeline_id| {
|
||||
self.pipeline(old_pipeline_id).rect
|
||||
let window_size = old_pipeline_id.and_then(|old_pipeline_id| {
|
||||
self.pipeline(old_pipeline_id).size
|
||||
});
|
||||
let new_pipeline_id = self.new_pipeline(Some((containing_pipeline_id, new_subpage_id)),
|
||||
window_rect,
|
||||
window_size,
|
||||
script_chan,
|
||||
LoadData::new(url));
|
||||
|
||||
self.subpage_map.insert((containing_pipeline_id, new_subpage_id), new_pipeline_id);
|
||||
|
||||
// If anyone is waiting to know the pipeline ID, send that information now.
|
||||
if let Some(subpage_id_senders) = self.subpage_id_senders.remove(&(containing_pipeline_id,
|
||||
new_subpage_id)) {
|
||||
for subpage_id_sender in subpage_id_senders.into_iter() {
|
||||
subpage_id_sender.send(new_pipeline_id).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
self.push_pending_frame(new_pipeline_id, old_pipeline_id);
|
||||
}
|
||||
|
||||
|
@ -739,8 +755,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
// changes would be overridden by changing the subframe associated with source_id.
|
||||
|
||||
// Create the new pipeline
|
||||
let window_rect = self.pipeline(source_id).rect;
|
||||
let new_pipeline_id = self.new_pipeline(None, window_rect, None, load_data);
|
||||
let window_size = self.pipeline(source_id).size;
|
||||
let new_pipeline_id = self.new_pipeline(None, window_size, None, load_data);
|
||||
self.push_pending_frame(new_pipeline_id, Some(source_id));
|
||||
|
||||
// Send message to ScriptTask that will suspend all timers
|
||||
|
@ -954,7 +970,9 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
self.focus_parent_pipeline(pipeline_id);
|
||||
}
|
||||
|
||||
fn handle_remove_iframe_msg(&mut self, containing_pipeline_id: PipelineId, subpage_id: SubpageId) {
|
||||
fn handle_remove_iframe_msg(&mut self,
|
||||
containing_pipeline_id: PipelineId,
|
||||
subpage_id: SubpageId) {
|
||||
let pipeline_id = self.find_subpage(containing_pipeline_id, subpage_id).id;
|
||||
let frame_id = self.pipeline_to_frame_map.get(&pipeline_id).map(|id| *id);
|
||||
match frame_id {
|
||||
|
@ -1172,7 +1190,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
for pending_frame in &self.pending_frames {
|
||||
let pipeline = self.pipelines.get(&pending_frame.new_pipeline_id).unwrap();
|
||||
if pipeline.parent_info.is_none() {
|
||||
let _ = pipeline.script_chan.send(ConstellationControlMsg::Resize(pipeline.id, new_size));
|
||||
let _ = pipeline.script_chan.send(ConstellationControlMsg::Resize(pipeline.id,
|
||||
new_size));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1180,7 +1199,9 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
}
|
||||
|
||||
/// Handle updating actual viewport / zoom due to @viewport rules
|
||||
fn handle_viewport_constrained_msg(&mut self, pipeline_id: PipelineId, constraints: ViewportConstraints) {
|
||||
fn handle_viewport_constrained_msg(&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
constraints: ViewportConstraints) {
|
||||
self.compositor_proxy.send(CompositorMsg::ViewportConstrained(pipeline_id, constraints));
|
||||
}
|
||||
|
||||
|
@ -1196,12 +1217,6 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
return false;
|
||||
}
|
||||
|
||||
// If there are pending changes to the current frame
|
||||
// tree, the image is not stable yet.
|
||||
if self.pending_frames.len() > 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step through the current frame tree, checking that the script
|
||||
// task is idle, and that the current epoch of the layout task
|
||||
// matches what the compositor has painted. If all these conditions
|
||||
|
@ -1215,12 +1230,11 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
let (sender, receiver) = channel();
|
||||
let msg = ConstellationControlMsg::GetCurrentState(sender, frame.current);
|
||||
pipeline.script_chan.send(msg).unwrap();
|
||||
if receiver.recv().unwrap() == ScriptState::DocumentLoading {
|
||||
let result = receiver.recv().unwrap();
|
||||
if result == ScriptState::DocumentLoading {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Synchronously query the layout task for this pipeline
|
||||
// to see if it is idle.
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
let msg = LayoutControlMsg::GetWebFontLoadState(sender);
|
||||
pipeline.layout_chan.0.send(msg).unwrap();
|
||||
|
@ -1228,15 +1242,15 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Check the visible rectangle for this pipeline. If the constellation
|
||||
// hasn't received a rectangle for this pipeline yet, then assume
|
||||
// that the output image isn't stable yet.
|
||||
match pipeline.rect {
|
||||
Some(rect) => {
|
||||
// Check the visible rectangle for this pipeline. If the constellation has received a
|
||||
// size for the pipeline, then its painting should be up to date. If the constellation
|
||||
// *hasn't* received a size, it could be that the layer was hidden by script before the
|
||||
// compositor discovered it, so we just don't check the layer.
|
||||
if let Some(size) = pipeline.size {
|
||||
// If the rectangle for this pipeline is zero sized, it will
|
||||
// never be painted. In this case, don't query the layout
|
||||
// task as it won't contribute to the final output image.
|
||||
if rect.size == Size2D::zero() {
|
||||
if size == Size2D::zero() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1263,10 +1277,6 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All script tasks are idle and layout epochs match compositor, so output image!
|
||||
|
@ -1354,7 +1364,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
|
||||
let mut frame_tree = SendableFrameTree {
|
||||
pipeline: pipeline.to_sendable(),
|
||||
rect: pipeline.rect,
|
||||
size: pipeline.size,
|
||||
children: vec!(),
|
||||
};
|
||||
|
||||
|
@ -1409,7 +1419,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
// If this is an iframe, then send the event with new url
|
||||
if let Some((containing_pipeline_id, subpage_id, url)) = event_info {
|
||||
let parent_pipeline = self.pipeline(containing_pipeline_id);
|
||||
parent_pipeline.trigger_mozbrowser_event(subpage_id, MozBrowserEvent::LocationChange(url));
|
||||
parent_pipeline.trigger_mozbrowser_event(subpage_id,
|
||||
MozBrowserEvent::LocationChange(url));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1451,7 +1462,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
self.pipelines.get_mut(&pipeline_id).expect("unable to find pipeline - this is a bug")
|
||||
}
|
||||
|
||||
fn find_subpage(&mut self, containing_pipeline_id: PipelineId, subpage_id: SubpageId) -> &mut Pipeline {
|
||||
fn find_subpage(&mut self, containing_pipeline_id: PipelineId, subpage_id: SubpageId)
|
||||
-> &mut Pipeline {
|
||||
let pipeline_id = *self.subpage_map
|
||||
.get(&(containing_pipeline_id, subpage_id))
|
||||
.expect("no subpage pipeline_id");
|
||||
|
|
|
@ -100,7 +100,6 @@ impl CompositorEventListener for NullCompositor {
|
|||
// SetFrameTree.
|
||||
|
||||
Msg::InitializeLayersForPipeline(..) |
|
||||
Msg::SetLayerRect(..) |
|
||||
Msg::AssignPaintedBuffers(..) |
|
||||
Msg::ScrollFragmentPoint(..) |
|
||||
Msg::Status(..) |
|
||||
|
@ -122,6 +121,8 @@ impl CompositorEventListener for NullCompositor {
|
|||
Msg::HeadParsed => {}
|
||||
Msg::ReturnUnusedNativeSurfaces(..) => {}
|
||||
Msg::CollectMemoryReports(..) => {}
|
||||
Msg::PipelineExited(..) => {}
|
||||
Msg::CreateLayerForSubpage(..) => {}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
|
||||
use CompositorProxy;
|
||||
use compositor_task;
|
||||
use compositor_task::Msg as CompositorMsg;
|
||||
use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
|
||||
use euclid::rect::{TypedRect};
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::TypedSize2D;
|
||||
use gfx::font_cache_task::FontCacheTask;
|
||||
use gfx::paint_task::{ChromeToPaintMsg, LayoutToPaintMsg, PaintTask};
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||
|
@ -39,6 +40,8 @@ pub struct Pipeline {
|
|||
pub script_chan: Sender<ConstellationControlMsg>,
|
||||
/// A channel to layout, for performing reflows and shutdown.
|
||||
pub layout_chan: LayoutControlChan,
|
||||
/// A channel to the compositor.
|
||||
pub compositor_proxy: Box<CompositorProxy + 'static + Send>,
|
||||
pub chrome_to_paint_chan: Sender<ChromeToPaintMsg>,
|
||||
pub layout_shutdown_port: Receiver<()>,
|
||||
pub paint_shutdown_port: Receiver<()>,
|
||||
|
@ -46,7 +49,7 @@ pub struct Pipeline {
|
|||
pub url: Url,
|
||||
/// The title of the most recently-loaded page.
|
||||
pub title: Option<String>,
|
||||
pub rect: Option<TypedRect<PagePx, f32>>,
|
||||
pub size: Option<TypedSize2D<PagePx, f32>>,
|
||||
/// Whether this pipeline is currently running animations. Pipelines that are running
|
||||
/// animations cause composites to be continually scheduled.
|
||||
pub running_animations: bool,
|
||||
|
@ -88,7 +91,7 @@ pub struct InitialPipelineState {
|
|||
/// A channel to the memory profiler thread.
|
||||
pub mem_profiler_chan: profile_mem::ProfilerChan,
|
||||
/// Information about the initial window size.
|
||||
pub window_rect: Option<TypedRect<PagePx, f32>>,
|
||||
pub window_size: Option<TypedSize2D<PagePx, f32>>,
|
||||
/// Information about the device pixel ratio.
|
||||
pub device_pixel_ratio: ScaleFactor<ViewportPx, DevicePixel, f32>,
|
||||
/// A channel to the script thread, if applicable. If this is `Some`,
|
||||
|
@ -116,10 +119,10 @@ impl Pipeline {
|
|||
parent_info: state.parent_info,
|
||||
};
|
||||
|
||||
let window_size = state.window_rect.map(|rect| {
|
||||
let window_size = state.window_size.map(|size| {
|
||||
WindowSizeData {
|
||||
visible_viewport: rect.size,
|
||||
initial_viewport: rect.size * ScaleFactor::new(1.0),
|
||||
visible_viewport: size,
|
||||
initial_viewport: size * ScaleFactor::new(1.0),
|
||||
device_pixel_ratio: state.device_pixel_ratio,
|
||||
}
|
||||
});
|
||||
|
@ -164,11 +167,12 @@ impl Pipeline {
|
|||
state.parent_info,
|
||||
script_chan.clone(),
|
||||
LayoutControlChan(pipeline_chan),
|
||||
state.compositor_proxy.clone_compositor_proxy(),
|
||||
chrome_to_paint_chan.clone(),
|
||||
layout_shutdown_port,
|
||||
paint_shutdown_port,
|
||||
state.load_data.url.clone(),
|
||||
state.window_rect);
|
||||
state.window_size);
|
||||
|
||||
let pipeline_content = PipelineContent {
|
||||
id: state.id,
|
||||
|
@ -203,24 +207,26 @@ impl Pipeline {
|
|||
parent_info: Option<(PipelineId, SubpageId)>,
|
||||
script_chan: Sender<ConstellationControlMsg>,
|
||||
layout_chan: LayoutControlChan,
|
||||
compositor_proxy: Box<CompositorProxy + 'static + Send>,
|
||||
chrome_to_paint_chan: Sender<ChromeToPaintMsg>,
|
||||
layout_shutdown_port: Receiver<()>,
|
||||
paint_shutdown_port: Receiver<()>,
|
||||
url: Url,
|
||||
rect: Option<TypedRect<PagePx, f32>>)
|
||||
size: Option<TypedSize2D<PagePx, f32>>)
|
||||
-> Pipeline {
|
||||
Pipeline {
|
||||
id: id,
|
||||
parent_info: parent_info,
|
||||
script_chan: script_chan,
|
||||
layout_chan: layout_chan,
|
||||
compositor_proxy: compositor_proxy,
|
||||
chrome_to_paint_chan: chrome_to_paint_chan,
|
||||
layout_shutdown_port: layout_shutdown_port,
|
||||
paint_shutdown_port: paint_shutdown_port,
|
||||
url: url,
|
||||
title: None,
|
||||
children: vec!(),
|
||||
rect: rect,
|
||||
size: size,
|
||||
running_animations: false,
|
||||
}
|
||||
}
|
||||
|
@ -239,13 +245,17 @@ impl Pipeline {
|
|||
|
||||
// Script task handles shutting down layout, and layout handles shutting down the painter.
|
||||
// For now, if the script task has failed, we give up on clean shutdown.
|
||||
if self.script_chan.send(ConstellationControlMsg::ExitPipeline(self.id, exit_type)).is_ok() {
|
||||
if self.script_chan
|
||||
.send(ConstellationControlMsg::ExitPipeline(self.id, exit_type))
|
||||
.is_ok() {
|
||||
// Wait until all slave tasks have terminated and run destructors
|
||||
// NOTE: We don't wait for script task as we don't always own it
|
||||
let _ = self.paint_shutdown_port.recv();
|
||||
let _ = self.layout_shutdown_port.recv();
|
||||
}
|
||||
|
||||
// The compositor wants to know when pipelines shut down too.
|
||||
self.compositor_proxy.send(CompositorMsg::PipelineExited(self.id))
|
||||
}
|
||||
|
||||
pub fn freeze(&self) {
|
||||
|
|
|
@ -22,7 +22,7 @@ use euclid::num::Zero;
|
|||
use euclid::{Matrix2D, Matrix4, Point2D, Rect, SideOffsets2D, Size2D};
|
||||
use gfx_traits::color;
|
||||
use libc::uintptr_t;
|
||||
use msg::compositor_msg::{LayerId, LayerKind, ScrollPolicy};
|
||||
use msg::compositor_msg::{LayerId, LayerKind, ScrollPolicy, SubpageLayerInfo};
|
||||
use net_traits::image::base::Image;
|
||||
use paint_context::PaintContext;
|
||||
use paint_task::PaintLayer;
|
||||
|
@ -364,6 +364,9 @@ pub struct StackingContext {
|
|||
|
||||
/// The layer id for this stacking context, if there is one.
|
||||
pub layer_id: Option<LayerId>,
|
||||
|
||||
/// The subpage that this stacking context represents, if there is one.
|
||||
pub subpage_layer_info: Option<SubpageLayerInfo>,
|
||||
}
|
||||
|
||||
impl StackingContext {
|
||||
|
@ -380,7 +383,8 @@ impl StackingContext {
|
|||
establishes_3d_context: bool,
|
||||
scrolls_overflow_area: bool,
|
||||
scroll_policy: ScrollPolicy,
|
||||
layer_id: Option<LayerId>)
|
||||
layer_id: Option<LayerId>,
|
||||
subpage_layer_info: Option<SubpageLayerInfo>)
|
||||
-> StackingContext {
|
||||
let mut stacking_context = StackingContext {
|
||||
display_list: display_list,
|
||||
|
@ -395,6 +399,7 @@ impl StackingContext {
|
|||
scrolls_overflow_area: scrolls_overflow_area,
|
||||
scroll_policy: scroll_policy,
|
||||
layer_id: layer_id,
|
||||
subpage_layer_info: subpage_layer_info,
|
||||
};
|
||||
StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context);
|
||||
stacking_context
|
||||
|
@ -416,6 +421,7 @@ impl StackingContext {
|
|||
scrolls_overflow_area: self.scrolls_overflow_area,
|
||||
scroll_policy: self.scroll_policy,
|
||||
layer_id: Some(layer_id),
|
||||
subpage_layer_info: self.subpage_layer_info,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -679,11 +685,19 @@ impl StackingContextLayerCreator {
|
|||
fn finish_building_current_layer(&mut self, stacking_context: &mut StackingContext) {
|
||||
if let Some(display_list) = self.display_list_for_next_layer.take() {
|
||||
let next_layer_id =
|
||||
stacking_context.display_list.layered_children.back().unwrap().id.companion_layer_id();
|
||||
stacking_context.display_list
|
||||
.layered_children
|
||||
.back()
|
||||
.unwrap()
|
||||
.id
|
||||
.companion_layer_id();
|
||||
let child_stacking_context =
|
||||
Arc::new(stacking_context.create_layered_child(next_layer_id, display_list));
|
||||
stacking_context.display_list.layered_children.push_back(Arc::new(
|
||||
PaintLayer::new(next_layer_id, color::transparent(), child_stacking_context)));
|
||||
stacking_context.display_list.layered_children.push_back(
|
||||
Arc::new(PaintLayer::new(next_layer_id,
|
||||
color::transparent(),
|
||||
child_stacking_context,
|
||||
ScrollPolicy::Scrollable)));
|
||||
self.all_following_children_need_layers = true;
|
||||
}
|
||||
}
|
||||
|
@ -694,7 +708,10 @@ impl StackingContextLayerCreator {
|
|||
if let Some(layer_id) = stacking_context.layer_id {
|
||||
self.finish_building_current_layer(parent_stacking_context);
|
||||
parent_stacking_context.display_list.layered_children.push_back(
|
||||
Arc::new(PaintLayer::new(layer_id, color::transparent(), stacking_context)));
|
||||
Arc::new(PaintLayer::new(layer_id,
|
||||
color::transparent(),
|
||||
stacking_context,
|
||||
ScrollPolicy::Scrollable)));
|
||||
|
||||
// We have started processing layered stacking contexts, so any stacking context that
|
||||
// we process from now on needs its own layer to ensure proper rendering order.
|
||||
|
|
|
@ -17,8 +17,8 @@ use font_context::FontContext;
|
|||
use ipc_channel::ipc::IpcSender;
|
||||
use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
|
||||
use layers::platform::surface::{NativeDisplay, NativeSurface};
|
||||
use msg::compositor_msg::{Epoch, FrameTreeId, LayerId, LayerKind};
|
||||
use msg::compositor_msg::{LayerProperties, PaintListener};
|
||||
use msg::compositor_msg::{Epoch, FrameTreeId, LayerId, LayerKind, LayerProperties, PaintListener};
|
||||
use msg::compositor_msg::{ScrollPolicy};
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::PipelineExitType;
|
||||
use msg::constellation_msg::{ConstellationChan, Failure, PipelineId};
|
||||
|
@ -48,15 +48,22 @@ pub struct PaintLayer {
|
|||
pub background_color: Color,
|
||||
/// The stacking context that represents the content of this layer.
|
||||
pub stacking_context: Arc<StackingContext>,
|
||||
/// The scrolling policy of this layer.
|
||||
pub scroll_policy: ScrollPolicy,
|
||||
}
|
||||
|
||||
impl PaintLayer {
|
||||
/// Creates a new `PaintLayer`.
|
||||
pub fn new(id: LayerId, background_color: Color, stacking_context: Arc<StackingContext>) -> PaintLayer {
|
||||
pub fn new(id: LayerId,
|
||||
background_color: Color,
|
||||
stacking_context: Arc<StackingContext>,
|
||||
scroll_policy: ScrollPolicy)
|
||||
-> PaintLayer {
|
||||
PaintLayer {
|
||||
id: id,
|
||||
background_color: background_color,
|
||||
stacking_context: stacking_context,
|
||||
scroll_policy: scroll_policy,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,8 +362,8 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
|
|||
let transform = transform.mul(&paint_layer.stacking_context.transform);
|
||||
let perspective = perspective.mul(&paint_layer.stacking_context.perspective);
|
||||
|
||||
let overflow_size =
|
||||
Size2D::new(paint_layer.stacking_context.overflow.size.width.to_nearest_px() as f32,
|
||||
let overflow_size = Size2D::new(
|
||||
paint_layer.stacking_context.overflow.size.width.to_nearest_px() as f32,
|
||||
paint_layer.stacking_context.overflow.size.height.to_nearest_px() as f32);
|
||||
|
||||
// Layers start at the top left of their overflow rect, as far as the info
|
||||
|
@ -379,6 +386,7 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
|
|||
perspective: perspective,
|
||||
establishes_3d_context: paint_layer.stacking_context.establishes_3d_context,
|
||||
scrolls_overflow_area: paint_layer.stacking_context.scrolls_overflow_area,
|
||||
subpage_layer_info: paint_layer.stacking_context.subpage_layer_info,
|
||||
});
|
||||
|
||||
// When there is a new layer, the transforms and origin are handled by the compositor,
|
||||
|
|
|
@ -2126,10 +2126,11 @@ impl Flow for BlockFlow {
|
|||
}
|
||||
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
self.fragment.compute_overflow(&self.base.early_absolute_position_info
|
||||
.relative_containing_block_size,
|
||||
self.base.early_absolute_position_info
|
||||
.relative_containing_block_mode)
|
||||
let flow_size = self.base.position.size.to_physical(self.base.writing_mode);
|
||||
self.fragment.compute_overflow(&flow_size,
|
||||
&self.base
|
||||
.early_absolute_position_info
|
||||
.relative_containing_block_size)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
|
|
|
@ -285,15 +285,6 @@ impl<'a> FlowConstructor<'a> {
|
|||
fn set_flow_construction_result(&self,
|
||||
node: &ThreadSafeLayoutNode,
|
||||
result: ConstructionResult) {
|
||||
if let ConstructionResult::None = result {
|
||||
let mut layout_data_ref = node.mutate_layout_data();
|
||||
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||
layout_data.remove_compositor_layers(self.layout_context
|
||||
.shared
|
||||
.constellation_chan
|
||||
.clone());
|
||||
}
|
||||
|
||||
node.set_flow_construction_result(result);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use construct::{ConstructionItem, ConstructionResult};
|
||||
use construct::ConstructionResult;
|
||||
use incremental::RestyleDamage;
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
use parallel::DomParallelInfo;
|
||||
use script::dom::node::SharedLayoutData;
|
||||
use std::sync::Arc;
|
||||
|
@ -64,30 +63,6 @@ pub struct LayoutDataWrapper {
|
|||
pub data: Box<PrivateLayoutData>,
|
||||
}
|
||||
|
||||
impl LayoutDataWrapper {
|
||||
pub fn remove_compositor_layers(&self, constellation_chan: ConstellationChan) {
|
||||
match self.data.flow_construction_result {
|
||||
ConstructionResult::None => {}
|
||||
ConstructionResult::Flow(ref flow_ref, _) => {
|
||||
flow_ref.remove_compositor_layers(constellation_chan);
|
||||
}
|
||||
ConstructionResult::ConstructionItem(ref construction_item) => {
|
||||
match *construction_item {
|
||||
ConstructionItem::InlineFragments(ref inline_fragments) => {
|
||||
for fragment in &inline_fragments.fragments.fragments {
|
||||
fragment.remove_compositor_layers(constellation_chan.clone());
|
||||
}
|
||||
}
|
||||
ConstructionItem::Whitespace(..) => {}
|
||||
ConstructionItem::TableColumnFragment(ref fragment) => {
|
||||
fragment.remove_compositor_layers(constellation_chan.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code, unsafe_code)]
|
||||
fn static_assertion(x: Option<LayoutDataWrapper>) {
|
||||
unsafe {
|
||||
|
|
|
@ -14,13 +14,12 @@ use azure::azure_hl::Color;
|
|||
use block::BlockFlow;
|
||||
use canvas_traits::{CanvasMsg, FromLayoutMsg};
|
||||
use context::LayoutContext;
|
||||
use euclid::Matrix4;
|
||||
use euclid::{Point2D, Point3D, Rect, SideOffsets2D, Size2D};
|
||||
use euclid::{Matrix4, Point2D, Point3D, Rect, SideOffsets2D, Size2D};
|
||||
use flex::FlexFlow;
|
||||
use flow::{self, BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
|
||||
use flow_ref;
|
||||
use fragment::{CoordinateSystem, Fragment, HAS_LAYER, IframeFragmentInfo, ImageFragmentInfo};
|
||||
use fragment::{ScannedTextFragmentInfo, SpecificFragmentInfo};
|
||||
use fragment::{CoordinateSystem, Fragment, HAS_LAYER, ImageFragmentInfo, ScannedTextFragmentInfo};
|
||||
use fragment::{SpecificFragmentInfo};
|
||||
use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem};
|
||||
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
|
||||
use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList};
|
||||
|
@ -35,9 +34,7 @@ use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
|
|||
use ipc_channel::ipc::{self, IpcSharedMemory};
|
||||
use list_item::ListItemFlow;
|
||||
use model::{self, MaybeAuto, ToGfxMatrix};
|
||||
use msg::compositor_msg::{LayerId, ScrollPolicy};
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::compositor_msg::{LayerId, ScrollPolicy, SubpageLayerInfo};
|
||||
use net_traits::image::base::{Image, PixelFormat};
|
||||
use net_traits::image_cache_task::UsePlaceholder;
|
||||
use std::default::Default;
|
||||
|
@ -70,7 +67,7 @@ const INSERTION_POINT_LOGICAL_WIDTH: Au = Au(1 * AU_PER_PX);
|
|||
/// Whether a stacking context needs a layer or not.
|
||||
pub enum StackingContextLayerNecessity {
|
||||
Always(LayerId, ScrollPolicy),
|
||||
IfCanvas(LayerId),
|
||||
IfCanvasOrIframe(LayerId),
|
||||
}
|
||||
|
||||
/// The results of display list building for a single flow.
|
||||
|
@ -206,13 +203,6 @@ pub trait FragmentDisplayListBuilding {
|
|||
clip: &ClippingRegion,
|
||||
stacking_relative_display_port: &Rect<Au>);
|
||||
|
||||
/// Sends the size and position of this iframe fragment to the constellation. This is out of
|
||||
/// line to guide inlining.
|
||||
fn finalize_position_and_size_of_iframe(&self,
|
||||
iframe_fragment: &IframeFragmentInfo,
|
||||
offset: Point2D<Au>,
|
||||
layout_context: &LayoutContext);
|
||||
|
||||
/// Returns the appropriate clipping region for descendants of this fragment.
|
||||
fn clipping_region_for_children(&self,
|
||||
current_clip: &ClippingRegion,
|
||||
|
@ -270,7 +260,6 @@ pub trait FragmentDisplayListBuilding {
|
|||
needs_layer: StackingContextLayerNecessity,
|
||||
mode: StackingContextCreationMode)
|
||||
-> Arc<StackingContext>;
|
||||
|
||||
}
|
||||
|
||||
fn handle_overlapping_radii(size: &Size2D<Au>, radii: &BorderRadii<Au>) -> BorderRadii<Au> {
|
||||
|
@ -1060,28 +1049,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
&stacking_relative_border_box,
|
||||
&clip)
|
||||
}
|
||||
|
||||
// If this is an iframe, then send its position and size up to the constellation.
|
||||
//
|
||||
// FIXME(pcwalton): Doing this during display list construction seems potentially
|
||||
// problematic if iframes are outside the area we're computing the display list for, since
|
||||
// they won't be able to reflow at all until the user scrolls to them. Perhaps we should
|
||||
// separate this into two parts: first we should send the size only to the constellation
|
||||
// once that's computed during assign-block-sizes, and second we should should send the
|
||||
// origin to the constellation here during display list construction. This should work
|
||||
// because layout for the iframe only needs to know size, and origin is only relevant if
|
||||
// the iframe is actually going to be displayed.
|
||||
if let SpecificFragmentInfo::Iframe(ref iframe_fragment) = self.specific {
|
||||
let stacking_relative_border_box_in_parent_coordinate_system =
|
||||
self.stacking_relative_border_box(stacking_relative_flow_origin,
|
||||
relative_containing_block_size,
|
||||
relative_containing_block_mode,
|
||||
CoordinateSystem::Parent);
|
||||
self.finalize_position_and_size_of_iframe(
|
||||
&**iframe_fragment,
|
||||
stacking_relative_border_box_in_parent_coordinate_system.origin,
|
||||
layout_context)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_fragment_type_specific_display_items(&mut self,
|
||||
|
@ -1317,15 +1284,18 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
filters.push(Filter::Opacity(effects.opacity))
|
||||
}
|
||||
|
||||
// Ensure every canvas has a layer
|
||||
// Ensure every canvas or iframe has a layer.
|
||||
let (scroll_policy, layer_id) = match needs_layer {
|
||||
StackingContextLayerNecessity::Always(layer_id, scroll_policy) =>
|
||||
(scroll_policy, Some(layer_id)),
|
||||
StackingContextLayerNecessity::IfCanvas(layer_id) => {
|
||||
if let SpecificFragmentInfo::Canvas(_) = self.specific {
|
||||
StackingContextLayerNecessity::Always(layer_id, scroll_policy) => {
|
||||
(scroll_policy, Some(layer_id))
|
||||
}
|
||||
StackingContextLayerNecessity::IfCanvasOrIframe(layer_id) => {
|
||||
// FIXME(pcwalton): So so bogus :(
|
||||
match self.specific {
|
||||
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => {
|
||||
(ScrollPolicy::Scrollable, Some(layer_id))
|
||||
} else {
|
||||
(ScrollPolicy::Scrollable, None)
|
||||
}
|
||||
_ => (ScrollPolicy::Scrollable, None),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1341,6 +1311,18 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
let subpage_layer_info = match self.specific {
|
||||
SpecificFragmentInfo::Iframe(ref iframe_fragment_info) => {
|
||||
let border_padding = self.border_padding.to_physical(self.style().writing_mode);
|
||||
Some(SubpageLayerInfo {
|
||||
pipeline_id: iframe_fragment_info.pipeline_id,
|
||||
subpage_id: iframe_fragment_info.subpage_id,
|
||||
origin: Point2D::new(border_padding.left, border_padding.top),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let scrolls_overflow_area = mode == StackingContextCreationMode::OuterScrollWrapper;
|
||||
let transform_style = self.style().get_used_transform_style();
|
||||
let establishes_3d_context = scrolls_overflow_area ||
|
||||
|
@ -1357,28 +1339,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
establishes_3d_context,
|
||||
scrolls_overflow_area,
|
||||
scroll_policy,
|
||||
layer_id))
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn finalize_position_and_size_of_iframe(&self,
|
||||
iframe_fragment: &IframeFragmentInfo,
|
||||
offset: Point2D<Au>,
|
||||
layout_context: &LayoutContext) {
|
||||
let border_padding = (self.border_padding).to_physical(self.style.writing_mode);
|
||||
let content_size = self.content_box().size.to_physical(self.style.writing_mode);
|
||||
let iframe_rect = Rect::new(Point2D::new((offset.x + border_padding.left).to_f32_px(),
|
||||
(offset.y + border_padding.top).to_f32_px()),
|
||||
Size2D::new(content_size.width.to_f32_px(),
|
||||
content_size.height.to_f32_px()));
|
||||
|
||||
debug!("finalizing position and size of iframe for {:?},{:?}",
|
||||
iframe_fragment.pipeline_id,
|
||||
iframe_fragment.subpage_id);
|
||||
let ConstellationChan(ref chan) = layout_context.shared.constellation_chan;
|
||||
chan.send(ConstellationMsg::FrameRect(iframe_fragment.pipeline_id,
|
||||
iframe_fragment.subpage_id,
|
||||
iframe_rect)).unwrap();
|
||||
layer_id,
|
||||
subpage_layer_info))
|
||||
}
|
||||
|
||||
fn clipping_region_for_children(&self,
|
||||
|
@ -1643,7 +1605,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
&self.base,
|
||||
display_list,
|
||||
layout_context,
|
||||
StackingContextLayerNecessity::IfCanvas(self.layer_id()),
|
||||
StackingContextLayerNecessity::IfCanvasOrIframe(self.layer_id()),
|
||||
StackingContextCreationMode::Normal))
|
||||
} else {
|
||||
match self.fragment.style.get_box().position {
|
||||
|
@ -1720,7 +1682,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
&self.base,
|
||||
display_list,
|
||||
layout_context,
|
||||
StackingContextLayerNecessity::IfCanvas(self.layer_id()),
|
||||
StackingContextLayerNecessity::IfCanvasOrIframe(self.layer_id()),
|
||||
StackingContextCreationMode::Normal));
|
||||
}
|
||||
return
|
||||
|
@ -1785,7 +1747,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
&self.base,
|
||||
display_list,
|
||||
layout_context,
|
||||
StackingContextLayerNecessity::IfCanvas(self.layer_id()),
|
||||
StackingContextLayerNecessity::IfCanvasOrIframe(self.layer_id()),
|
||||
StackingContextCreationMode::Normal))
|
||||
} else {
|
||||
DisplayListBuildingResult::Normal(display_list)
|
||||
|
@ -1871,13 +1833,17 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
|||
|
||||
// FIXME(Savago): fix Fragment::establishes_stacking_context() for absolute positioned item
|
||||
// and remove the check for filter presence. Further details on #5812.
|
||||
has_stacking_context = has_stacking_context && {
|
||||
if let SpecificFragmentInfo::Canvas(_) = self.fragments.fragments[0].specific {
|
||||
true
|
||||
} else {
|
||||
//
|
||||
// FIXME(#7424, pcwalton): This is terribly bogus! What is even going on here?
|
||||
if has_stacking_context {
|
||||
match self.fragments.fragments[0].specific {
|
||||
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => {}
|
||||
_ => {
|
||||
has_stacking_context =
|
||||
!self.fragments.fragments[0].style().get_effects().filter.is_empty()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
self.base.display_list_building_result = if has_stacking_context {
|
||||
DisplayListBuildingResult::StackingContext(
|
||||
|
@ -1885,7 +1851,8 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
|||
&self.base,
|
||||
display_list,
|
||||
layout_context,
|
||||
StackingContextLayerNecessity::IfCanvas(self.layer_id()),
|
||||
StackingContextLayerNecessity::Always(self.layer_id(),
|
||||
ScrollPolicy::Scrollable),
|
||||
StackingContextCreationMode::Normal))
|
||||
} else {
|
||||
DisplayListBuildingResult::Normal(display_list)
|
||||
|
|
|
@ -22,7 +22,7 @@ use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT};
|
|||
use ipc_channel::ipc::IpcSender;
|
||||
use layout_debug;
|
||||
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
|
||||
use msg::constellation_msg::{ConstellationChan, Msg, PipelineId, SubpageId};
|
||||
use msg::constellation_msg::{PipelineId, SubpageId};
|
||||
use net_traits::image::base::Image;
|
||||
use net_traits::image_cache_task::UsePlaceholder;
|
||||
use rustc_serialize::{Encodable, Encoder};
|
||||
|
@ -2102,6 +2102,16 @@ impl Fragment {
|
|||
stacking_relative_border_box.size.height - border_padding.vertical()))
|
||||
}
|
||||
|
||||
/// Returns true if this fragment unconditionally layerizes.
|
||||
pub fn needs_layer(&self) -> bool {
|
||||
// Canvas and iframes always layerize, as an special case
|
||||
// FIXME(pcwalton): Don't unconditionally form stacking contexts for each canvas.
|
||||
match self.specific {
|
||||
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this fragment establishes a new stacking context and false otherwise.
|
||||
pub fn establishes_stacking_context(&self) -> bool {
|
||||
if self.flags.contains(HAS_LAYER) {
|
||||
|
@ -2126,9 +2136,7 @@ impl Fragment {
|
|||
transform_style::T::auto => {}
|
||||
}
|
||||
|
||||
// Canvas always layerizes, as an special case
|
||||
// FIXME(pcwalton): Don't unconditionally form stacking contexts for each canvas.
|
||||
if let SpecificFragmentInfo::Canvas(_) = self.specific {
|
||||
if self.needs_layer() {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -2161,12 +2169,10 @@ impl Fragment {
|
|||
|
||||
/// Computes the overflow rect of this fragment relative to the start of the flow.
|
||||
pub fn compute_overflow(&self,
|
||||
relative_containing_block_size: &LogicalSize<Au>,
|
||||
relative_containing_block_mode: WritingMode)
|
||||
flow_size: &Size2D<Au>,
|
||||
relative_containing_block_size: &LogicalSize<Au>)
|
||||
-> Rect<Au> {
|
||||
let container_size =
|
||||
relative_containing_block_size.to_physical(relative_containing_block_mode);
|
||||
let mut border_box = self.border_box.to_physical(self.style.writing_mode, container_size);
|
||||
let mut border_box = self.border_box.to_physical(self.style.writing_mode, *flow_size);
|
||||
|
||||
// Relative position can cause us to draw outside our border box.
|
||||
//
|
||||
|
@ -2209,23 +2215,6 @@ impl Fragment {
|
|||
overflow
|
||||
}
|
||||
|
||||
/// Remove any compositor layers associated with this fragment - it is being
|
||||
/// removed from the tree or had its display property set to none.
|
||||
/// TODO(gw): This just hides the compositor layer for now. In the future
|
||||
/// it probably makes sense to provide a hint to the compositor whether
|
||||
/// the layers should be destroyed to free memory.
|
||||
pub fn remove_compositor_layers(&self, constellation_chan: ConstellationChan) {
|
||||
match self.specific {
|
||||
SpecificFragmentInfo::Iframe(ref iframe_info) => {
|
||||
let ConstellationChan(ref chan) = constellation_chan;
|
||||
chan.send(Msg::FrameRect(iframe_info.pipeline_id,
|
||||
iframe_info.subpage_id,
|
||||
Rect::zero())).unwrap();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn requires_line_break_afterward_if_wrapping_on_newlines(&self) -> bool {
|
||||
match self.specific {
|
||||
SpecificFragmentInfo::ScannedText(ref scanned_text) => {
|
||||
|
|
|
@ -9,7 +9,7 @@ use context::LayoutContext;
|
|||
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
use floats::{FloatKind, Floats, PlacementInfo};
|
||||
use flow::{EarlyAbsolutePositionInfo, MutableFlowUtils, OpaqueFlow};
|
||||
use flow::{EarlyAbsolutePositionInfo, LAYERS_NEEDED_FOR_DESCENDANTS, MutableFlowUtils, OpaqueFlow};
|
||||
use flow::{self, BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, IS_ABSOLUTELY_POSITIONED};
|
||||
use flow_ref;
|
||||
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||
|
@ -1465,6 +1465,7 @@ impl Flow for InlineFlow {
|
|||
|
||||
// Now, go through each line and lay out the fragments inside.
|
||||
let mut line_distance_from_flow_block_start = Au(0);
|
||||
let mut layers_needed_for_descendants = false;
|
||||
let line_count = self.lines.len();
|
||||
for line_index in 0..line_count {
|
||||
let line = &mut self.lines[line_index];
|
||||
|
@ -1493,6 +1494,10 @@ impl Flow for InlineFlow {
|
|||
for fragment_index in line.range.each_index() {
|
||||
let fragment = &mut self.fragments.fragments[fragment_index.to_usize()];
|
||||
|
||||
if fragment.needs_layer() && !fragment.is_positioned() {
|
||||
layers_needed_for_descendants = true
|
||||
}
|
||||
|
||||
let InlineMetrics {
|
||||
mut block_size_above_baseline,
|
||||
mut depth_below_baseline,
|
||||
|
@ -1589,6 +1594,10 @@ impl Flow for InlineFlow {
|
|||
kid.assign_block_size_for_inorder_child_if_necessary(layout_context, thread_id);
|
||||
}
|
||||
|
||||
// Mark ourselves for layerization if that will be necessary to paint in the proper
|
||||
// order (CSS 2.1, Appendix E).
|
||||
self.base.flags.set(LAYERS_NEEDED_FOR_DESCENDANTS, layers_needed_for_descendants);
|
||||
|
||||
if self.contains_positioned_fragments() {
|
||||
// Assign block-sizes for all flows in this absolute flow tree.
|
||||
// This is preorder because the block-size of an absolute flow may depend on
|
||||
|
@ -1773,10 +1782,12 @@ impl Flow for InlineFlow {
|
|||
|
||||
fn compute_overflow(&self) -> Rect<Au> {
|
||||
let mut overflow = ZERO_RECT;
|
||||
let flow_size = self.base.position.size.to_physical(self.base.writing_mode);
|
||||
let relative_containing_block_size =
|
||||
&self.base.early_absolute_position_info.relative_containing_block_size;
|
||||
for fragment in &self.fragments.fragments {
|
||||
overflow = overflow.union(&fragment.compute_overflow(
|
||||
&self.base.early_absolute_position_info.relative_containing_block_size,
|
||||
self.base.early_absolute_position_info.relative_containing_block_mode));
|
||||
overflow = overflow.union(&fragment.compute_overflow(&flow_size,
|
||||
&relative_containing_block_size))
|
||||
}
|
||||
overflow
|
||||
}
|
||||
|
|
|
@ -637,7 +637,7 @@ impl LayoutTask {
|
|||
unsafe {
|
||||
self.handle_reap_layout_data(dead_layout_data)
|
||||
}
|
||||
},
|
||||
}
|
||||
Msg::CollectReports(reports_chan) => {
|
||||
self.collect_reports(reports_chan, possibly_locked_rw_data);
|
||||
},
|
||||
|
@ -724,8 +724,7 @@ impl LayoutTask {
|
|||
info.layout_shutdown_chan);
|
||||
}
|
||||
|
||||
/// Enters a quiescent state in which no new messages except for
|
||||
/// `layout_interface::Msg::ReapLayoutData` will be processed until an `ExitNow` is
|
||||
/// Enters a quiescent state in which no new messages will be processed until an `ExitNow` is
|
||||
/// received. A pong is immediately sent on the given response channel.
|
||||
fn prepare_to_exit<'a>(&'a self,
|
||||
response_chan: Sender<()>,
|
||||
|
@ -1099,6 +1098,7 @@ impl LayoutTask {
|
|||
flow::mut_base(flow_ref::deref_mut(layout_root))
|
||||
.display_list_building_result
|
||||
.add_to(&mut *display_list);
|
||||
|
||||
let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size);
|
||||
let layer_id = layout_root.layer_id();
|
||||
let stacking_context = Arc::new(StackingContext::new(display_list,
|
||||
|
@ -1112,11 +1112,8 @@ impl LayoutTask {
|
|||
true,
|
||||
false,
|
||||
ScrollPolicy::Scrollable,
|
||||
Some(layer_id)));
|
||||
let paint_layer = PaintLayer::new(layer_id,
|
||||
root_background_color,
|
||||
stacking_context.clone());
|
||||
|
||||
Some(layer_id),
|
||||
None));
|
||||
if opts::get().dump_display_list {
|
||||
stacking_context.print("DisplayList".to_owned());
|
||||
}
|
||||
|
@ -1124,7 +1121,12 @@ impl LayoutTask {
|
|||
println!("{}", serde_json::to_string_pretty(&stacking_context).unwrap());
|
||||
}
|
||||
|
||||
rw_data.stacking_context = Some(stacking_context);
|
||||
rw_data.stacking_context = Some(stacking_context.clone());
|
||||
|
||||
let paint_layer = PaintLayer::new(layout_root.layer_id(),
|
||||
root_background_color,
|
||||
stacking_context,
|
||||
ScrollPolicy::Scrollable);
|
||||
|
||||
debug!("Layout done!");
|
||||
|
||||
|
@ -1489,8 +1491,7 @@ impl LayoutTask {
|
|||
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* task
|
||||
/// because the struct type is transmuted to a different type on the script side.
|
||||
unsafe fn handle_reap_layout_data(&self, layout_data: LayoutData) {
|
||||
let layout_data_wrapper: LayoutDataWrapper = transmute(layout_data);
|
||||
layout_data_wrapper.remove_compositor_layers(self.constellation_chan.clone());
|
||||
let _: LayoutDataWrapper = transmute(layout_data);
|
||||
}
|
||||
|
||||
/// Returns profiling information which is passed to the time profiler.
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use azure::azure_hl::Color;
|
||||
use constellation_msg::{Key, KeyModifiers, KeyState, PipelineId};
|
||||
use constellation_msg::{Key, KeyModifiers, KeyState, PipelineId, SubpageId};
|
||||
use euclid::{Matrix4, Point2D, Rect, Size2D};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use layers::layers::{BufferRequest, LayerBufferSet};
|
||||
use layers::platform::surface::NativeDisplay;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use util::geometry::Au;
|
||||
|
||||
/// A newtype struct for denoting the age of messages; prevents race conditions.
|
||||
#[derive(PartialEq, Eq, Debug, Copy, Clone, PartialOrd, Ord, Deserialize, Serialize)]
|
||||
|
@ -124,6 +125,9 @@ pub struct LayerProperties {
|
|||
pub transform: Matrix4,
|
||||
/// The perspective transform for this layer
|
||||
pub perspective: Matrix4,
|
||||
/// The subpage that this layer represents. If this is `Some`, this layer represents an
|
||||
/// iframe.
|
||||
pub subpage_layer_info: Option<SubpageLayerInfo>,
|
||||
/// Whether this layer establishes a new 3d rendering context.
|
||||
pub establishes_3d_context: bool,
|
||||
/// Whether this layer scrolls its overflow area.
|
||||
|
@ -166,3 +170,15 @@ pub enum ScriptToCompositorMsg {
|
|||
ResizeTo(Size2D<u32>),
|
||||
Exit,
|
||||
}
|
||||
|
||||
/// Subpage (i.e. iframe)-specific information about each layer.
|
||||
#[derive(Clone, Copy, Deserialize, Serialize, HeapSizeOf)]
|
||||
pub struct SubpageLayerInfo {
|
||||
/// The ID of the pipeline.
|
||||
pub pipeline_id: PipelineId,
|
||||
/// The ID of the subpage.
|
||||
pub subpage_id: SubpageId,
|
||||
/// The offset of the subpage within this layer (to account for borders).
|
||||
pub origin: Point2D<Au>,
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
use canvas_traits::CanvasMsg;
|
||||
use compositor_msg::Epoch;
|
||||
use euclid::rect::Rect;
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
use hyper::header::Headers;
|
||||
|
@ -221,7 +220,7 @@ pub enum Msg {
|
|||
LoadComplete(PipelineId),
|
||||
/// Dispatched after the DOM load event has fired on a document
|
||||
DOMLoad(PipelineId),
|
||||
FrameRect(PipelineId, SubpageId, Rect<f32>),
|
||||
FrameSize(PipelineId, SubpageId, Size2D<f32>),
|
||||
LoadUrl(PipelineId, LoadData),
|
||||
ScriptLoadedURLInIFrame(Url, PipelineId, SubpageId, Option<SubpageId>, IFrameSandboxState),
|
||||
Navigate(Option<(PipelineId, SubpageId)>, NavigationDirection),
|
||||
|
@ -273,6 +272,9 @@ pub enum Msg {
|
|||
IpcSender<Result<(IpcSender<CanvasMsg>, usize), String>>),
|
||||
/// Status message to be displayed in the chrome, eg. a link URL on mouseover.
|
||||
NodeStatus(Option<String>),
|
||||
/// Requests that the pipeline ID of the subpage identified by a (pipeline ID, subpage ID)
|
||||
/// pair be sent to the compositor via a `CreateLayerForSubpage` message.
|
||||
PrepareForSubpageLayerCreation(PipelineId, SubpageId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
|
||||
|
|
|
@ -149,6 +149,7 @@ prefs:"layout.flex.enabled" == flex_row_direction.html flex_row_direction_ref.ht
|
|||
== iframe/size_attributes.html iframe/size_attributes_ref.html
|
||||
prefs:"layout.writing-mode.enabled" == iframe/size_attributes_vertical_writing_mode.html iframe/size_attributes_vertical_writing_mode_ref.html
|
||||
== iframe/stacking_context.html iframe/stacking_context_ref.html
|
||||
== iframe/stacking_context_position_a.html iframe/stacking_context_position_ref.html
|
||||
|
||||
!= image_rendering_auto_a.html image_rendering_pixelated_a.html
|
||||
== image_rendering_pixelated_a.html image_rendering_pixelated_ref.html
|
||||
|
|
5
tests/ref/iframe/stacking_context_position_a.html
Normal file
5
tests/ref/iframe/stacking_context_position_a.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
<body style="background:tan">
|
||||
<div style="transform: translateX(0px)">
|
||||
<iframe src="data:text/html,%3Cspan%3EJust%20a%20simple%20little%20iframe.%3C%2Fspan%3E"></iframe>
|
||||
</div>
|
||||
</body>
|
5
tests/ref/iframe/stacking_context_position_ref.html
Normal file
5
tests/ref/iframe/stacking_context_position_ref.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
<body style="background:tan">
|
||||
<div>
|
||||
<iframe style="transform: translateX(0px)" src="data:text/html,%3Cspan%3EJust%20a%20simple%20little%20iframe.%3C%2Fspan%3E"></iframe>
|
||||
</div>
|
||||
</body>
|
Loading…
Add table
Add a link
Reference in a new issue