diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/compositing/compositor.rs | 81 | ||||
-rw-r--r-- | components/compositing/webview_renderer.rs | 82 | ||||
-rw-r--r-- | components/constellation/constellation.rs | 42 | ||||
-rw-r--r-- | components/constellation/event_loop.rs | 21 | ||||
-rw-r--r-- | components/devtools/actors/source.rs | 50 | ||||
-rw-r--r-- | components/devtools/actors/thread.rs | 39 | ||||
-rw-r--r-- | components/devtools/actors/watcher.rs | 2 | ||||
-rw-r--r-- | components/devtools/lib.rs | 9 | ||||
-rw-r--r-- | components/layout/dom.rs | 25 | ||||
-rw-r--r-- | components/layout/table/mod.rs | 1 | ||||
-rw-r--r-- | components/malloc_size_of/lib.rs | 1 | ||||
-rw-r--r-- | components/script/dom/document.rs | 30 | ||||
-rw-r--r-- | components/script/dom/node.rs | 1 | ||||
-rw-r--r-- | components/script/layout_image.rs | 5 | ||||
-rw-r--r-- | components/script/messaging.rs | 2 | ||||
-rw-r--r-- | components/script/script_thread.rs | 28 | ||||
-rw-r--r-- | components/shared/constellation/lib.rs | 17 | ||||
-rw-r--r-- | components/shared/script/lib.rs | 4 | ||||
-rw-r--r-- | components/shared/script_layout/lib.rs | 9 | ||||
-rw-r--r-- | components/shared/script_layout/wrapper_traits.rs | 6 |
20 files changed, 232 insertions, 223 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 4550188a7fa..41286a2760a 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -21,12 +21,12 @@ use compositing_traits::rendering_context::RenderingContext; use compositing_traits::{ CompositionPipeline, CompositorMsg, ImageUpdate, SendableFrameTree, WebViewTrait, }; -use constellation_traits::{AnimationTickType, EmbedderToConstellationMessage, PaintMetricEvent}; +use constellation_traits::{EmbedderToConstellationMessage, PaintMetricEvent}; use crossbeam_channel::{Receiver, Sender}; use dpi::PhysicalSize; use embedder_traits::{ - AnimationState, CompositorHitTestResult, Cursor, InputEvent, MouseButtonEvent, MouseMoveEvent, - ShutdownState, TouchEventType, UntrustedNodeAddress, ViewportDetails, + CompositorHitTestResult, Cursor, InputEvent, MouseButtonEvent, MouseMoveEvent, ShutdownState, + TouchEventType, UntrustedNodeAddress, ViewportDetails, }; use euclid::{Point2D, Rect, Scale, Size2D, Transform3D}; use fnv::FnvHashMap; @@ -197,9 +197,6 @@ pub(crate) struct PipelineDetails { /// The pipeline associated with this PipelineDetails object. pub pipeline: Option<CompositionPipeline>, - /// The [`PipelineId`] of this pipeline. - pub id: PipelineId, - /// The id of the parent pipeline, if any. pub parent_pipeline_id: Option<PipelineId>, @@ -243,32 +240,12 @@ impl PipelineDetails { pub(crate) fn animating(&self) -> bool { !self.throttled && (self.animation_callbacks_running || self.animations_running) } - - pub(crate) fn tick_animations(&self, compositor: &IOCompositor) { - if !self.animating() { - return; - } - - let mut tick_type = AnimationTickType::empty(); - if self.animations_running { - tick_type.insert(AnimationTickType::CSS_ANIMATIONS_AND_TRANSITIONS); - } - if self.animation_callbacks_running { - tick_type.insert(AnimationTickType::REQUEST_ANIMATION_FRAME); - } - - let msg = EmbedderToConstellationMessage::TickAnimation(self.id, tick_type); - if let Err(e) = compositor.global.borrow().constellation_sender.send(msg) { - warn!("Sending tick to constellation failed ({:?}).", e); - } - } } impl PipelineDetails { - pub(crate) fn new(id: PipelineId) -> PipelineDetails { + pub(crate) fn new() -> PipelineDetails { PipelineDetails { pipeline: None, - id, parent_pipeline_id: None, most_recent_display_list_epoch: None, animations_running: false, @@ -543,22 +520,14 @@ impl IOCompositor { pipeline_id, animation_state, ) => { - let mut throttled = true; if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) { - throttled = webview_renderer - .change_running_animations_state(pipeline_id, animation_state); - } - - // These operations should eventually happen per-WebView, but they are global now as rendering - // is still global to all WebViews. - if !throttled && animation_state == AnimationState::AnimationsPresent { - self.set_needs_repaint(RepaintReason::ChangedAnimationState); - } - - if !throttled && animation_state == AnimationState::AnimationCallbacksPresent { - // We need to fetch the WebView again in order to avoid a double borrow. - if let Some(webview_renderer) = self.webview_renderers.get(webview_id) { - webview_renderer.tick_animations_for_pipeline(pipeline_id, self); + if webview_renderer + .change_pipeline_running_animations_state(pipeline_id, animation_state) && + webview_renderer.animating() + { + // These operations should eventually happen per-WebView, but they are + // global now as rendering is still global to all WebViews. + self.process_animations(true); } } }, @@ -605,8 +574,13 @@ impl IOCompositor { CompositorMsg::SetThrottled(webview_id, pipeline_id, throttled) => { if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) { - webview_renderer.set_throttled(pipeline_id, throttled); - self.process_animations(true); + if webview_renderer.set_throttled(pipeline_id, throttled) && + webview_renderer.animating() + { + // These operations should eventually happen per-WebView, but they are + // global now as rendering is still global to all WebViews. + self.process_animations(true); + } } }, @@ -1283,8 +1257,23 @@ impl IOCompositor { } self.last_animation_tick = Instant::now(); - for webview_renderer in self.webview_renderers.iter() { - webview_renderer.tick_all_animations(self); + let animating_webviews: Vec<_> = self + .webview_renderers + .iter() + .filter_map(|webview_renderer| { + if webview_renderer.animating() { + Some(webview_renderer.id) + } else { + None + } + }) + .collect(); + if !animating_webviews.is_empty() { + if let Err(error) = self.global.borrow().constellation_sender.send( + EmbedderToConstellationMessage::TickAnimation(animating_webviews), + ) { + warn!("Sending tick to constellation failed ({error:?})."); + } } } diff --git a/components/compositing/webview_renderer.rs b/components/compositing/webview_renderer.rs index 6ad77d46043..614ef0ff4c3 100644 --- a/components/compositing/webview_renderer.rs +++ b/components/compositing/webview_renderer.rs @@ -86,6 +86,9 @@ pub(crate) struct WebViewRenderer { /// The HiDPI scale factor for the `WebView` associated with this renderer. This is controlled /// by the embedding layer. hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>, + /// Whether or not this [`WebViewRenderer`] isn't throttled and has a pipeline with + /// active animations or animation frame callbacks. + animating: bool, } impl Drop for WebViewRenderer { @@ -119,6 +122,7 @@ impl WebViewRenderer { min_viewport_zoom: Some(PinchZoomFactor::new(1.0)), max_viewport_zoom: None, hidpi_scale_factor: Scale::new(hidpi_scale_factor.0), + animating: false, } } @@ -138,6 +142,10 @@ impl WebViewRenderer { self.pipelines.keys() } + pub(crate) fn animating(&self) -> bool { + self.animating + } + /// Returns the [`PipelineDetails`] for the given [`PipelineId`], creating it if needed. pub(crate) fn ensure_pipeline_details( &mut self, @@ -148,14 +156,10 @@ impl WebViewRenderer { .borrow_mut() .pipeline_to_webview_map .insert(pipeline_id, self.id); - PipelineDetails::new(pipeline_id) + PipelineDetails::new() }) } - pub(crate) fn set_throttled(&mut self, pipeline_id: PipelineId, throttled: bool) { - self.ensure_pipeline_details(pipeline_id).throttled = throttled; - } - pub(crate) fn remove_pipeline(&mut self, pipeline_id: PipelineId) { self.global .borrow_mut() @@ -245,51 +249,45 @@ impl WebViewRenderer { }) } - /// Sets or unsets the animations-running flag for the given pipeline. Returns true if - /// the pipeline is throttled. - pub(crate) fn change_running_animations_state( + /// Sets or unsets the animations-running flag for the given pipeline. Returns + /// true if the [`WebViewRenderer`]'s overall animating state changed. + pub(crate) fn change_pipeline_running_animations_state( &mut self, pipeline_id: PipelineId, animation_state: AnimationState, ) -> bool { - let throttled = { - let pipeline_details = self.ensure_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 - }; - - let animating = self.pipelines.values().any(PipelineDetails::animating); - self.webview.set_animating(animating); - throttled + let pipeline_details = self.ensure_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; + }, + } + self.update_animation_state() } - pub(crate) fn tick_all_animations(&self, compositor: &IOCompositor) { - for pipeline_details in self.pipelines.values() { - pipeline_details.tick_animations(compositor) - } + /// Sets or unsets the throttled flag for the given pipeline. Returns + /// true if the [`WebViewRenderer`]'s overall animating state changed. + pub(crate) fn set_throttled(&mut self, pipeline_id: PipelineId, throttled: bool) -> bool { + self.ensure_pipeline_details(pipeline_id).throttled = throttled; + + // Throttling a pipeline can cause it to be taken into the "not-animating" state. + self.update_animation_state() } - 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 update_animation_state(&mut self) -> bool { + let animating = self.pipelines.values().any(PipelineDetails::animating); + let old_animating = std::mem::replace(&mut self.animating, animating); + self.webview.set_animating(self.animating); + old_animating != self.animating } /// On a Window refresh tick (e.g. vsync) diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 3f70b0abb89..05081fe0ba7 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -112,13 +112,12 @@ use compositing_traits::{ CompositorMsg, CompositorProxy, SendableFrameTree, WebrenderExternalImageRegistry, }; use constellation_traits::{ - AnimationTickType, AuxiliaryWebViewCreationRequest, AuxiliaryWebViewCreationResponse, - BroadcastMsg, DocumentState, EmbedderToConstellationMessage, IFrameLoadInfo, - IFrameLoadInfoWithData, IFrameSandboxState, IFrameSizeMsg, Job, LoadData, LoadOrigin, LogEntry, - MessagePortMsg, NavigationHistoryBehavior, PaintMetricEvent, PortMessageTask, SWManagerMsg, - SWManagerSenders, ScriptToConstellationChan, ScriptToConstellationMessage, ScrollState, - ServiceWorkerManagerFactory, ServiceWorkerMsg, StructuredSerializedData, TraversalDirection, - WindowSizeType, + AuxiliaryWebViewCreationRequest, AuxiliaryWebViewCreationResponse, BroadcastMsg, DocumentState, + EmbedderToConstellationMessage, IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, + IFrameSizeMsg, Job, LoadData, LoadOrigin, LogEntry, MessagePortMsg, NavigationHistoryBehavior, + PaintMetricEvent, PortMessageTask, SWManagerMsg, SWManagerSenders, ScriptToConstellationChan, + ScriptToConstellationMessage, ScrollState, ServiceWorkerManagerFactory, ServiceWorkerMsg, + StructuredSerializedData, TraversalDirection, WindowSizeType, }; use crossbeam_channel::{Receiver, Select, Sender, unbounded}; use devtools_traits::{ @@ -1398,8 +1397,8 @@ where EmbedderToConstellationMessage::ThemeChange(theme) => { self.handle_theme_change(theme); }, - EmbedderToConstellationMessage::TickAnimation(pipeline_id, tick_type) => { - self.handle_tick_animation(pipeline_id, tick_type) + EmbedderToConstellationMessage::TickAnimation(webview_ids) => { + self.handle_tick_animation(webview_ids) }, EmbedderToConstellationMessage::WebDriverCommand(command) => { self.handle_webdriver_msg(command); @@ -3528,15 +3527,24 @@ where feature = "tracing", tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") )] - fn handle_tick_animation(&mut self, pipeline_id: PipelineId, tick_type: AnimationTickType) { - let pipeline = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline, - None => return warn!("{}: Got script tick after closure", pipeline_id), - }; + fn handle_tick_animation(&mut self, webview_ids: Vec<WebViewId>) { + let mut animating_event_loops = HashSet::new(); - let message = ScriptThreadMessage::TickAllAnimations(pipeline_id, tick_type); - if let Err(e) = pipeline.event_loop.send(message) { - self.handle_send_error(pipeline_id, e); + for webview_id in webview_ids.iter() { + for browsing_context in self.fully_active_browsing_contexts_iter(*webview_id) { + let Some(pipeline) = self.pipelines.get(&browsing_context.pipeline_id) else { + continue; + }; + animating_event_loops.insert(pipeline.event_loop.clone()); + } + } + + for event_loop in animating_event_loops { + // No error handling here. It's unclear what to do when this fails as the error isn't associated + // with a particular pipeline. In addition, the danger of not progressing animations is pretty + // low, so it's probably safe to ignore this error and handle the crashed ScriptThread on + // some other message. + let _ = event_loop.send(ScriptThreadMessage::TickAllAnimations(webview_ids.clone())); } } diff --git a/components/constellation/event_loop.rs b/components/constellation/event_loop.rs index 362960eba64..46542e7212f 100644 --- a/components/constellation/event_loop.rs +++ b/components/constellation/event_loop.rs @@ -6,17 +6,36 @@ //! view of a script thread. When an `EventLoop` is dropped, an `ExitScriptThread` //! message is sent to the script thread, asking it to shut down. +use std::hash::Hash; use std::marker::PhantomData; use std::rc::Rc; +use std::sync::atomic::{AtomicUsize, Ordering}; use ipc_channel::Error; use ipc_channel::ipc::IpcSender; use script_traits::ScriptThreadMessage; +static CURRENT_EVENT_LOOP_ID: AtomicUsize = AtomicUsize::new(0); + /// <https://html.spec.whatwg.org/multipage/#event-loop> pub struct EventLoop { script_chan: IpcSender<ScriptThreadMessage>, dont_send_or_sync: PhantomData<Rc<()>>, + id: usize, +} + +impl PartialEq for EventLoop { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for EventLoop {} + +impl Hash for EventLoop { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.id.hash(state); + } } impl Drop for EventLoop { @@ -28,9 +47,11 @@ impl Drop for EventLoop { impl EventLoop { /// Create a new event loop from the channel to its script thread. pub fn new(script_chan: IpcSender<ScriptThreadMessage>) -> Rc<EventLoop> { + let id = CURRENT_EVENT_LOOP_ID.fetch_add(1, Ordering::Relaxed); Rc::new(EventLoop { script_chan, dont_send_or_sync: PhantomData, + id, }) } diff --git a/components/devtools/actors/source.rs b/components/devtools/actors/source.rs new file mode 100644 index 00000000000..9d29bc1d3ef --- /dev/null +++ b/components/devtools/actors/source.rs @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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::{Ref, RefCell}; +use std::collections::BTreeSet; + +use serde::Serialize; +use servo_url::ServoUrl; + +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SourceData { + pub actor: String, + /// URL of the script, or URL of the page for inline scripts. + pub url: String, + pub is_black_boxed: bool, +} + +#[derive(Serialize)] +pub(crate) struct SourcesReply { + pub from: String, + pub sources: Vec<SourceData>, +} + +pub(crate) struct Source { + actor_name: String, + source_urls: RefCell<BTreeSet<SourceData>>, +} + +impl Source { + pub fn new(actor_name: String) -> Self { + Self { + actor_name, + source_urls: RefCell::new(BTreeSet::default()), + } + } + + pub fn add_source(&self, url: ServoUrl) { + self.source_urls.borrow_mut().insert(SourceData { + actor: self.actor_name.clone(), + url: url.to_string(), + is_black_boxed: false, + }); + } + + pub fn sources(&self) -> Ref<BTreeSet<SourceData>> { + self.source_urls.borrow() + } +} diff --git a/components/devtools/actors/thread.rs b/components/devtools/actors/thread.rs index 85ff2b732eb..7ff11dff675 100644 --- a/components/devtools/actors/thread.rs +++ b/components/devtools/actors/thread.rs @@ -2,14 +2,12 @@ * 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::{Ref, RefCell}; -use std::collections::BTreeSet; use std::net::TcpStream; use serde::Serialize; use serde_json::{Map, Value}; -use servo_url::ServoUrl; +use super::source::{Source, SourcesReply}; use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; use crate::protocol::JsonPacketStream; use crate::{EmptyReplyMsg, StreamId}; @@ -52,45 +50,18 @@ struct ThreadInterruptedReply { type_: String, } -#[derive(Serialize)] -struct SourcesReply { - from: String, - sources: Vec<Source>, -} - -#[derive(Eq, Ord, PartialEq, PartialOrd, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Source { - pub actor: String, - /// URL of the script, or URL of the page for inline scripts. - pub url: String, - pub is_black_boxed: bool, -} - pub struct ThreadActor { - name: String, - source_urls: RefCell<BTreeSet<Source>>, + pub name: String, + pub source_manager: Source, } impl ThreadActor { pub fn new(name: String) -> ThreadActor { ThreadActor { - name, - source_urls: RefCell::new(BTreeSet::default()), + name: name.clone(), + source_manager: Source::new(name), } } - - pub fn add_source(&self, url: ServoUrl) { - self.source_urls.borrow_mut().insert(Source { - actor: self.name.clone(), - url: url.to_string(), - is_black_boxed: false, - }); - } - - pub fn sources(&self) -> Ref<BTreeSet<Source>> { - self.source_urls.borrow() - } } impl Actor for ThreadActor { diff --git a/components/devtools/actors/watcher.rs b/components/devtools/actors/watcher.rs index d48374fc523..6a84499b6dd 100644 --- a/components/devtools/actors/watcher.rs +++ b/components/devtools/actors/watcher.rs @@ -265,7 +265,7 @@ impl Actor for WatcherActor { }, "source" => { let thread_actor = registry.find::<ThreadActor>(&target.thread); - let sources = thread_actor.sources(); + let sources = thread_actor.source_manager.sources(); target.resources_available(sources.iter().collect(), "source".into()); }, "console-message" | "error-message" => {}, diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index d4c3095b025..4d1e0222177 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -19,7 +19,7 @@ use std::net::{Shutdown, TcpListener, TcpStream}; use std::sync::{Arc, Mutex}; use std::thread; -use actors::thread::Source; +use actors::source::SourceData; use base::id::{BrowsingContextId, PipelineId, WebViewId}; use crossbeam_channel::{Receiver, Sender, unbounded}; use devtools_traits::{ @@ -66,6 +66,7 @@ mod actors { pub mod process; pub mod reflow; pub mod root; + pub mod source; pub mod stylesheets; pub mod tab; pub mod thread; @@ -525,9 +526,11 @@ impl DevtoolsInstance { .clone(); let thread_actor = actors.find_mut::<ThreadActor>(&thread_actor_name); - thread_actor.add_source(source_info.url.clone()); + thread_actor + .source_manager + .add_source(source_info.url.clone()); - let source = Source { + let source = SourceData { actor: thread_actor_name.clone(), url: source_info.url.to_string(), is_black_boxed: false, diff --git a/components/layout/dom.rs b/components/layout/dom.rs index 6db4dbccd41..a81a6eec545 100644 --- a/components/layout/dom.rs +++ b/components/layout/dom.rs @@ -2,18 +2,21 @@ * 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::any::Any; use std::marker::PhantomData; use std::sync::Arc; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use base::id::{BrowsingContextId, PipelineId}; use html5ever::{local_name, ns}; +use malloc_size_of_derive::MallocSizeOf; use pixels::Image; use script_layout_interface::wrapper_traits::{ LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode, }; use script_layout_interface::{ - HTMLCanvasDataSource, LayoutElementType, LayoutNodeType as ScriptLayoutNodeType, + GenericLayoutDataTrait, HTMLCanvasDataSource, LayoutElementType, + LayoutNodeType as ScriptLayoutNodeType, }; use servo_arc::Arc as ServoArc; use style::properties::ComputedValues; @@ -31,7 +34,7 @@ use crate::table::TableLevelBox; use crate::taffy::TaffyItemBox; /// The data that is stored in each DOM node that is used by layout. -#[derive(Default)] +#[derive(Default, MallocSizeOf)] pub struct InnerDOMLayoutData { pub(super) self_box: ArcRefCell<Option<LayoutBox>>, pub(super) pseudo_before_box: ArcRefCell<Option<LayoutBox>>, @@ -54,6 +57,7 @@ impl InnerDOMLayoutData { } /// A box that is stored in one of the `DOMLayoutData` slots. +#[derive(MallocSizeOf)] pub(super) enum LayoutBox { DisplayContents, BlockLevel(ArcRefCell<BlockLevelBox>), @@ -98,11 +102,16 @@ impl LayoutBox { /// A wrapper for [`InnerDOMLayoutData`]. This is necessary to give the entire data /// structure interior mutability, as we will need to mutate the layout data of /// non-mutable DOM nodes. -#[derive(Default)] +#[derive(Default, MallocSizeOf)] pub struct DOMLayoutData(AtomicRefCell<InnerDOMLayoutData>); // The implementation of this trait allows the data to be stored in the DOM. impl LayoutDataTrait for DOMLayoutData {} +impl GenericLayoutDataTrait for DOMLayoutData { + fn as_any(&self) -> &dyn Any { + self + } +} pub struct BoxSlot<'dom> { pub(crate) slot: Option<ArcRefCell<Option<LayoutBox>>>, @@ -255,6 +264,7 @@ where } LayoutNode::layout_data(&self) .unwrap() + .as_any() .downcast_ref::<DOMLayoutData>() .unwrap() .0 @@ -262,8 +272,13 @@ where } fn layout_data(self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>> { - LayoutNode::layout_data(&self) - .map(|data| data.downcast_ref::<DOMLayoutData>().unwrap().0.borrow()) + LayoutNode::layout_data(&self).map(|data| { + data.as_any() + .downcast_ref::<DOMLayoutData>() + .unwrap() + .0 + .borrow() + }) } fn element_box_slot(&self) -> BoxSlot<'dom> { diff --git a/components/layout/table/mod.rs b/components/layout/table/mod.rs index 120270fc7cf..fe7f90437b8 100644 --- a/components/layout/table/mod.rs +++ b/components/layout/table/mod.rs @@ -346,6 +346,7 @@ pub(crate) struct TableLayoutStyle<'a> { /// Table parts that are stored in the DOM. This is used in order to map from /// the DOM to the box tree and will eventually be important for incremental /// layout. +#[derive(MallocSizeOf)] pub(crate) enum TableLevelBox { Caption(ArcRefCell<TableCaption>), Cell(ArcRefCell<TableSlotCell>), diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs index b7f677f8044..52523af7cb1 100644 --- a/components/malloc_size_of/lib.rs +++ b/components/malloc_size_of/lib.rs @@ -746,6 +746,7 @@ malloc_size_of_is_0!(std::sync::atomic::AtomicUsize); malloc_size_of_is_0!(std::time::Duration); malloc_size_of_is_0!(std::time::Instant); malloc_size_of_is_0!(std::time::SystemTime); +malloc_size_of_is_0!(style::data::ElementData); malloc_size_of_is_0!(style::font_face::SourceList); malloc_size_of_is_0!(style::properties::ComputedValues); malloc_size_of_is_0!(style::queries::values::PrefersColorScheme); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 852a12fc7c5..02bdd343d89 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -21,9 +21,7 @@ use base::id::WebViewId; use canvas_traits::canvas::CanvasId; use canvas_traits::webgl::{self, WebGLContextId, WebGLMsg}; use chrono::Local; -use constellation_traits::{ - AnimationTickType, NavigationHistoryBehavior, ScriptToConstellationMessage, -}; +use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage}; use content_security_policy::{self as csp, CspList, PolicyDisposition}; use cookie::Cookie; use cssparser::match_ignore_ascii_case; @@ -516,10 +514,6 @@ pub(crate) struct Document { pending_input_events: DomRefCell<Vec<ConstellationInputEvent>>, /// The index of the last mouse move event in the pending compositor events queue. mouse_move_event_index: DomRefCell<Option<usize>>, - /// Pending animation ticks, to be handled at the next rendering opportunity. - #[no_trace] - #[ignore_malloc_size_of = "AnimationTickType contains data from an outside crate"] - pending_animation_ticks: DomRefCell<AnimationTickType>, /// <https://drafts.csswg.org/resize-observer/#dom-document-resizeobservers-slot> /// /// Note: we are storing, but never removing, resize observers. @@ -2397,10 +2391,6 @@ impl Document { pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) { let _realm = enter_realm(self); - self.pending_animation_ticks - .borrow_mut() - .remove(AnimationTickType::REQUEST_ANIMATION_FRAME); - self.running_animation_callbacks.set(true); let was_faking_animation_frames = self.is_faking_animation_frames(); let timing = self.global().performance().Now(); @@ -3916,7 +3906,6 @@ impl Document { image_animation_manager: DomRefCell::new(ImageAnimationManager::new()), dirty_root: Default::default(), declarative_refresh: Default::default(), - pending_animation_ticks: Default::default(), pending_input_events: Default::default(), mouse_move_event_index: Default::default(), resize_observers: Default::default(), @@ -4689,18 +4678,6 @@ impl Document { .collect() } - /// Note a pending animation tick, to be processed at the next `update_the_rendering` task. - pub(crate) fn note_pending_animation_tick(&self, tick_type: AnimationTickType) { - self.pending_animation_ticks.borrow_mut().extend(tick_type); - } - - /// Whether this document has received an animation tick for rafs. - pub(crate) fn has_received_raf_tick(&self) -> bool { - self.pending_animation_ticks - .borrow() - .contains(AnimationTickType::REQUEST_ANIMATION_FRAME) - } - pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) { self.animation_timeline.borrow_mut().advance_specific(delta); let current_timeline_value = self.current_animation_timeline_value(); @@ -6437,10 +6414,7 @@ impl FakeRequestAnimationFrameCallback { pub(crate) fn invoke(self, can_gc: CanGc) { // TODO: Once there is a more generic mechanism to trigger `update_the_rendering` when // not driven by the compositor, it should be used here. - self.document - .root() - .note_pending_animation_tick(AnimationTickType::REQUEST_ANIMATION_FRAME); - with_script_thread(|script_thread| script_thread.update_the_rendering(false, can_gc)) + with_script_thread(|script_thread| script_thread.update_the_rendering(true, can_gc)) } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 2a01370085a..45a107ae673 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -167,7 +167,6 @@ pub struct Node { /// Layout data for this node. This is populated during layout and can /// be used for incremental relayout and script queries. - #[ignore_malloc_size_of = "trait object"] #[no_trace] layout_data: DomRefCell<Option<Box<GenericLayoutData>>>, } diff --git a/components/script/layout_image.rs b/components/script/layout_image.rs index 7fd23804ffd..df542b4b759 100644 --- a/components/script/layout_image.rs +++ b/components/script/layout_image.rs @@ -119,7 +119,10 @@ pub(crate) fn fetch_image_for_layout( ) .origin(document.origin().immutable().clone()) .destination(Destination::Image) - .pipeline_id(Some(document.global().pipeline_id())); + .pipeline_id(Some(document.global().pipeline_id())) + .insecure_requests_policy(document.insecure_requests_policy()) + .has_trustworthy_ancestor_origin(document.has_trustworthy_ancestor_origin()) + .policy_container(document.policy_container().to_owned()); // Layout image loads do not delay the document load event. document.fetch_background(request, context); diff --git a/components/script/messaging.rs b/components/script/messaging.rs index 808b338e709..7d0b7aabe05 100644 --- a/components/script/messaging.rs +++ b/components/script/messaging.rs @@ -73,7 +73,7 @@ impl MixedMessage { ScriptThreadMessage::RemoveHistoryStates(id, ..) => Some(*id), ScriptThreadMessage::FocusIFrame(id, ..) => Some(*id), ScriptThreadMessage::WebDriverScriptCommand(id, ..) => Some(*id), - ScriptThreadMessage::TickAllAnimations(id, ..) => Some(*id), + ScriptThreadMessage::TickAllAnimations(..) => None, ScriptThreadMessage::WebFontLoaded(id, ..) => Some(*id), ScriptThreadMessage::DispatchIFrameLoadEvent { target: _, diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index c9b27bb6c56..07310073949 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -1147,14 +1147,6 @@ impl ScriptThread { return; } - // Run rafs for all pipeline, if a raf tick was received for any. - // This ensures relative ordering of rafs between parent doc and iframes. - let should_run_rafs = self - .documents - .borrow() - .iter() - .any(|(_, doc)| doc.is_fully_active() && doc.has_received_raf_tick()); - let any_animations_running = self.documents.borrow().iter().any(|(_, document)| { document.is_fully_active() && document.animations().running_animation_count() != 0 }); @@ -1242,7 +1234,7 @@ impl ScriptThread { // > 14. For each doc of docs, run the animation frame callbacks for doc, passing // > in the relative high resolution time given frameTimestamp and doc's // > relevant global object as the timestamp. - if should_run_rafs { + if requested_by_compositor { document.run_the_animation_frame_callbacks(can_gc); } @@ -1421,18 +1413,9 @@ impl ScriptThread { self.handle_viewport(id, rect); }), MixedMessage::FromConstellation(ScriptThreadMessage::TickAllAnimations( - pipeline_id, - tick_type, + _webviews, )) => { - if let Some(document) = self.documents.borrow().find_document(pipeline_id) { - document.note_pending_animation_tick(tick_type); - compositor_requested_update_the_rendering = true; - } else { - warn!( - "Trying to note pending animation tick for closed pipeline {}.", - pipeline_id - ) - } + compositor_requested_update_the_rendering = true; }, MixedMessage::FromConstellation(ScriptThreadMessage::SendInputEvent(id, event)) => { self.handle_input_event(id, event) @@ -2439,8 +2422,6 @@ impl ScriptThread { let mut reports = vec![]; perform_memory_report(|ops| { - let prefix = format!("url({urls})"); - reports.extend(self.get_cx().get_reports(prefix.clone(), ops)); for (_, document) in documents.iter() { document .window() @@ -2448,6 +2429,9 @@ impl ScriptThread { .collect_reports(&mut reports, ops); } + let prefix = format!("url({urls})"); + reports.extend(self.get_cx().get_reports(prefix.clone(), ops)); + reports.push(self.image_cache.memory_report(&prefix, ops)); }); diff --git a/components/shared/constellation/lib.rs b/components/shared/constellation/lib.rs index 548e17b532c..b3d4fe525a1 100644 --- a/components/shared/constellation/lib.rs +++ b/components/shared/constellation/lib.rs @@ -18,7 +18,6 @@ use std::time::Duration; use base::Epoch; use base::cross_process_instant::CrossProcessInstant; use base::id::{MessagePortId, PipelineId, WebViewId}; -use bitflags::bitflags; use embedder_traits::{ CompositorHitTestResult, Cursor, InputEvent, MediaSessionActionType, Theme, ViewportDetails, WebDriverCommandMsg, @@ -57,8 +56,9 @@ pub enum EmbedderToConstellationMessage { ChangeViewportDetails(WebViewId, ViewportDetails, WindowSizeType), /// Inform the constellation of a theme change. ThemeChange(Theme), - /// Requests that the constellation instruct layout to begin a new tick of the animation. - TickAnimation(PipelineId, AnimationTickType), + /// Requests that the constellation instruct script/layout to try to layout again and tick + /// animations. + TickAnimation(Vec<WebViewId>), /// Dispatch a webdriver command WebDriverCommand(WebDriverCommandMsg), /// Reload a top-level browsing context. @@ -130,17 +130,6 @@ pub enum WindowSizeType { Resize, } -bitflags! { - #[derive(Debug, Default, Deserialize, Serialize)] - /// Specifies if rAF should be triggered and/or CSS Animations and Transitions. - pub struct AnimationTickType: u8 { - /// Trigger a call to requestAnimationFrame. - const REQUEST_ANIMATION_FRAME = 0b001; - /// Trigger restyles for CSS Animations and Transitions. - const CSS_ANIMATIONS_AND_TRANSITIONS = 0b010; - } -} - /// The scroll state of a stacking context. #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct ScrollState { diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index a39be739fd5..7323907cba3 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -20,7 +20,7 @@ use bluetooth_traits::BluetoothRequest; use canvas_traits::webgl::WebGLPipeline; use compositing_traits::CrossProcessCompositorApi; use constellation_traits::{ - AnimationTickType, LoadData, NavigationHistoryBehavior, ScriptToConstellationChan, ScrollState, + LoadData, NavigationHistoryBehavior, ScriptToConstellationChan, ScrollState, StructuredSerializedData, WindowSizeType, }; use crossbeam_channel::{RecvTimeoutError, Sender}; @@ -195,7 +195,7 @@ pub enum ScriptThreadMessage { /// Passes a webdriver command to the script thread for execution WebDriverScriptCommand(PipelineId, WebDriverScriptCommand), /// Notifies script thread that all animations are done - TickAllAnimations(PipelineId, AnimationTickType), + TickAllAnimations(Vec<WebViewId>), /// Notifies the script thread that a new Web font has been loaded, and thus the page should be /// reflowed. WebFontLoaded(PipelineId, bool /* success */), diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index 69e577e139d..233d02dfd47 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -27,7 +27,7 @@ use fonts::{FontContext, SystemFontServiceProxy}; use fxhash::FxHashMap; use ipc_channel::ipc::IpcSender; use libc::c_void; -use malloc_size_of::MallocSizeOfOps; +use malloc_size_of::{MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps}; use malloc_size_of_derive::MallocSizeOf; use net_traits::image_cache::{ImageCache, PendingImageId}; use pixels::Image; @@ -51,7 +51,11 @@ use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot}; use style::stylesheets::Stylesheet; use webrender_api::ImageKey; -pub type GenericLayoutData = dyn Any + Send + Sync; +pub trait GenericLayoutDataTrait: Any + MallocSizeOfTrait { + fn as_any(&self) -> &dyn Any; +} + +pub type GenericLayoutData = dyn GenericLayoutDataTrait + Send + Sync; #[derive(MallocSizeOf)] pub struct StyleData { @@ -59,7 +63,6 @@ pub struct StyleData { /// style system is being used standalone, this is all that hangs /// off the node. This must be first to permit the various /// transmutations between ElementData and PersistentLayoutData. - #[ignore_malloc_size_of = "This probably should not be ignored"] pub element_data: AtomicRefCell<ElementData>, /// Information needed during parallel traversals. diff --git a/components/shared/script_layout/wrapper_traits.rs b/components/shared/script_layout/wrapper_traits.rs index be27050a42f..6c4de339c1b 100644 --- a/components/shared/script_layout/wrapper_traits.rs +++ b/components/shared/script_layout/wrapper_traits.rs @@ -25,11 +25,11 @@ use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorIm use style::stylist::RuleInclusion; use crate::{ - FragmentType, GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutNodeType, SVGSVGData, - StyleData, + FragmentType, GenericLayoutData, GenericLayoutDataTrait, HTMLCanvasData, HTMLMediaData, + LayoutNodeType, SVGSVGData, StyleData, }; -pub trait LayoutDataTrait: Default + Send + Sync + 'static {} +pub trait LayoutDataTrait: GenericLayoutDataTrait + Default + Send + Sync + 'static {} /// A wrapper so that layout can access only the methods that it should have access to. Layout must /// only ever see these and must never see instances of `LayoutDom`. |