diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index d1cf5fed950..2d30004746e 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -3106,13 +3106,18 @@ where } fn handle_iframe_size_msg(&mut self, iframe_sizes: Vec) { - for IFrameSizeMsg { data, type_ } in iframe_sizes { + for IFrameSizeMsg { + browsing_context_id, + size, + type_, + } in iframe_sizes + { let window_size = WindowSizeData { - initial_viewport: data.size, + initial_viewport: size, device_pixel_ratio: self.window_size.device_pixel_ratio, }; - self.resize_browsing_context(window_size, type_, data.id); + self.resize_browsing_context(window_size, type_, browsing_context_id); } } diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index cad8b712142..17f6a974a50 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -43,10 +43,9 @@ use gfx::text::glyph::ByteIndex; use gfx::text::TextRun; use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId}; use ipc_channel::ipc; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{BrowsingContextId, PipelineId}; use net_traits::image_cache::UsePlaceholder; use range::Range; -use script_traits::IFrameSize; use servo_config::opts; use servo_geometry::{self, MaxRect}; use std::default::Default; @@ -68,7 +67,7 @@ use style::values::generics::background::BackgroundSize; use style::values::generics::image::PaintWorklet; use style::values::specified::ui::CursorKind; use style::values::RGBA; -use style_traits::ToCss; +use style_traits::{CSSPixel, ToCss}; use webrender_api::units::{LayoutRect, LayoutTransform, LayoutVector2D}; use webrender_api::{self, BorderDetails, BorderRadius, BorderSide, BoxShadowClipMode, ColorF}; use webrender_api::{ColorU, ExternalScrollId, FilterOp, GlyphInstance, ImageRendering, LineStyle}; @@ -328,7 +327,7 @@ pub struct DisplayListBuildState<'a> { /// Vector containing iframe sizes, used to inform the constellation about /// new iframe sizes - pub iframe_sizes: Vec, + pub iframe_sizes: FnvHashMap>, /// Stores text runs to answer text queries used to place a cursor inside text. pub indexable_text: IndexableText, @@ -350,7 +349,7 @@ impl<'a> DisplayListBuildState<'a> { current_clipping_and_scrolling: ClippingAndScrolling::simple( ClipScrollNodeIndex::root_scroll_node(), ), - iframe_sizes: Vec::new(), + iframe_sizes: FnvHashMap::default(), indexable_text: IndexableText::default(), } } @@ -1838,10 +1837,10 @@ impl Fragment { // XXXjdm: This sleight-of-hand to convert LayoutRect -> Size2D // looks bogus. - state.iframe_sizes.push(IFrameSize { - id: browsing_context_id, - size: euclid::Size2D::new(bounds.size.width, bounds.size.height), - }); + state.iframe_sizes.insert( + browsing_context_id, + euclid::Size2D::new(bounds.size.width, bounds.size.height), + ); let pipeline_id = match fragment_info.pipeline_id { Some(pipeline_id) => pipeline_id, diff --git a/components/layout_2020/display_list/mod.rs b/components/layout_2020/display_list/mod.rs index 73b7b6bb97f..ae34c5ad952 100644 --- a/components/layout_2020/display_list/mod.rs +++ b/components/layout_2020/display_list/mod.rs @@ -10,8 +10,10 @@ use crate::replaced::IntrinsicSizes; use crate::style_ext::ComputedValuesExt; use embedder_traits::Cursor; use euclid::{Point2D, SideOffsets2D, Size2D}; +use fnv::FnvHashMap; use gfx::text::glyph::GlyphStore; use mitochondria::OnceCell; +use msg::constellation_msg::BrowsingContextId; use net_traits::image_cache::UsePlaceholder; use script_traits::compositor::CompositorDisplayListInfo; use std::sync::Arc; @@ -22,6 +24,7 @@ use style::properties::ComputedValues; use style::values::computed::{BorderStyle, Length, LengthPercentage}; use style::values::specified::text::TextDecorationLine; use style::values::specified::ui::CursorKind; +use style_traits::CSSPixel; use webrender_api::{self as wr, units}; mod background; @@ -48,6 +51,7 @@ pub struct DisplayListBuilder<'a> { pub context: &'a LayoutContext<'a>, pub wr: wr::DisplayListBuilder, pub compositor_info: CompositorDisplayListInfo, + pub iframe_sizes: FnvHashMap>, /// Contentful paint, for the purpose of /// https://w3c.github.io/paint-timing/#first-contentful-paint @@ -69,6 +73,7 @@ impl<'a> DisplayListBuilder<'a> { context, wr: wr::DisplayListBuilder::new(pipeline_id, fragment_tree.scrollable_overflow()), compositor_info: CompositorDisplayListInfo::default(), + iframe_sizes: FnvHashMap::default(), } } @@ -142,6 +147,34 @@ impl Fragment { Visibility::Hidden => (), Visibility::Collapse => (), }, + Fragment::IFrame(iframe) => match iframe.style.get_inherited_box().visibility { + Visibility::Visible => { + builder.is_contentful = true; + let rect = iframe + .rect + .to_physical(iframe.style.writing_mode, containing_block) + .translate(containing_block.origin.to_vector()); + + builder.iframe_sizes.insert( + iframe.browsing_context_id, + Size2D::new(rect.size.width.px(), rect.size.height.px()), + ); + + let common = builder.common_properties(rect.to_webrender(), &iframe.style); + builder.wr.push_iframe( + rect.to_webrender(), + common.clip_rect, + &wr::SpaceAndClipInfo { + spatial_id: common.spatial_id, + clip_id: common.clip_id, + }, + iframe.pipeline_id.to_webrender(), + true, + ); + }, + Visibility::Hidden => (), + Visibility::Collapse => (), + }, Fragment::Text(t) => match t.parent_style.get_inherited_box().visibility { Visibility::Visible => { self.build_display_list_for_text_fragment(t, builder, containing_block) diff --git a/components/layout_2020/display_list/stacking_context.rs b/components/layout_2020/display_list/stacking_context.rs index 669dfd9c2ae..78992d9c5bc 100644 --- a/components/layout_2020/display_list/stacking_context.rs +++ b/components/layout_2020/display_list/stacking_context.rs @@ -482,7 +482,7 @@ impl Fragment { stacking_context, ); }, - Fragment::Text(_) | Fragment::Image(_) => { + Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => { stacking_context.fragments.push(StackingContextFragment { section: StackingContextSection::Content, space_and_clip: builder.current_space_and_clip, diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index 4eb402c1726..2e1d81ad8fb 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -11,6 +11,7 @@ use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOuts use crate::wrapper::GetStyleAndLayoutData; use atomic_refcell::AtomicRefMut; use html5ever::LocalName; +use msg::constellation_msg::{BrowsingContextId, PipelineId}; use net_traits::image::base::Image as NetImage; use script_layout_interface::wrapper_traits::{ LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode, @@ -396,6 +397,7 @@ pub(crate) trait NodeExt<'dom>: 'dom + Copy + LayoutNode<'dom> + Send + Sync { /// adjusted for `image_density`. fn as_image(self) -> Option<(Option>, PhysicalSize)>; fn as_canvas(self) -> Option<(CanvasInfo, PhysicalSize)>; + fn as_iframe(self) -> Option<(PipelineId, BrowsingContextId)>; fn first_child(self) -> Option; fn next_sibling(self) -> Option; fn parent_node(self) -> Option; @@ -462,6 +464,16 @@ where )) } + fn as_iframe(self) -> Option<(PipelineId, BrowsingContextId)> { + let node = self.to_threadsafe(); + match (node.iframe_pipeline_id(), node.iframe_browsing_context_id()) { + (Some(pipeline_id), Some(browsing_context_id)) => { + Some((pipeline_id, browsing_context_id)) + }, + _ => None, + } + } + fn first_child(self) -> Option { TNode::first_child(&self) } diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 21d99742367..80a42c70701 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -475,6 +475,7 @@ impl FragmentTree { .to_physical(fragment.parent_style.writing_mode, &containing_block), Fragment::AbsoluteOrFixedPositioned(_) | Fragment::Image(_) | + Fragment::IFrame(_) | Fragment::Anonymous(_) => return None, }; @@ -506,6 +507,7 @@ impl FragmentTree { Fragment::Box(_) | Fragment::Text(_) | Fragment::Image(_) | + Fragment::IFrame(_) | Fragment::Anonymous(_) => return None, }; diff --git a/components/layout_2020/fragments.rs b/components/layout_2020/fragments.rs index 73fa57be71e..b54fa90a52b 100644 --- a/components/layout_2020/fragments.rs +++ b/components/layout_2020/fragments.rs @@ -13,6 +13,7 @@ use gfx::font::FontMetrics as GfxFontMetrics; use gfx::text::glyph::GlyphStore; use gfx_traits::print_tree::PrintTree; use gfx_traits::{combine_id_with_fragment_type, FragmentType}; +use msg::constellation_msg::{BrowsingContextId, PipelineId}; #[cfg(not(debug_assertions))] use serde::ser::{Serialize, Serializer}; use servo_arc::Arc as ServoArc; @@ -70,6 +71,7 @@ pub(crate) enum Fragment { AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment), Text(TextFragment), Image(ImageFragment), + IFrame(IFrameFragment), } #[derive(Serialize)] @@ -174,6 +176,16 @@ pub(crate) struct ImageFragment { pub image_key: ImageKey, } +#[derive(Serialize)] +pub(crate) struct IFrameFragment { + pub debug_id: DebugId, + pub pipeline_id: PipelineId, + pub browsing_context_id: BrowsingContextId, + pub rect: Rect, + #[serde(skip_serializing)] + pub style: ServoArc, +} + impl Fragment { pub fn offset_inline(&mut self, offset: &Length) { let position = match self { @@ -182,6 +194,7 @@ impl Fragment { Fragment::Anonymous(f) => &mut f.rect.start_corner, Fragment::Text(f) => &mut f.rect.start_corner, Fragment::Image(f) => &mut f.rect.start_corner, + Fragment::IFrame(f) => &mut f.rect.start_corner, }; position.inline += *offset; @@ -193,7 +206,8 @@ impl Fragment { Fragment::Text(fragment) => Some(fragment.tag), Fragment::AbsoluteOrFixedPositioned(_) | Fragment::Anonymous(_) | - Fragment::Image(_) => None, + Fragment::Image(_) | + Fragment::IFrame(_) => None, } } @@ -204,6 +218,7 @@ impl Fragment { Fragment::Anonymous(fragment) => fragment.print(tree), Fragment::Text(fragment) => fragment.print(tree), Fragment::Image(fragment) => fragment.print(tree), + Fragment::IFrame(fragment) => fragment.print(tree), } } @@ -221,6 +236,9 @@ impl Fragment { Fragment::Image(fragment) => fragment .rect .to_physical(fragment.style.writing_mode, &containing_block), + Fragment::IFrame(fragment) => fragment + .rect + .to_physical(fragment.style.writing_mode, &containing_block), } } @@ -462,6 +480,16 @@ impl ImageFragment { } } +impl IFrameFragment { + pub fn print(&self, tree: &mut PrintTree) { + tree.add_item(format!( + "IFrame\ + \npipeline={:?} rect={:?}", + self.pipeline_id, self.rect + )); + } +} + impl CollapsedBlockMargins { pub fn from_margin(margin: &Sides) -> Self { Self { diff --git a/components/layout_2020/query.rs b/components/layout_2020/query.rs index ef322e6623c..0e99ec88fac 100644 --- a/components/layout_2020/query.rs +++ b/components/layout_2020/query.rs @@ -10,7 +10,6 @@ use app_units::Au; use euclid::default::{Point2D, Rect}; use euclid::Size2D; use euclid::Vector2D; -use ipc_channel::ipc::IpcSender; use msg::constellation_msg::PipelineId; use script_layout_interface::rpc::TextIndexResponse; use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC}; @@ -19,7 +18,6 @@ use script_layout_interface::rpc::{OffsetParentResponse, ResolvedStyleResponse}; use script_layout_interface::wrapper_traits::{ LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode, }; -use script_traits::LayoutMsg as ConstellationMsg; use script_traits::UntrustedNodeAddress; use servo_arc::Arc as ServoArc; use std::collections::HashMap; @@ -43,9 +41,6 @@ use webrender_api::ExternalScrollId; /// /// This needs to be protected by a mutex so we can do fast RPCs. pub struct LayoutThreadData { - /// The channel on which messages can be sent to the constellation. - pub constellation_chan: IpcSender, - /// The root stacking context. pub display_list: Option, @@ -427,6 +422,7 @@ fn process_offset_parent_query_inner( .to_physical(fragment.parent_style.writing_mode, &containing_block), Fragment::AbsoluteOrFixedPositioned(_) | Fragment::Image(_) | + Fragment::IFrame(_) | Fragment::Anonymous(_) => unreachable!(), }; let border_box = fragment_relative_rect.translate(containing_block.origin.to_vector()); @@ -503,6 +499,7 @@ fn process_offset_parent_query_inner( Fragment::AbsoluteOrFixedPositioned(_) | Fragment::Text(_) | Fragment::Image(_) | + Fragment::IFrame(_) | Fragment::Anonymous(_) => None, }; @@ -552,6 +549,7 @@ fn process_offset_parent_query_inner( Fragment::Box(_) | Fragment::Text(_) | Fragment::Image(_) | + Fragment::IFrame(_) | Fragment::Anonymous(_) => None, } }) diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index d5b22bdd573..907af6e67e9 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -4,7 +4,7 @@ use crate::context::LayoutContext; use crate::dom_traversal::NodeExt; -use crate::fragments::{DebugId, Fragment, ImageFragment}; +use crate::fragments::{DebugId, Fragment, IFrameFragment, ImageFragment}; use crate::geom::flow_relative::{Rect, Vec2}; use crate::geom::PhysicalSize; use crate::sizing::ContentSizes; @@ -12,6 +12,7 @@ use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin}; use crate::ContainingBlock; use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg}; use ipc_channel::ipc::{self, IpcSender}; +use msg::constellation_msg::{BrowsingContextId, PipelineId}; use net_traits::image::base::Image; use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder}; use servo_arc::Arc as ServoArc; @@ -41,6 +42,9 @@ pub(crate) struct ReplacedContent { /// /// * For SVG, see https://svgwg.org/svg2-draft/coords.html#SizingSVGInCSS /// and again https://github.com/w3c/csswg-drafts/issues/4572. +/// +/// * IFrames do not have intrinsic width and height or intrinsic ratio according +/// to https://drafts.csswg.org/css-images/#intrinsic-dimensions. #[derive(Debug, Serialize)] pub(crate) struct IntrinsicSizes { pub width: Option, @@ -75,9 +79,16 @@ pub(crate) struct CanvasInfo { pub canvas_id: CanvasId, } +#[derive(Debug, Serialize)] +pub(crate) struct IFrameInfo { + pub pipeline_id: PipelineId, + pub browsing_context_id: BrowsingContextId, +} + #[derive(Debug, Serialize)] pub(crate) enum ReplacedContentKind { Image(Option>), + IFrame(IFrameInfo), Canvas(CanvasInfo), } @@ -85,35 +96,51 @@ impl ReplacedContent { pub fn for_element<'dom>(element: impl NodeExt<'dom>) -> Option { let (kind, intrinsic_size_in_dots) = { if let Some((image, intrinsic_size_in_dots)) = element.as_image() { - (ReplacedContentKind::Image(image), intrinsic_size_in_dots) + ( + ReplacedContentKind::Image(image), + Some(intrinsic_size_in_dots), + ) } else if let Some((canvas_info, intrinsic_size_in_dots)) = element.as_canvas() { ( ReplacedContentKind::Canvas(canvas_info), - intrinsic_size_in_dots, + Some(intrinsic_size_in_dots), + ) + } else if let Some((pipeline_id, browsing_context_id)) = element.as_iframe() { + ( + ReplacedContentKind::IFrame(IFrameInfo { + pipeline_id, + browsing_context_id, + }), + None, ) } else { return None; } }; - // FIXME: should 'image-resolution' (when implemented) be used *instead* of - // `script::dom::htmlimageelement::ImageRequest::current_pixel_density`? - - // https://drafts.csswg.org/css-images-4/#the-image-resolution - let dppx = 1.0; - - let width = (intrinsic_size_in_dots.width as CSSFloat) / dppx; - let height = (intrinsic_size_in_dots.height as CSSFloat) / dppx; - - return Some(Self { - kind, - intrinsic: IntrinsicSizes { - width: Some(Length::new(width)), - height: Some(Length::new(height)), - // FIXME https://github.com/w3c/csswg-drafts/issues/4572 - ratio: Some(width / height), + let intrinsic = intrinsic_size_in_dots.map_or_else( + || IntrinsicSizes { + width: None, + height: None, + ratio: None, }, - }); + |intrinsic_size_in_dots| { + // FIXME: should 'image-resolution' (when implemented) be used *instead* of + // `script::dom::htmlimageelement::ImageRequest::current_pixel_density`? + // https://drafts.csswg.org/css-images-4/#the-image-resolution + let dppx = 1.0; + let width = (intrinsic_size_in_dots.width as CSSFloat) / dppx; + let height = (intrinsic_size_in_dots.height as CSSFloat) / dppx; + IntrinsicSizes { + width: Some(Length::new(width)), + height: Some(Length::new(height)), + // FIXME https://github.com/w3c/csswg-drafts/issues/4572 + ratio: Some(width / height), + } + }, + ); + + return Some(Self { kind, intrinsic }); } pub fn from_image_url<'dom>( @@ -203,6 +230,18 @@ impl ReplacedContent { }) .into_iter() .collect(), + ReplacedContentKind::IFrame(iframe) => { + vec![Fragment::IFrame(IFrameFragment { + debug_id: DebugId::new(), + style: style.clone(), + pipeline_id: iframe.pipeline_id, + browsing_context_id: iframe.browsing_context_id, + rect: Rect { + start_corner: Vec2::zero(), + size, + }, + })] + }, ReplacedContentKind::Canvas(canvas_info) => { if self.intrinsic.width == Some(Length::zero()) || self.intrinsic.height == Some(Length::zero()) @@ -264,6 +303,7 @@ impl ReplacedContent { let default_object_size = || { // FIXME: + // https://drafts.csswg.org/css-images/#default-object-size // “If 300px is too wide to fit the device, UAs should use the width of // the largest rectangle that has a 2:1 ratio and fits the device instead.” // “height of the largest rectangle that has a 2:1 ratio, has a height not greater diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 7600cdd478d..4ea217edfec 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -216,7 +216,7 @@ pub struct LayoutThread { layout_query_waiting_time: Histogram, /// The sizes of all iframes encountered during the last layout operation. - last_iframe_sizes: RefCell>>, + last_iframe_sizes: RefCell>>, /// Flag that indicates if LayoutThread is busy handling a request. busy: Arc, @@ -1008,6 +1008,49 @@ impl LayoutThread { ); } + /// Update the recorded iframe sizes of the contents of this layout thread and + /// when these sizes changes, send a message to the constellation informing it + /// of the new sizes. + fn update_iframe_sizes( + &self, + new_iframe_sizes: FnvHashMap>, + ) { + let old_iframe_sizes = + std::mem::replace(&mut *self.last_iframe_sizes.borrow_mut(), new_iframe_sizes); + + if self.last_iframe_sizes.borrow().is_empty() { + return; + } + + let size_messages: Vec<_> = self + .last_iframe_sizes + .borrow() + .iter() + .filter_map(|(browsing_context_id, size)| { + match old_iframe_sizes.get(&browsing_context_id) { + Some(old_size) if old_size != size => Some(IFrameSizeMsg { + browsing_context_id: *browsing_context_id, + size: *size, + type_: WindowSizeType::Resize, + }), + None => Some(IFrameSizeMsg { + browsing_context_id: *browsing_context_id, + size: *size, + type_: WindowSizeType::Initial, + }), + _ => None, + } + }) + .collect(); + + if !size_messages.is_empty() { + let msg = ConstellationMsg::IFrameSizes(size_messages); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Layout resize to constellation failed ({}).", e); + } + } + } + /// Computes the stacking-relative positions of all flows and, if the painting is dirty and the /// reflow type need it, builds the display list. fn compute_abs_pos_and_build_display_list( @@ -1068,48 +1111,10 @@ impl LayoutThread { build_state.root_stacking_context.bounds = origin; build_state.root_stacking_context.overflow = origin; - if !build_state.iframe_sizes.is_empty() { - // build_state.iframe_sizes is only used here, so its okay to replace - // it with an empty vector - let iframe_sizes = - std::mem::replace(&mut build_state.iframe_sizes, vec![]); - // Collect the last frame's iframe sizes to compute any differences. - // Every frame starts with a fresh collection so that any removed - // iframes do not linger. - let last_iframe_sizes = std::mem::replace( - &mut *self.last_iframe_sizes.borrow_mut(), - HashMap::default(), - ); - let mut size_messages = vec![]; - for new_size in iframe_sizes { - // Only notify the constellation about existing iframes - // that have a new size, or iframes that did not previously - // exist. - if let Some(old_size) = last_iframe_sizes.get(&new_size.id) { - if *old_size != new_size.size { - size_messages.push(IFrameSizeMsg { - data: new_size, - type_: WindowSizeType::Resize, - }); - } - } else { - size_messages.push(IFrameSizeMsg { - data: new_size, - type_: WindowSizeType::Initial, - }); - } - self.last_iframe_sizes - .borrow_mut() - .insert(new_size.id, new_size.size); - } - - if !size_messages.is_empty() { - let msg = ConstellationMsg::IFrameSizes(size_messages); - if let Err(e) = self.constellation_chan.send(msg) { - warn!("Layout resize to constellation failed ({}).", e); - } - } - } + // We will not use build_state.iframe_sizes again, so it's safe to move it. + let iframe_sizes = + std::mem::replace(&mut build_state.iframe_sizes, FnvHashMap::default()); + self.update_iframe_sizes(iframe_sizes); rw_data.indexable_text = std::mem::replace( &mut build_state.indexable_text, diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index fd5f0c91b32..2b7661a631b 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -51,10 +51,10 @@ use layout_traits::LayoutThreadFactory; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use metrics::{PaintTimeMetrics, ProfilerMetadataFactory, ProgressiveWebMetric}; use msg::constellation_msg::{ - BackgroundHangMonitor, BackgroundHangMonitorRegister, HangAnnotation, + BackgroundHangMonitor, BackgroundHangMonitorRegister, BrowsingContextId, HangAnnotation, + LayoutHangAnnotation, MonitoredComponentId, MonitoredComponentType, PipelineId, + TopLevelBrowsingContextId, }; -use msg::constellation_msg::{LayoutHangAnnotation, MonitoredComponentType, PipelineId}; -use msg::constellation_msg::{MonitoredComponentId, TopLevelBrowsingContextId}; use net_traits::image_cache::{ImageCache, UsePlaceholder}; use parking_lot::RwLock; use profile_traits::mem::{self as profile_mem, Report, ReportKind, ReportsChan}; @@ -64,10 +64,11 @@ use script_layout_interface::message::{LayoutThreadInit, Msg, NodesFromPointQuer use script_layout_interface::message::{QueryMsg, ReflowComplete, ReflowGoal, ScriptReflow}; use script_layout_interface::rpc::TextIndexResponse; use script_layout_interface::rpc::{LayoutRPC, OffsetParentResponse}; -use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; -use script_traits::{DrawAPaintImageResult, PaintWorkletError}; -use script_traits::{Painter, WebrenderIpcSender}; -use script_traits::{ScrollState, UntrustedNodeAddress, WindowSizeData}; +use script_traits::{ + ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg, + LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress, + WebrenderIpcSender, WindowSizeData, WindowSizeType, +}; use servo_arc::Arc as ServoArc; use servo_atoms::Atom; use servo_config::opts; @@ -135,6 +136,9 @@ pub struct LayoutThread { /// A means of communication with the background hang monitor. background_hang_monitor: Box, + /// The channel on which messages can be sent to the constellation. + constellation_chan: IpcSender, + /// The channel on which messages can be sent to the script thread. script_chan: IpcSender, @@ -190,6 +194,9 @@ pub struct LayoutThread { /// Paint time metrics. paint_time_metrics: PaintTimeMetrics, + /// The sizes of all iframes encountered during the last layout operation. + last_iframe_sizes: RefCell>>, + /// Flag that indicates if LayoutThread is busy handling a request. busy: Arc, @@ -493,6 +500,7 @@ impl LayoutThread { is_iframe: is_iframe, port: port, pipeline_port: pipeline_receiver, + constellation_chan, script_chan: script_chan.clone(), background_hang_monitor, time_profiler_chan: time_profiler_chan, @@ -513,7 +521,6 @@ impl LayoutThread { webrender_api: webrender_api_sender, stylist: Stylist::new(device, QuirksMode::NoQuirks), rw_data: Arc::new(Mutex::new(LayoutThreadData { - constellation_chan: constellation_chan, display_list: None, content_box_response: None, content_boxes_response: Vec::new(), @@ -531,6 +538,7 @@ impl LayoutThread { })), webrender_image_cache: Default::default(), paint_time_metrics: paint_time_metrics, + last_iframe_sizes: Default::default(), busy, load_webfonts_synchronously, relayout_event, @@ -919,8 +927,12 @@ impl LayoutThread { &QueryMsg::ElementInnerTextQuery(_) => { rw_data.element_inner_text_response = String::new(); }, - &QueryMsg::InnerWindowDimensionsQuery(_) => { - rw_data.inner_window_dimensions_response = None; + &QueryMsg::InnerWindowDimensionsQuery(browsing_context_id) => { + rw_data.inner_window_dimensions_response = self + .last_iframe_sizes + .borrow() + .get(&browsing_context_id) + .cloned(); }, }, ReflowGoal::Full | ReflowGoal::TickAnimations => {}, @@ -976,8 +988,7 @@ impl LayoutThread { if viewport_size_changed { if let Some(constraints) = self.stylist.viewport_constraints() { // let the constellation know about the viewport constraints - rw_data - .constellation_chan + self.constellation_chan .send(ConstellationMsg::ViewportConstrained( self.id, constraints.clone(), @@ -1348,6 +1359,8 @@ impl LayoutThread { display_list.wr.finalize(), ); + self.update_iframe_sizes(display_list.iframe_sizes); + if self.trace_layout { layout_debug::end_trace(self.generation.get()); } @@ -1391,6 +1404,49 @@ impl LayoutThread { } } } + + /// Update the recorded iframe sizes of the contents of this layout thread and + /// when these sizes changes, send a message to the constellation informing it + /// of the new sizes. + fn update_iframe_sizes( + &self, + new_iframe_sizes: FnvHashMap>, + ) { + let old_iframe_sizes = + std::mem::replace(&mut *self.last_iframe_sizes.borrow_mut(), new_iframe_sizes); + + if self.last_iframe_sizes.borrow().is_empty() { + return; + } + + let size_messages: Vec<_> = self + .last_iframe_sizes + .borrow() + .iter() + .filter_map(|(browsing_context_id, size)| { + match old_iframe_sizes.get(&browsing_context_id) { + Some(old_size) if old_size != size => Some(IFrameSizeMsg { + browsing_context_id: *browsing_context_id, + size: *size, + type_: WindowSizeType::Resize, + }), + None => Some(IFrameSizeMsg { + browsing_context_id: *browsing_context_id, + size: *size, + type_: WindowSizeType::Initial, + }), + _ => None, + } + }) + .collect(); + + if !size_messages.is_empty() { + let msg = ConstellationMsg::IFrameSizes(size_messages); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Layout resize to constellation failed ({}).", e); + } + } + } } impl ProfilerMetadataFactory for LayoutThread { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index fe5caa5fbda..e05306986c0 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1541,17 +1541,13 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> { } fn iframe_browsing_context_id(self) -> Option { - let iframe_element = self - .downcast::() - .expect("not an iframe element!"); - iframe_element.browsing_context_id() + self.downcast::() + .map_or(None, |iframe_element| iframe_element.browsing_context_id()) } fn iframe_pipeline_id(self) -> Option { - let iframe_element = self - .downcast::() - .expect("not an iframe element!"); - iframe_element.pipeline_id() + self.downcast::() + .map_or(None, |iframe_element| iframe_element.pipeline_id()) } #[allow(unsafe_code)] diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index d306cc696db..168b910b3c2 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -82,9 +82,7 @@ pub use crate::script_msg::{ DOMMessage, HistoryEntryReplacement, Job, JobError, JobResult, JobResultValue, JobType, SWManagerMsg, SWManagerSenders, ScopeThings, ServiceWorkerMsg, }; -pub use crate::script_msg::{ - EventResult, IFrameSize, IFrameSizeMsg, LayoutMsg, LogEntry, ScriptMsg, -}; +pub use crate::script_msg::{EventResult, IFrameSizeMsg, LayoutMsg, LogEntry, ScriptMsg}; /// The address of a node. Layout sends these back. They must be validated via /// `from_untrusted_node_address` before they can be used, because we do not trust layout. diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index b17f84180b5..afa3eeaea83 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -41,20 +41,13 @@ use style_traits::CSSPixel; use webgpu::{wgpu, WebGPU, WebGPUResponseResult}; use webrender_api::units::{DeviceIntPoint, DeviceIntSize}; -/// A particular iframe's size, associated with a browsing context. -#[derive(Clone, Copy, Debug, Deserialize, Serialize)] -pub struct IFrameSize { - /// The child browsing context for this iframe. - pub id: BrowsingContextId, - /// The size of the iframe. - pub size: Size2D, -} - /// An iframe sizing operation. #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub struct IFrameSizeMsg { - /// The iframe sizing data. - pub data: IFrameSize, + /// The child browsing context for this iframe. + pub browsing_context_id: BrowsingContextId, + /// The size of the iframe. + pub size: Size2D, /// The kind of sizing operation. pub type_: WindowSizeType, } diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/floats-clear/float-replaced-height-004.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/floats-clear/float-replaced-height-004.xht.ini deleted file mode 100644 index aac1cfe9d08..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/floats-clear/float-replaced-height-004.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[float-replaced-height-004.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/floats-clear/float-replaced-height-005.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/floats-clear/float-replaced-height-005.xht.ini deleted file mode 100644 index 330561fd2c9..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/floats-clear/float-replaced-height-005.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[float-replaced-height-005.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/floats-clear/float-replaced-height-007.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/floats-clear/float-replaced-height-007.xht.ini deleted file mode 100644 index 0a4f4ed9433..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/floats-clear/float-replaced-height-007.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[float-replaced-height-007.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/block-replaced-height-004.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/block-replaced-height-004.xht.ini deleted file mode 100644 index 212fae693d4..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/block-replaced-height-004.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[block-replaced-height-004.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/block-replaced-height-005.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/block-replaced-height-005.xht.ini deleted file mode 100644 index a54cfb5a9e7..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/block-replaced-height-005.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[block-replaced-height-005.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/block-replaced-height-007.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/block-replaced-height-007.xht.ini deleted file mode 100644 index feb0b61f02d..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/block-replaced-height-007.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[block-replaced-height-007.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/cross-domain-iframe-paint-order.sub.html.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/cross-domain-iframe-paint-order.sub.html.ini deleted file mode 100644 index 091a06a0350..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/cross-domain-iframe-paint-order.sub.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[cross-domain-iframe-paint-order.sub.html] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-block-replaced-height-004.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-block-replaced-height-004.xht.ini deleted file mode 100644 index 851eec59297..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-block-replaced-height-004.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[inline-block-replaced-height-004.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-block-replaced-height-005.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-block-replaced-height-005.xht.ini deleted file mode 100644 index d39fbf30b24..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-block-replaced-height-005.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[inline-block-replaced-height-005.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-block-replaced-height-007.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-block-replaced-height-007.xht.ini deleted file mode 100644 index 525a0612db1..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-block-replaced-height-007.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[inline-block-replaced-height-007.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-replaced-height-004.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-replaced-height-004.xht.ini deleted file mode 100644 index b13b8c57648..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-replaced-height-004.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[inline-replaced-height-004.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-replaced-height-005.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-replaced-height-005.xht.ini deleted file mode 100644 index ab760ed1aad..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-replaced-height-005.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[inline-replaced-height-005.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-replaced-height-007.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-replaced-height-007.xht.ini deleted file mode 100644 index f6a7c44063d..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/inline-replaced-height-007.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[inline-replaced-height-007.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/resizable-iframe-paint-order.html.ini b/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/resizable-iframe-paint-order.html.ini deleted file mode 100644 index 6fa43bf94a5..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/normal-flow/resizable-iframe-paint-order.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[resizable-iframe-paint-order.html] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-004.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-004.xht.ini deleted file mode 100644 index 665ed871ed1..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-004.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-004.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-005.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-005.xht.ini deleted file mode 100644 index ecf1c13b37b..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-005.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-005.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-011.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-011.xht.ini deleted file mode 100644 index d72b8dde375..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-011.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-011.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-012.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-012.xht.ini deleted file mode 100644 index 692d976ec99..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-012.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-012.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-018.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-018.xht.ini deleted file mode 100644 index 4e88c55df79..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-018.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-018.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-019.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-019.xht.ini deleted file mode 100644 index 615721a370e..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-019.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-019.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-025.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-025.xht.ini deleted file mode 100644 index 1833dcd8f20..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-025.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-025.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-026.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-026.xht.ini deleted file mode 100644 index 2de13eb97cf..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-026.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-026.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-032.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-032.xht.ini deleted file mode 100644 index a05b7ae9834..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-032.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-032.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-033.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-033.xht.ini deleted file mode 100644 index 42bd4bd5c87..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/positioning/absolute-replaced-height-033.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[absolute-replaced-height-033.xht] - expected: FAIL