mirror of
https://github.com/servo/servo.git
synced 2025-08-07 22:45:34 +01:00
compositor: Make PipelineDetails
and pending paint metrics per-WebView (#35701)
This is one of the first big steps toward making the compositor work per-WebView. It moves the collection of pipelines into the per-WebView data structure in the compositor as well as the pending paint metrics. This means that more messages need to carry information about the WebView they apply to. Note that there are still a few places that we need to map from `PipelineId` to `WebViewId`, so this also includes a shared mapping which tracks this. The mapping can be removed once event handling is fully per-WebView. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Delan Azabani <dazabani@igalia.com>
This commit is contained in:
parent
0d0bcdeb4d
commit
f3e6e4f04e
13 changed files with 537 additions and 373 deletions
|
@ -2,19 +2,190 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::hash_map::{Entry, Keys, Values, ValuesMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
use base::id::{PipelineId, WebViewId};
|
||||
use webrender_api::units::DeviceRect;
|
||||
use compositing_traits::SendableFrameTree;
|
||||
use fnv::FnvHashSet;
|
||||
use log::debug;
|
||||
use script_traits::AnimationState;
|
||||
use webrender_api::units::{DeviceRect, LayoutVector2D};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct WebView {
|
||||
pub pipeline_id: Option<PipelineId>,
|
||||
use crate::IOCompositor;
|
||||
use crate::compositor::PipelineDetails;
|
||||
|
||||
pub(crate) struct WebView {
|
||||
/// The [`WebViewId`] of the `WebView` associated with this [`WebViewDetails`].
|
||||
pub id: WebViewId,
|
||||
/// The root [`PipelineId`] of the currently displayed page in this WebView.
|
||||
pub root_pipeline_id: Option<PipelineId>,
|
||||
pub rect: DeviceRect,
|
||||
/// Tracks details about each active pipeline that the compositor knows about.
|
||||
pub pipelines: HashMap<PipelineId, PipelineDetails>,
|
||||
/// This is a temporary map between [`PipelineId`]s and their associated [`WebViewId`]. Once
|
||||
/// all renderer operations become per-`WebView` this map can be removed, but we still sometimes
|
||||
/// need to work backwards to figure out what `WebView` is associated with a `Pipeline`.
|
||||
pub pipeline_to_webview_map: Rc<RefCell<HashMap<PipelineId, WebViewId>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
impl Drop for WebView {
|
||||
fn drop(&mut self) {
|
||||
self.pipeline_to_webview_map
|
||||
.borrow_mut()
|
||||
.retain(|_, webview_id| self.id != *webview_id);
|
||||
}
|
||||
}
|
||||
|
||||
impl WebView {
|
||||
pub(crate) fn animations_or_animation_callbacks_running(&self) -> bool {
|
||||
self.pipelines
|
||||
.values()
|
||||
.any(PipelineDetails::animations_or_animation_callbacks_running)
|
||||
}
|
||||
|
||||
pub(crate) fn animation_callbacks_running(&self) -> bool {
|
||||
self.pipelines
|
||||
.values()
|
||||
.any(PipelineDetails::animation_callbacks_running)
|
||||
}
|
||||
|
||||
pub(crate) fn pipeline_ids(&self) -> Keys<'_, PipelineId, PipelineDetails> {
|
||||
self.pipelines.keys()
|
||||
}
|
||||
|
||||
pub(crate) fn pipeline_details(&mut self, pipeline_id: PipelineId) -> &mut PipelineDetails {
|
||||
self.pipelines.entry(pipeline_id).or_insert_with(|| {
|
||||
self.pipeline_to_webview_map
|
||||
.borrow_mut()
|
||||
.insert(pipeline_id, self.id);
|
||||
PipelineDetails::new(pipeline_id)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn set_throttled(&mut self, pipeline_id: PipelineId, throttled: bool) {
|
||||
self.pipeline_details(pipeline_id).throttled = throttled;
|
||||
}
|
||||
|
||||
pub(crate) fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
|
||||
self.pipeline_to_webview_map
|
||||
.borrow_mut()
|
||||
.remove(&pipeline_id);
|
||||
self.pipelines.remove(&pipeline_id);
|
||||
}
|
||||
|
||||
pub(crate) fn set_frame_tree(&mut self, frame_tree: &SendableFrameTree) {
|
||||
let pipeline_id = frame_tree.pipeline.id;
|
||||
let old_pipeline_id = std::mem::replace(&mut self.root_pipeline_id, Some(pipeline_id));
|
||||
|
||||
if old_pipeline_id != self.root_pipeline_id {
|
||||
debug!(
|
||||
"Updating webview ({:?}) from pipeline {:?} to {:?}",
|
||||
3, old_pipeline_id, self.root_pipeline_id
|
||||
);
|
||||
}
|
||||
|
||||
self.set_frame_tree_on_pipeline_details(frame_tree, None);
|
||||
self.reset_scroll_tree_for_unattached_pipelines(frame_tree);
|
||||
}
|
||||
|
||||
pub(crate) fn set_frame_tree_on_pipeline_details(
|
||||
&mut self,
|
||||
frame_tree: &SendableFrameTree,
|
||||
parent_pipeline_id: Option<PipelineId>,
|
||||
) {
|
||||
let pipeline_id = frame_tree.pipeline.id;
|
||||
let pipeline_details = self.pipeline_details(pipeline_id);
|
||||
pipeline_details.pipeline = Some(frame_tree.pipeline.clone());
|
||||
pipeline_details.parent_pipeline_id = parent_pipeline_id;
|
||||
|
||||
for kid in &frame_tree.children {
|
||||
self.set_frame_tree_on_pipeline_details(kid, Some(pipeline_id));
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reset_scroll_tree_for_unattached_pipelines(
|
||||
&mut self,
|
||||
frame_tree: &SendableFrameTree,
|
||||
) {
|
||||
// TODO(mrobinson): Eventually this can selectively preserve the scroll trees
|
||||
// state for some unattached pipelines in order to preserve scroll position when
|
||||
// navigating backward and forward.
|
||||
fn collect_pipelines(
|
||||
pipelines: &mut FnvHashSet<PipelineId>,
|
||||
frame_tree: &SendableFrameTree,
|
||||
) {
|
||||
pipelines.insert(frame_tree.pipeline.id);
|
||||
for kid in &frame_tree.children {
|
||||
collect_pipelines(pipelines, kid);
|
||||
}
|
||||
}
|
||||
|
||||
let mut attached_pipelines: FnvHashSet<PipelineId> = FnvHashSet::default();
|
||||
collect_pipelines(&mut attached_pipelines, frame_tree);
|
||||
|
||||
self.pipelines
|
||||
.iter_mut()
|
||||
.filter(|(id, _)| !attached_pipelines.contains(id))
|
||||
.for_each(|(_, details)| {
|
||||
details.scroll_tree.nodes.iter_mut().for_each(|node| {
|
||||
node.set_offset(LayoutVector2D::zero());
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets or unsets the animations-running flag for the given pipeline, and schedules a
|
||||
/// recomposite if necessary. Returns true if the pipeline is throttled.
|
||||
pub(crate) fn change_running_animations_state(
|
||||
&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
animation_state: AnimationState,
|
||||
) -> bool {
|
||||
let pipeline_details = self.pipeline_details(pipeline_id);
|
||||
match animation_state {
|
||||
AnimationState::AnimationsPresent => {
|
||||
pipeline_details.animations_running = true;
|
||||
},
|
||||
AnimationState::AnimationCallbacksPresent => {
|
||||
pipeline_details.animation_callbacks_running = true;
|
||||
},
|
||||
AnimationState::NoAnimationsPresent => {
|
||||
pipeline_details.animations_running = false;
|
||||
},
|
||||
AnimationState::NoAnimationCallbacksPresent => {
|
||||
pipeline_details.animation_callbacks_running = false;
|
||||
},
|
||||
}
|
||||
pipeline_details.throttled
|
||||
}
|
||||
|
||||
pub(crate) fn tick_all_animations(&self, compositor: &IOCompositor) -> bool {
|
||||
let mut ticked_any = false;
|
||||
for pipeline_details in self.pipelines.values() {
|
||||
ticked_any = pipeline_details.tick_animations(compositor) || ticked_any;
|
||||
}
|
||||
ticked_any
|
||||
}
|
||||
|
||||
pub(crate) fn tick_animations_for_pipeline(
|
||||
&self,
|
||||
pipeline_id: PipelineId,
|
||||
compositor: &IOCompositor,
|
||||
) {
|
||||
if let Some(pipeline_details) = self.pipelines.get(&pipeline_id) {
|
||||
pipeline_details.tick_animations(compositor);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_pending_paint_metric(&mut self, pipeline_id: PipelineId, epoch: base::Epoch) {
|
||||
self.pipeline_details(pipeline_id)
|
||||
.pending_paint_metrics
|
||||
.push(epoch);
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct WebViewManager<WebView> {
|
||||
/// Our top-level browsing contexts. In the WebRender scene, their pipelines are the children of
|
||||
/// a single root pipeline that also applies any pinch zoom transformation.
|
||||
|
@ -27,6 +198,15 @@ pub struct WebViewManager<WebView> {
|
|||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct UnknownWebView(pub WebViewId);
|
||||
|
||||
impl<WebView> Default for WebViewManager<WebView> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
webviews: Default::default(),
|
||||
painting_order: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<WebView> WebViewManager<WebView> {
|
||||
pub fn remove(&mut self, webview_id: WebViewId) -> Result<WebView, UnknownWebView> {
|
||||
self.painting_order.retain(|b| *b != webview_id);
|
||||
|
@ -98,6 +278,14 @@ impl<WebView> WebViewManager<WebView> {
|
|||
pub fn entry(&mut self, webview_id: WebViewId) -> Entry<'_, WebViewId, WebView> {
|
||||
self.webviews.entry(webview_id)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Values<'_, WebViewId, WebView> {
|
||||
self.webviews.values()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> ValuesMut<'_, WebViewId, WebView> {
|
||||
self.webviews.values_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue