mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
script: Manage <iframe>
sizes in Window
(#34643)
Manage `<iframe>` size updates in `Window`. In addition to removing duplicated code, this will allow setting `<iframe>` sizes synchronously on child `Pipeline`s of the same origin in the script process in a followup change. The goal is remove flakiness from `<iframe>` sizing. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
eb82161a8a
commit
3e052676ef
18 changed files with 165 additions and 200 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -6088,6 +6088,7 @@ dependencies = [
|
||||||
"canvas_traits",
|
"canvas_traits",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"euclid",
|
"euclid",
|
||||||
|
"fnv",
|
||||||
"fonts",
|
"fonts",
|
||||||
"fonts_traits",
|
"fonts_traits",
|
||||||
"html5ever",
|
"html5ever",
|
||||||
|
|
|
@ -1865,6 +1865,7 @@ where
|
||||||
pipeline.title = title;
|
pipeline.title = title;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
FromScriptMsg::IFrameSizes(iframe_sizes) => self.handle_iframe_size_msg(iframe_sizes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2138,11 +2139,6 @@ where
|
||||||
fn handle_request_from_layout(&mut self, message: FromLayoutMsg) {
|
fn handle_request_from_layout(&mut self, message: FromLayoutMsg) {
|
||||||
trace_layout_msg!(message, "{message:?}");
|
trace_layout_msg!(message, "{message:?}");
|
||||||
match message {
|
match message {
|
||||||
// Layout sends new sizes for all subframes. This needs to be reflected by all
|
|
||||||
// frame trees in the navigation context containing the subframe.
|
|
||||||
FromLayoutMsg::IFrameSizes(iframe_sizes) => {
|
|
||||||
self.handle_iframe_size_msg(iframe_sizes);
|
|
||||||
},
|
|
||||||
FromLayoutMsg::PendingPaintMetric(pipeline_id, epoch) => {
|
FromLayoutMsg::PendingPaintMetric(pipeline_id, epoch) => {
|
||||||
self.handle_pending_paint_metric(pipeline_id, epoch);
|
self.handle_pending_paint_metric(pipeline_id, epoch);
|
||||||
},
|
},
|
||||||
|
|
|
@ -189,6 +189,7 @@ mod from_script {
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
Self::GetWebGPUChan(..) => target!("GetWebGPUChan"),
|
Self::GetWebGPUChan(..) => target!("GetWebGPUChan"),
|
||||||
Self::TitleChanged(..) => target!("TitleChanged"),
|
Self::TitleChanged(..) => target!("TitleChanged"),
|
||||||
|
Self::IFrameSizes(..) => target!("IFrameSizes"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,7 +258,6 @@ mod from_layout {
|
||||||
impl LogTarget for script_traits::LayoutMsg {
|
impl LogTarget for script_traits::LayoutMsg {
|
||||||
fn log_target(&self) -> &'static str {
|
fn log_target(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::IFrameSizes(..) => target!("IFrameSizes"),
|
|
||||||
Self::PendingPaintMetric(..) => target!("PendingPaintMetric"),
|
Self::PendingPaintMetric(..) => target!("PendingPaintMetric"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::sync::Arc;
|
||||||
use std::{f32, mem};
|
use std::{f32, mem};
|
||||||
|
|
||||||
use app_units::{Au, AU_PER_PX};
|
use app_units::{Au, AU_PER_PX};
|
||||||
use base::id::{BrowsingContextId, PipelineId};
|
use base::id::PipelineId;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg};
|
use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg};
|
||||||
use embedder_traits::Cursor;
|
use embedder_traits::Cursor;
|
||||||
|
@ -25,7 +25,9 @@ use ipc_channel::ipc;
|
||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
use net_traits::image_cache::UsePlaceholder;
|
use net_traits::image_cache::UsePlaceholder;
|
||||||
use range::Range;
|
use range::Range;
|
||||||
use script_layout_interface::{combine_id_with_fragment_type, FragmentType};
|
use script_layout_interface::{
|
||||||
|
combine_id_with_fragment_type, FragmentType, IFrameSize, IFrameSizes,
|
||||||
|
};
|
||||||
use servo_config::opts;
|
use servo_config::opts;
|
||||||
use servo_geometry::{self, MaxRect};
|
use servo_geometry::{self, MaxRect};
|
||||||
use style::color::AbsoluteColor;
|
use style::color::AbsoluteColor;
|
||||||
|
@ -43,7 +45,7 @@ use style::values::computed::{ClipRectOrAuto, Gradient};
|
||||||
use style::values::generics::background::BackgroundSize;
|
use style::values::generics::background::BackgroundSize;
|
||||||
use style::values::generics::image::PaintWorklet;
|
use style::values::generics::image::PaintWorklet;
|
||||||
use style::values::specified::ui::CursorKind;
|
use style::values::specified::ui::CursorKind;
|
||||||
use style_traits::{CSSPixel, ToCss};
|
use style_traits::ToCss;
|
||||||
use webrender_api::units::{LayoutRect, LayoutTransform, LayoutVector2D};
|
use webrender_api::units::{LayoutRect, LayoutTransform, LayoutVector2D};
|
||||||
use webrender_api::{
|
use webrender_api::{
|
||||||
self, BorderDetails, BorderRadius, BorderSide, BoxShadowClipMode, ColorF, ColorU,
|
self, BorderDetails, BorderRadius, BorderSide, BoxShadowClipMode, ColorF, ColorU,
|
||||||
|
@ -327,7 +329,7 @@ pub struct DisplayListBuildState<'a> {
|
||||||
|
|
||||||
/// Vector containing iframe sizes, used to inform the constellation about
|
/// Vector containing iframe sizes, used to inform the constellation about
|
||||||
/// new iframe sizes
|
/// new iframe sizes
|
||||||
pub iframe_sizes: FnvHashMap<BrowsingContextId, euclid::Size2D<f32, CSSPixel>>,
|
pub iframe_sizes: IFrameSizes,
|
||||||
|
|
||||||
/// Stores text runs to answer text queries used to place a cursor inside text.
|
/// Stores text runs to answer text queries used to place a cursor inside text.
|
||||||
pub indexable_text: IndexableText,
|
pub indexable_text: IndexableText,
|
||||||
|
@ -1872,19 +1874,25 @@ impl Fragment {
|
||||||
},
|
},
|
||||||
SpecificFragmentInfo::Iframe(ref fragment_info) => {
|
SpecificFragmentInfo::Iframe(ref fragment_info) => {
|
||||||
if !stacking_relative_content_box.is_empty() {
|
if !stacking_relative_content_box.is_empty() {
|
||||||
let browsing_context_id = match fragment_info.browsing_context_id {
|
let Some(browsing_context_id) = fragment_info.browsing_context_id else {
|
||||||
Some(browsing_context_id) => browsing_context_id,
|
return warn!("No browsing context id for iframe.");
|
||||||
None => return warn!("No browsing context id for iframe."),
|
};
|
||||||
|
let Some(pipeline_id) = fragment_info.pipeline_id else {
|
||||||
|
return warn!("No pipeline id for iframe.");
|
||||||
};
|
};
|
||||||
|
|
||||||
let base = create_base_display_item(state);
|
let base = create_base_display_item(state);
|
||||||
let bounds = stacking_relative_content_box.to_layout();
|
let bounds = stacking_relative_content_box.to_layout();
|
||||||
|
|
||||||
// XXXjdm: This sleight-of-hand to convert LayoutRect -> Size2D<CSSPixel>
|
|
||||||
// looks bogus.
|
|
||||||
state.iframe_sizes.insert(
|
state.iframe_sizes.insert(
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
euclid::Size2D::new(bounds.size().width, bounds.size().height),
|
IFrameSize {
|
||||||
|
browsing_context_id,
|
||||||
|
pipeline_id,
|
||||||
|
// XXXjdm: This sleight-of-hand to convert LayoutRect -> Size2D<CSSPixel>
|
||||||
|
// looks bogus.
|
||||||
|
size: euclid::Size2D::new(bounds.size().width, bounds.size().height),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let pipeline_id = match fragment_info.pipeline_id {
|
let pipeline_id = match fragment_info.pipeline_id {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use net_traits::image_cache::{
|
||||||
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, UsePlaceholder,
|
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, UsePlaceholder,
|
||||||
};
|
};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use script_layout_interface::{PendingImage, PendingImageState};
|
use script_layout_interface::{IFrameSizes, PendingImage, PendingImageState};
|
||||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||||
use style::context::SharedStyleContext;
|
use style::context::SharedStyleContext;
|
||||||
use style::dom::OpaqueNode;
|
use style::dom::OpaqueNode;
|
||||||
|
@ -35,6 +35,9 @@ pub struct LayoutContext<'a> {
|
||||||
/// A list of in-progress image loads to be shared with the script thread.
|
/// A list of in-progress image loads to be shared with the script thread.
|
||||||
pub pending_images: Mutex<Vec<PendingImage>>,
|
pub pending_images: Mutex<Vec<PendingImage>>,
|
||||||
|
|
||||||
|
/// A collection of `<iframe>` sizes to send back to script.
|
||||||
|
pub iframe_sizes: Mutex<IFrameSizes>,
|
||||||
|
|
||||||
pub webrender_image_cache:
|
pub webrender_image_cache:
|
||||||
Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo>>>,
|
Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo>>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,9 @@ use std::cell::{OnceCell, RefCell};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use base::id::BrowsingContextId;
|
|
||||||
use base::WebRenderEpochToU16;
|
use base::WebRenderEpochToU16;
|
||||||
use embedder_traits::Cursor;
|
use embedder_traits::Cursor;
|
||||||
use euclid::{Point2D, SideOffsets2D, Size2D, UnknownUnit};
|
use euclid::{Point2D, SideOffsets2D, Size2D, UnknownUnit};
|
||||||
use fnv::FnvHashMap;
|
|
||||||
use fonts::GlyphStore;
|
use fonts::GlyphStore;
|
||||||
use gradient::WebRenderGradient;
|
use gradient::WebRenderGradient;
|
||||||
use net_traits::image_cache::UsePlaceholder;
|
use net_traits::image_cache::UsePlaceholder;
|
||||||
|
@ -32,7 +30,6 @@ use style::values::generics::NonNegative;
|
||||||
use style::values::specified::text::TextDecorationLine;
|
use style::values::specified::text::TextDecorationLine;
|
||||||
use style::values::specified::ui::CursorKind;
|
use style::values::specified::ui::CursorKind;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
use style_traits::CSSPixel;
|
|
||||||
use webrender_api::units::{DevicePixel, LayoutPixel, LayoutRect, LayoutSize};
|
use webrender_api::units::{DevicePixel, LayoutPixel, LayoutRect, LayoutSize};
|
||||||
use webrender_api::{
|
use webrender_api::{
|
||||||
self as wr, units, BorderDetails, BoxShadowClipMode, ClipChainId, CommonItemProperties,
|
self as wr, units, BorderDetails, BoxShadowClipMode, ClipChainId, CommonItemProperties,
|
||||||
|
@ -162,12 +159,6 @@ pub(crate) struct DisplayListBuilder<'a> {
|
||||||
/// The [DisplayList] used to collect display list items and metadata.
|
/// The [DisplayList] used to collect display list items and metadata.
|
||||||
pub display_list: &'a mut DisplayList,
|
pub display_list: &'a mut DisplayList,
|
||||||
|
|
||||||
/// A recording of the sizes of iframes encountered when building this
|
|
||||||
/// display list. This information is forwarded to layout for the
|
|
||||||
/// iframe so that its layout knows how large the initial containing block /
|
|
||||||
/// viewport is.
|
|
||||||
iframe_sizes: FnvHashMap<BrowsingContextId, Size2D<f32, CSSPixel>>,
|
|
||||||
|
|
||||||
/// Contentful paint i.e. whether the display list contains items of type
|
/// Contentful paint i.e. whether the display list contains items of type
|
||||||
/// text, image, non-white canvas or SVG). Used by metrics.
|
/// text, image, non-white canvas or SVG). Used by metrics.
|
||||||
/// See <https://w3c.github.io/paint-timing/#first-contentful-paint>.
|
/// See <https://w3c.github.io/paint-timing/#first-contentful-paint>.
|
||||||
|
@ -175,12 +166,13 @@ pub(crate) struct DisplayListBuilder<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayList {
|
impl DisplayList {
|
||||||
|
/// Build the display list, returning true if it was contentful.
|
||||||
pub fn build(
|
pub fn build(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: &LayoutContext,
|
context: &LayoutContext,
|
||||||
fragment_tree: &FragmentTree,
|
fragment_tree: &FragmentTree,
|
||||||
root_stacking_context: &StackingContext,
|
root_stacking_context: &StackingContext,
|
||||||
) -> (FnvHashMap<BrowsingContextId, Size2D<f32, CSSPixel>>, bool) {
|
) -> bool {
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let _span = tracing::trace_span!("display_list::build", servo_profiling = true).entered();
|
let _span = tracing::trace_span!("display_list::build", servo_profiling = true).entered();
|
||||||
let mut builder = DisplayListBuilder {
|
let mut builder = DisplayListBuilder {
|
||||||
|
@ -191,10 +183,9 @@ impl DisplayList {
|
||||||
is_contentful: false,
|
is_contentful: false,
|
||||||
context,
|
context,
|
||||||
display_list: self,
|
display_list: self,
|
||||||
iframe_sizes: FnvHashMap::default(),
|
|
||||||
};
|
};
|
||||||
fragment_tree.build_display_list(&mut builder, root_stacking_context);
|
fragment_tree.build_display_list(&mut builder, root_stacking_context);
|
||||||
(builder.iframe_sizes, builder.is_contentful)
|
builder.is_contentful
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,11 +309,6 @@ impl Fragment {
|
||||||
builder.is_contentful = true;
|
builder.is_contentful = true;
|
||||||
let rect = iframe.rect.translate(containing_block.origin.to_vector());
|
let rect = iframe.rect.translate(containing_block.origin.to_vector());
|
||||||
|
|
||||||
builder.iframe_sizes.insert(
|
|
||||||
iframe.browsing_context_id,
|
|
||||||
Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()),
|
|
||||||
);
|
|
||||||
|
|
||||||
let common = builder.common_properties(rect.to_webrender(), &iframe.style);
|
let common = builder.common_properties(rect.to_webrender(), &iframe.style);
|
||||||
builder.wr().push_iframe(
|
builder.wr().push_iframe(
|
||||||
rect.to_webrender(),
|
rect.to_webrender(),
|
||||||
|
|
|
@ -1987,8 +1987,11 @@ impl FlexItem<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let fragments = replaced
|
let fragments = replaced.make_fragments(
|
||||||
.make_fragments(item_style, size.to_physical_size(container_writing_mode));
|
flex_context.layout_context,
|
||||||
|
item_style,
|
||||||
|
size.to_physical_size(container_writing_mode),
|
||||||
|
);
|
||||||
|
|
||||||
Some(FlexItemLayoutResult {
|
Some(FlexItemLayoutResult {
|
||||||
hypothetical_cross_size,
|
hypothetical_cross_size,
|
||||||
|
|
|
@ -1399,6 +1399,7 @@ impl ReplacedContents {
|
||||||
fn layout_in_flow_block_level(
|
fn layout_in_flow_block_level(
|
||||||
&self,
|
&self,
|
||||||
base: &LayoutBoxBase,
|
base: &LayoutBoxBase,
|
||||||
|
layout_context: &LayoutContext,
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
|
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
|
||||||
) -> BoxFragment {
|
) -> BoxFragment {
|
||||||
|
@ -1420,7 +1421,7 @@ impl ReplacedContents {
|
||||||
|
|
||||||
let containing_block_writing_mode = containing_block.style.writing_mode;
|
let containing_block_writing_mode = containing_block.style.writing_mode;
|
||||||
let physical_content_size = content_size.to_physical_size(containing_block_writing_mode);
|
let physical_content_size = content_size.to_physical_size(containing_block_writing_mode);
|
||||||
let fragments = self.make_fragments(&base.style, physical_content_size);
|
let fragments = self.make_fragments(layout_context, &base.style, physical_content_size);
|
||||||
|
|
||||||
let clearance;
|
let clearance;
|
||||||
if let Some(ref mut sequential_layout_state) = sequential_layout_state {
|
if let Some(ref mut sequential_layout_state) = sequential_layout_state {
|
||||||
|
@ -2071,7 +2072,12 @@ impl IndependentFormattingContext {
|
||||||
sequential_layout_state,
|
sequential_layout_state,
|
||||||
),
|
),
|
||||||
IndependentFormattingContextContents::Replaced(contents) => contents
|
IndependentFormattingContextContents::Replaced(contents) => contents
|
||||||
.layout_in_flow_block_level(&self.base, containing_block, sequential_layout_state),
|
.layout_in_flow_block_level(
|
||||||
|
&self.base,
|
||||||
|
layout_context,
|
||||||
|
containing_block,
|
||||||
|
sequential_layout_state,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(crate) fn layout_float_or_atomic_inline(
|
pub(crate) fn layout_float_or_atomic_inline(
|
||||||
|
@ -2099,7 +2105,7 @@ impl IndependentFormattingContext {
|
||||||
&content_box_sizes_and_pbm,
|
&content_box_sizes_and_pbm,
|
||||||
)
|
)
|
||||||
.to_physical_size(container_writing_mode);
|
.to_physical_size(container_writing_mode);
|
||||||
let fragments = replaced.make_fragments(style, content_size);
|
let fragments = replaced.make_fragments(layout_context, style, content_size);
|
||||||
|
|
||||||
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
|
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
|
||||||
(fragments, content_rect, None)
|
(fragments, content_rect, None)
|
||||||
|
|
|
@ -572,6 +572,7 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
block: block_axis.size.to_definite().unwrap(),
|
block: block_axis.size.to_definite().unwrap(),
|
||||||
};
|
};
|
||||||
fragments = replaced.make_fragments(
|
fragments = replaced.make_fragments(
|
||||||
|
layout_context,
|
||||||
&style,
|
&style,
|
||||||
content_size.to_physical_size(containing_block_writing_mode),
|
content_size.to_physical_size(containing_block_writing_mode),
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,9 +10,11 @@ use app_units::Au;
|
||||||
use base::id::{BrowsingContextId, PipelineId};
|
use base::id::{BrowsingContextId, PipelineId};
|
||||||
use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg};
|
use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg};
|
||||||
use data_url::DataUrl;
|
use data_url::DataUrl;
|
||||||
|
use euclid::Size2D;
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
|
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
|
||||||
use pixels::Image;
|
use pixels::Image;
|
||||||
|
use script_layout_interface::IFrameSize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use style::computed_values::object_fit::T as ObjectFit;
|
use style::computed_values::object_fit::T as ObjectFit;
|
||||||
|
@ -280,6 +282,7 @@ impl ReplacedContents {
|
||||||
|
|
||||||
pub fn make_fragments(
|
pub fn make_fragments(
|
||||||
&self,
|
&self,
|
||||||
|
layout_context: &LayoutContext,
|
||||||
style: &ServoArc<ComputedValues>,
|
style: &ServoArc<ComputedValues>,
|
||||||
size: PhysicalSize<Au>,
|
size: PhysicalSize<Au>,
|
||||||
) -> Vec<Fragment> {
|
) -> Vec<Fragment> {
|
||||||
|
@ -349,6 +352,15 @@ impl ReplacedContents {
|
||||||
image_key: video.as_ref().map(|video| video.image_key),
|
image_key: video.as_ref().map(|video| video.image_key),
|
||||||
})],
|
})],
|
||||||
ReplacedContentKind::IFrame(iframe) => {
|
ReplacedContentKind::IFrame(iframe) => {
|
||||||
|
let size = Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px());
|
||||||
|
layout_context.iframe_sizes.lock().insert(
|
||||||
|
iframe.browsing_context_id,
|
||||||
|
IFrameSize {
|
||||||
|
browsing_context_id: iframe.browsing_context_id,
|
||||||
|
pipeline_id: iframe.pipeline_id,
|
||||||
|
size,
|
||||||
|
},
|
||||||
|
);
|
||||||
vec![Fragment::IFrame(IFrameFragment {
|
vec![Fragment::IFrame(IFrameFragment {
|
||||||
base: self.base_fragment_info.into(),
|
base: self.base_fragment_info.into(),
|
||||||
style: style.clone(),
|
style: style.clone(),
|
||||||
|
|
|
@ -174,8 +174,11 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
|
||||||
// Create fragments if the RunMode if PerformLayout
|
// Create fragments if the RunMode if PerformLayout
|
||||||
// If the RunMode is ComputeSize then only the returned size will be used
|
// If the RunMode is ComputeSize then only the returned size will be used
|
||||||
if inputs.run_mode == RunMode::PerformLayout {
|
if inputs.run_mode == RunMode::PerformLayout {
|
||||||
child.child_fragments =
|
child.child_fragments = replaced.make_fragments(
|
||||||
replaced.make_fragments(style, content_box_size);
|
self.layout_context,
|
||||||
|
style,
|
||||||
|
content_box_size,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let computed_size = taffy::Size {
|
let computed_size = taffy::Size {
|
||||||
|
|
|
@ -15,7 +15,7 @@ use std::sync::{Arc, LazyLock, Mutex};
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use base::cross_process_instant::CrossProcessInstant;
|
use base::cross_process_instant::CrossProcessInstant;
|
||||||
use base::id::{BrowsingContextId, PipelineId};
|
use base::id::PipelineId;
|
||||||
use base::Epoch;
|
use base::Epoch;
|
||||||
use embedder_traits::resources::{self, Resource};
|
use embedder_traits::resources::{self, Resource};
|
||||||
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
|
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
|
||||||
|
@ -47,7 +47,7 @@ use layout::traversal::{
|
||||||
};
|
};
|
||||||
use layout::wrapper::ThreadSafeLayoutNodeHelpers;
|
use layout::wrapper::ThreadSafeLayoutNodeHelpers;
|
||||||
use layout::{layout_debug, layout_debug_scope, parallel, sequential};
|
use layout::{layout_debug, layout_debug_scope, parallel, sequential};
|
||||||
use log::{debug, error, trace, warn};
|
use log::{debug, error, trace};
|
||||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||||
use metrics::{PaintTimeMetrics, ProfilerMetadataFactory};
|
use metrics::{PaintTimeMetrics, ProfilerMetadataFactory};
|
||||||
use net_traits::image_cache::{ImageCache, UsePlaceholder};
|
use net_traits::image_cache::{ImageCache, UsePlaceholder};
|
||||||
|
@ -61,12 +61,12 @@ use profile_traits::{path, time_profile};
|
||||||
use script::layout_dom::{ServoLayoutElement, ServoLayoutNode};
|
use script::layout_dom::{ServoLayoutElement, ServoLayoutNode};
|
||||||
use script_layout_interface::wrapper_traits::LayoutNode;
|
use script_layout_interface::wrapper_traits::LayoutNode;
|
||||||
use script_layout_interface::{
|
use script_layout_interface::{
|
||||||
Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, Reflow,
|
IFrameSizes, Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType,
|
||||||
ReflowGoal, ReflowRequest, ReflowResult, TrustedNodeAddress,
|
OffsetParentResponse, Reflow, ReflowGoal, ReflowRequest, ReflowResult, TrustedNodeAddress,
|
||||||
};
|
};
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutMsg as ConstellationMsg,
|
ConstellationControlMsg, DrawAPaintImageResult, PaintWorkletError, Painter, ScrollState,
|
||||||
PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress, WindowSizeData, WindowSizeType,
|
UntrustedNodeAddress, WindowSizeData,
|
||||||
};
|
};
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
|
@ -130,9 +130,6 @@ pub struct LayoutThread {
|
||||||
/// Is the current reflow of an iframe, as opposed to a root window?
|
/// Is the current reflow of an iframe, as opposed to a root window?
|
||||||
is_iframe: bool,
|
is_iframe: bool,
|
||||||
|
|
||||||
/// The channel on which messages can be sent to the constellation.
|
|
||||||
constellation_chan: IpcSender<ConstellationMsg>,
|
|
||||||
|
|
||||||
/// The channel on which messages can be sent to the script thread.
|
/// The channel on which messages can be sent to the script thread.
|
||||||
script_chan: IpcSender<ConstellationControlMsg>,
|
script_chan: IpcSender<ConstellationControlMsg>,
|
||||||
|
|
||||||
|
@ -186,7 +183,7 @@ pub struct LayoutThread {
|
||||||
paint_time_metrics: PaintTimeMetrics,
|
paint_time_metrics: PaintTimeMetrics,
|
||||||
|
|
||||||
/// The sizes of all iframes encountered during the last layout operation.
|
/// The sizes of all iframes encountered during the last layout operation.
|
||||||
last_iframe_sizes: RefCell<FnvHashMap<BrowsingContextId, Size2D<f32, CSSPixel>>>,
|
last_iframe_sizes: RefCell<IFrameSizes>,
|
||||||
|
|
||||||
/// Debug options, copied from configuration to this `LayoutThread` in order
|
/// Debug options, copied from configuration to this `LayoutThread` in order
|
||||||
/// to avoid having to constantly access the thread-safe global options.
|
/// to avoid having to constantly access the thread-safe global options.
|
||||||
|
@ -204,7 +201,6 @@ impl LayoutFactory for LayoutFactoryImpl {
|
||||||
config.id,
|
config.id,
|
||||||
config.url,
|
config.url,
|
||||||
config.is_iframe,
|
config.is_iframe,
|
||||||
config.constellation_chan,
|
|
||||||
config.script_chan,
|
config.script_chan,
|
||||||
config.image_cache,
|
config.image_cache,
|
||||||
config.resource_threads,
|
config.resource_threads,
|
||||||
|
@ -306,16 +302,6 @@ impl Layout for LayoutThread {
|
||||||
get_the_text_steps(node, &self.indexable_text.borrow())
|
get_the_text_steps(node, &self.indexable_text.borrow())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_inner_window_dimension(
|
|
||||||
&self,
|
|
||||||
browsing_context_id: BrowsingContextId,
|
|
||||||
) -> Option<Size2D<f32, CSSPixel>> {
|
|
||||||
self.last_iframe_sizes
|
|
||||||
.borrow()
|
|
||||||
.get(&browsing_context_id)
|
|
||||||
.cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_nodes_from_point(
|
fn query_nodes_from_point(
|
||||||
&self,
|
&self,
|
||||||
point: UntypedPoint2D<f32>,
|
point: UntypedPoint2D<f32>,
|
||||||
|
@ -529,7 +515,6 @@ impl LayoutThread {
|
||||||
id: PipelineId,
|
id: PipelineId,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
is_iframe: bool,
|
is_iframe: bool,
|
||||||
constellation_chan: IpcSender<ConstellationMsg>,
|
|
||||||
script_chan: IpcSender<ConstellationControlMsg>,
|
script_chan: IpcSender<ConstellationControlMsg>,
|
||||||
image_cache: Arc<dyn ImageCache>,
|
image_cache: Arc<dyn ImageCache>,
|
||||||
resource_threads: ResourceThreads,
|
resource_threads: ResourceThreads,
|
||||||
|
@ -571,7 +556,6 @@ impl LayoutThread {
|
||||||
url,
|
url,
|
||||||
is_iframe,
|
is_iframe,
|
||||||
script_chan,
|
script_chan,
|
||||||
constellation_chan,
|
|
||||||
time_profiler_chan,
|
time_profiler_chan,
|
||||||
registered_painters: RegisteredPaintersImpl(Default::default()),
|
registered_painters: RegisteredPaintersImpl(Default::default()),
|
||||||
image_cache,
|
image_cache,
|
||||||
|
@ -755,48 +739,6 @@ impl LayoutThread {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the recorded iframe sizes of the contents of layout 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<BrowsingContextId, Size2D<f32, CSSPixel>>,
|
|
||||||
) {
|
|
||||||
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
|
/// Computes the stacking-relative positions of all flows and, if the painting is dirty and the
|
||||||
/// reflow type need it, builds the display list.
|
/// reflow type need it, builds the display list.
|
||||||
fn compute_abs_pos_and_build_display_list(
|
fn compute_abs_pos_and_build_display_list(
|
||||||
|
@ -850,8 +792,8 @@ impl LayoutThread {
|
||||||
build_state.root_stacking_context.overflow = origin;
|
build_state.root_stacking_context.overflow = origin;
|
||||||
|
|
||||||
// We will not use build_state.iframe_sizes again, so it's safe to move it.
|
// We will not use build_state.iframe_sizes again, so it's safe to move it.
|
||||||
let iframe_sizes = std::mem::take(&mut build_state.iframe_sizes);
|
*self.last_iframe_sizes.borrow_mut() =
|
||||||
self.update_iframe_sizes(iframe_sizes);
|
std::mem::take(&mut build_state.iframe_sizes);
|
||||||
|
|
||||||
*self.indexable_text.borrow_mut() =
|
*self.indexable_text.borrow_mut() =
|
||||||
std::mem::take(&mut build_state.indexable_text);
|
std::mem::take(&mut build_state.indexable_text);
|
||||||
|
@ -1130,7 +1072,10 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
let pending_images = std::mem::take(&mut *layout_context.pending_images.lock().unwrap());
|
let pending_images = std::mem::take(&mut *layout_context.pending_images.lock().unwrap());
|
||||||
Some(ReflowResult { pending_images })
|
Some(ReflowResult {
|
||||||
|
pending_images,
|
||||||
|
iframe_sizes: self.last_iframe_sizes.borrow().clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_scroll_node_state(&self, state: &ScrollState) {
|
fn update_scroll_node_state(&self, state: &ScrollState) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ use std::sync::{Arc, LazyLock};
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use base::cross_process_instant::CrossProcessInstant;
|
use base::cross_process_instant::CrossProcessInstant;
|
||||||
use base::id::{BrowsingContextId, PipelineId};
|
use base::id::PipelineId;
|
||||||
use base::Epoch;
|
use base::Epoch;
|
||||||
use embedder_traits::resources::{self, Resource};
|
use embedder_traits::resources::{self, Resource};
|
||||||
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
|
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
|
||||||
|
@ -35,7 +35,7 @@ use layout::query::{
|
||||||
};
|
};
|
||||||
use layout::traversal::RecalcStyle;
|
use layout::traversal::RecalcStyle;
|
||||||
use layout::{layout_debug, BoxTree, FragmentTree};
|
use layout::{layout_debug, BoxTree, FragmentTree};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error};
|
||||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||||
use metrics::{PaintTimeMetrics, ProfilerMetadataFactory};
|
use metrics::{PaintTimeMetrics, ProfilerMetadataFactory};
|
||||||
use net_traits::image_cache::{ImageCache, UsePlaceholder};
|
use net_traits::image_cache::{ImageCache, UsePlaceholder};
|
||||||
|
@ -52,8 +52,8 @@ use script_layout_interface::{
|
||||||
ReflowRequest, ReflowResult, TrustedNodeAddress,
|
ReflowRequest, ReflowResult, TrustedNodeAddress,
|
||||||
};
|
};
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutMsg as ConstellationMsg,
|
ConstellationControlMsg, DrawAPaintImageResult, PaintWorkletError, Painter, ScrollState,
|
||||||
PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress, WindowSizeData, WindowSizeType,
|
UntrustedNodeAddress, WindowSizeData,
|
||||||
};
|
};
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
|
@ -115,9 +115,6 @@ pub struct LayoutThread {
|
||||||
/// Is the current reflow of an iframe, as opposed to a root window?
|
/// Is the current reflow of an iframe, as opposed to a root window?
|
||||||
is_iframe: bool,
|
is_iframe: bool,
|
||||||
|
|
||||||
/// The channel on which messages can be sent to the constellation.
|
|
||||||
constellation_chan: IpcSender<ConstellationMsg>,
|
|
||||||
|
|
||||||
/// The channel on which messages can be sent to the script thread.
|
/// The channel on which messages can be sent to the script thread.
|
||||||
script_chan: IpcSender<ConstellationControlMsg>,
|
script_chan: IpcSender<ConstellationControlMsg>,
|
||||||
|
|
||||||
|
@ -164,9 +161,6 @@ pub struct LayoutThread {
|
||||||
/// Paint time metrics.
|
/// Paint time metrics.
|
||||||
paint_time_metrics: PaintTimeMetrics,
|
paint_time_metrics: PaintTimeMetrics,
|
||||||
|
|
||||||
/// The sizes of all iframes encountered during the last layout operation.
|
|
||||||
last_iframe_sizes: RefCell<FnvHashMap<BrowsingContextId, Size2D<f32, CSSPixel>>>,
|
|
||||||
|
|
||||||
/// Debug options, copied from configuration to this `LayoutThread` in order
|
/// Debug options, copied from configuration to this `LayoutThread` in order
|
||||||
/// to avoid having to constantly access the thread-safe global options.
|
/// to avoid having to constantly access the thread-safe global options.
|
||||||
debug: DebugOptions,
|
debug: DebugOptions,
|
||||||
|
@ -180,7 +174,6 @@ impl LayoutFactory for LayoutFactoryImpl {
|
||||||
config.id,
|
config.id,
|
||||||
config.url,
|
config.url,
|
||||||
config.is_iframe,
|
config.is_iframe,
|
||||||
config.constellation_chan,
|
|
||||||
config.script_chan,
|
config.script_chan,
|
||||||
config.image_cache,
|
config.image_cache,
|
||||||
config.resource_threads,
|
config.resource_threads,
|
||||||
|
@ -295,15 +288,6 @@ impl Layout for LayoutThread {
|
||||||
get_the_text_steps(node)
|
get_the_text_steps(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_inner_window_dimension(
|
|
||||||
&self,
|
|
||||||
_context: BrowsingContextId,
|
|
||||||
) -> Option<Size2D<f32, CSSPixel>> {
|
|
||||||
// TODO(jdm): port the iframe sizing code from layout2013's display
|
|
||||||
// builder in order to support query iframe sizing.
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "tracing",
|
feature = "tracing",
|
||||||
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
|
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
|
||||||
|
@ -505,7 +489,6 @@ impl LayoutThread {
|
||||||
id: PipelineId,
|
id: PipelineId,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
is_iframe: bool,
|
is_iframe: bool,
|
||||||
constellation_chan: IpcSender<ConstellationMsg>,
|
|
||||||
script_chan: IpcSender<ConstellationControlMsg>,
|
script_chan: IpcSender<ConstellationControlMsg>,
|
||||||
image_cache: Arc<dyn ImageCache>,
|
image_cache: Arc<dyn ImageCache>,
|
||||||
resource_threads: ResourceThreads,
|
resource_threads: ResourceThreads,
|
||||||
|
@ -548,7 +531,6 @@ impl LayoutThread {
|
||||||
id,
|
id,
|
||||||
url,
|
url,
|
||||||
is_iframe,
|
is_iframe,
|
||||||
constellation_chan,
|
|
||||||
script_chan: script_chan.clone(),
|
script_chan: script_chan.clone(),
|
||||||
time_profiler_chan,
|
time_profiler_chan,
|
||||||
registered_painters: RegisteredPaintersImpl(Default::default()),
|
registered_painters: RegisteredPaintersImpl(Default::default()),
|
||||||
|
@ -569,7 +551,6 @@ impl LayoutThread {
|
||||||
stylist: Stylist::new(device, QuirksMode::NoQuirks),
|
stylist: Stylist::new(device, QuirksMode::NoQuirks),
|
||||||
webrender_image_cache: Default::default(),
|
webrender_image_cache: Default::default(),
|
||||||
paint_time_metrics,
|
paint_time_metrics,
|
||||||
last_iframe_sizes: Default::default(),
|
|
||||||
debug: opts::get().debug.clone(),
|
debug: opts::get().debug.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -623,7 +604,8 @@ impl LayoutThread {
|
||||||
image_cache: self.image_cache.clone(),
|
image_cache: self.image_cache.clone(),
|
||||||
font_context: self.font_context.clone(),
|
font_context: self.font_context.clone(),
|
||||||
webrender_image_cache: self.webrender_image_cache.clone(),
|
webrender_image_cache: self.webrender_image_cache.clone(),
|
||||||
pending_images: Mutex::new(vec![]),
|
pending_images: Mutex::default(),
|
||||||
|
iframe_sizes: Mutex::default(),
|
||||||
use_rayon,
|
use_rayon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -867,7 +849,11 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
let pending_images = std::mem::take(&mut *layout_context.pending_images.lock());
|
let pending_images = std::mem::take(&mut *layout_context.pending_images.lock());
|
||||||
Some(ReflowResult { pending_images })
|
let iframe_sizes = std::mem::take(&mut *layout_context.iframe_sizes.lock());
|
||||||
|
Some(ReflowResult {
|
||||||
|
pending_images,
|
||||||
|
iframe_sizes,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_scroll_node_state(&self, state: &ScrollState) {
|
fn update_scroll_node_state(&self, state: &ScrollState) {
|
||||||
|
@ -935,8 +921,7 @@ impl LayoutThread {
|
||||||
display_list.build_stacking_context_tree(&fragment_tree, &self.debug);
|
display_list.build_stacking_context_tree(&fragment_tree, &self.debug);
|
||||||
|
|
||||||
// Build the rest of the display list which inclues all of the WebRender primitives.
|
// Build the rest of the display list which inclues all of the WebRender primitives.
|
||||||
let (iframe_sizes, is_contentful) =
|
let is_contentful = display_list.build(context, &fragment_tree, &root_stacking_context);
|
||||||
display_list.build(context, &fragment_tree, &root_stacking_context);
|
|
||||||
|
|
||||||
if self.debug.dump_flow_tree {
|
if self.debug.dump_flow_tree {
|
||||||
fragment_tree.print();
|
fragment_tree.print();
|
||||||
|
@ -963,8 +948,6 @@ impl LayoutThread {
|
||||||
.remove_unused_font_resources(keys, instance_keys)
|
.remove_unused_font_resources(keys, instance_keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_iframe_sizes(iframe_sizes);
|
|
||||||
|
|
||||||
if self.debug.trace_layout {
|
if self.debug.trace_layout {
|
||||||
layout_debug::end_trace(self.generation.get());
|
layout_debug::end_trace(self.generation.get());
|
||||||
}
|
}
|
||||||
|
@ -1009,48 +992,6 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the recorded iframe sizes of the contents of layout 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<BrowsingContextId, Size2D<f32, CSSPixel>>,
|
|
||||||
) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn viewport_did_change(&mut self, window_size_data: WindowSizeData) -> bool {
|
fn viewport_did_change(&mut self, window_size_data: WindowSizeData) -> bool {
|
||||||
let new_pixel_ratio = window_size_data.device_pixel_ratio.get();
|
let new_pixel_ratio = window_size_data.device_pixel_ratio.get();
|
||||||
let new_viewport_size = Size2D::new(
|
let new_viewport_size = Size2D::new(
|
||||||
|
|
|
@ -196,7 +196,7 @@ impl HTMLIFrameElement {
|
||||||
|
|
||||||
let window_size = WindowSizeData {
|
let window_size = WindowSizeData {
|
||||||
initial_viewport: window
|
initial_viewport: window
|
||||||
.inner_window_dimensions_query(browsing_context_id, can_gc)
|
.get_iframe_size_if_known(browsing_context_id, can_gc)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
device_pixel_ratio: window.device_pixel_ratio(),
|
device_pixel_ratio: window.device_pixel_ratio(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,14 +51,14 @@ use profile_traits::ipc as ProfiledIpc;
|
||||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||||
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||||||
use script_layout_interface::{
|
use script_layout_interface::{
|
||||||
combine_id_with_fragment_type, FragmentType, Layout, PendingImageState, QueryMsg, Reflow,
|
combine_id_with_fragment_type, FragmentType, IFrameSizes, Layout, PendingImageState, QueryMsg,
|
||||||
ReflowGoal, ReflowRequest, TrustedNodeAddress,
|
Reflow, ReflowGoal, ReflowRequest, TrustedNodeAddress,
|
||||||
};
|
};
|
||||||
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
ConstellationControlMsg, DocumentState, HistoryEntryReplacement, LoadData, ScriptMsg,
|
ConstellationControlMsg, DocumentState, HistoryEntryReplacement, IFrameSizeMsg, LoadData,
|
||||||
ScriptToConstellationChan, ScrollState, StructuredSerializedData, Theme, TimerSchedulerMsg,
|
ScriptMsg, ScriptToConstellationChan, ScrollState, StructuredSerializedData, Theme,
|
||||||
WindowSizeData, WindowSizeType,
|
TimerSchedulerMsg, WindowSizeData, WindowSizeType,
|
||||||
};
|
};
|
||||||
use selectors::attr::CaseSensitivity;
|
use selectors::attr::CaseSensitivity;
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
|
@ -377,6 +377,15 @@ pub struct Window {
|
||||||
|
|
||||||
/// <https://dom.spec.whatwg.org/#window-current-event>
|
/// <https://dom.spec.whatwg.org/#window-current-event>
|
||||||
current_event: DomRefCell<Option<Dom<Event>>>,
|
current_event: DomRefCell<Option<Dom<Event>>>,
|
||||||
|
|
||||||
|
/// Sizes of the various `<iframes>` that we might have on this [`Window`].
|
||||||
|
/// This is used to:
|
||||||
|
/// - Send the proper size for the `<iframe>` during new-Pipeline creation
|
||||||
|
/// when the `src` attribute changes.
|
||||||
|
/// - Let the `Constellation` know about `BrowsingContext` (one per `<iframe>`)
|
||||||
|
/// size changes when an `<iframe>` changes size during layout.
|
||||||
|
#[no_trace]
|
||||||
|
iframe_sizes: RefCell<IFrameSizes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
@ -1958,12 +1967,48 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.handle_new_iframe_sizes_after_layout(results.iframe_sizes);
|
||||||
|
|
||||||
document.update_animations_post_reflow();
|
document.update_animations_post_reflow();
|
||||||
self.update_constellation_epoch();
|
self.update_constellation_epoch();
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update the recorded iframe sizes of the contents of layout. When these sizes change,
|
||||||
|
/// send a message to the `Constellation` informing it of the new sizes.
|
||||||
|
fn handle_new_iframe_sizes_after_layout(&self, new_iframe_sizes: IFrameSizes) {
|
||||||
|
let old_iframe_sizes = self.iframe_sizes.replace(new_iframe_sizes);
|
||||||
|
let new_iframe_sizes = self.iframe_sizes.borrow();
|
||||||
|
if new_iframe_sizes.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send asynchronous updates to `Constellation.`
|
||||||
|
let size_messages: Vec<_> = new_iframe_sizes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(browsing_context_id, size)| {
|
||||||
|
match old_iframe_sizes.get(browsing_context_id) {
|
||||||
|
Some(old_size) if old_size.size == size.size => None,
|
||||||
|
Some(..) => Some(IFrameSizeMsg {
|
||||||
|
browsing_context_id: *browsing_context_id,
|
||||||
|
size: size.size,
|
||||||
|
type_: WindowSizeType::Resize,
|
||||||
|
}),
|
||||||
|
None => Some(IFrameSizeMsg {
|
||||||
|
browsing_context_id: *browsing_context_id,
|
||||||
|
size: size.size,
|
||||||
|
type_: WindowSizeType::Initial,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if !size_messages.is_empty() {
|
||||||
|
self.send_to_constellation(ScriptMsg::IFrameSizes(size_messages));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Reflows the page if it's possible to do so and the page is dirty. Returns true if layout
|
/// Reflows the page if it's possible to do so and the page is dirty. Returns true if layout
|
||||||
/// actually happened, false otherwise.
|
/// actually happened, false otherwise.
|
||||||
///
|
///
|
||||||
|
@ -2255,17 +2300,20 @@ impl Window {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner_window_dimensions_query(
|
/// If the given |browsing_context_id| refers to an `<iframe>` that is an element
|
||||||
|
/// in this [`Window`] and that `<iframe>` has been laid out, return its size.
|
||||||
|
/// Otherwise, return `None`.
|
||||||
|
pub(crate) fn get_iframe_size_if_known(
|
||||||
&self,
|
&self,
|
||||||
browsing_context: BrowsingContextId,
|
browsing_context_id: BrowsingContextId,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> Option<Size2D<f32, CSSPixel>> {
|
) -> Option<Size2D<f32, CSSPixel>> {
|
||||||
if !self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery, can_gc) {
|
// Reflow might fail, but do a best effort to return the right size.
|
||||||
return None;
|
self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery, can_gc);
|
||||||
}
|
self.iframe_sizes
|
||||||
self.layout
|
|
||||||
.borrow()
|
.borrow()
|
||||||
.query_inner_window_dimension(browsing_context)
|
.get(&browsing_context_id)
|
||||||
|
.map(|iframe_size| iframe_size.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -2800,6 +2848,7 @@ impl Window {
|
||||||
layout_marker: DomRefCell::new(Rc::new(Cell::new(true))),
|
layout_marker: DomRefCell::new(Rc::new(Cell::new(true))),
|
||||||
current_event: DomRefCell::new(None),
|
current_event: DomRefCell::new(None),
|
||||||
theme: Cell::new(PrefersColorScheme::Light),
|
theme: Cell::new(PrefersColorScheme::Light),
|
||||||
|
iframe_sizes: RefCell::default(),
|
||||||
});
|
});
|
||||||
|
|
||||||
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
|
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
|
||||||
|
|
|
@ -46,8 +46,6 @@ pub struct IFrameSizeMsg {
|
||||||
/// Messages from the layout to the constellation.
|
/// Messages from the layout to the constellation.
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum LayoutMsg {
|
pub enum LayoutMsg {
|
||||||
/// Inform the constellation of the size of the iframe's viewport.
|
|
||||||
IFrameSizes(Vec<IFrameSizeMsg>),
|
|
||||||
/// Requests that the constellation inform the compositor that it needs to record
|
/// Requests that the constellation inform the compositor that it needs to record
|
||||||
/// the time when the frame with the given ID (epoch) is painted.
|
/// the time when the frame with the given ID (epoch) is painted.
|
||||||
PendingPaintMetric(PipelineId, Epoch),
|
PendingPaintMetric(PipelineId, Epoch),
|
||||||
|
@ -57,7 +55,6 @@ impl fmt::Debug for LayoutMsg {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use self::LayoutMsg::*;
|
use self::LayoutMsg::*;
|
||||||
let variant = match *self {
|
let variant = match *self {
|
||||||
IFrameSizes(..) => "IFrameSizes",
|
|
||||||
PendingPaintMetric(..) => "PendingPaintMetric",
|
PendingPaintMetric(..) => "PendingPaintMetric",
|
||||||
};
|
};
|
||||||
write!(formatter, "LayoutMsg::{}", variant)
|
write!(formatter, "LayoutMsg::{}", variant)
|
||||||
|
@ -260,6 +257,8 @@ pub enum ScriptMsg {
|
||||||
GetWebGPUChan(IpcSender<Option<WebGPU>>),
|
GetWebGPUChan(IpcSender<Option<WebGPU>>),
|
||||||
/// Notify the constellation of a pipeline's document's title.
|
/// Notify the constellation of a pipeline's document's title.
|
||||||
TitleChanged(PipelineId, String),
|
TitleChanged(PipelineId, String),
|
||||||
|
/// Notify the constellation that the size of some `<iframe>`s has changed.
|
||||||
|
IFrameSizes(Vec<IFrameSizeMsg>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ScriptMsg {
|
impl fmt::Debug for ScriptMsg {
|
||||||
|
@ -320,6 +319,7 @@ impl fmt::Debug for ScriptMsg {
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
GetWebGPUChan(..) => "GetWebGPUChan",
|
GetWebGPUChan(..) => "GetWebGPUChan",
|
||||||
TitleChanged(..) => "TitleChanged",
|
TitleChanged(..) => "TitleChanged",
|
||||||
|
IFrameSizes(..) => "IFramSizes",
|
||||||
};
|
};
|
||||||
write!(formatter, "ScriptMsg::{}", variant)
|
write!(formatter, "ScriptMsg::{}", variant)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ atomic_refcell = { workspace = true }
|
||||||
canvas_traits = { workspace = true }
|
canvas_traits = { workspace = true }
|
||||||
crossbeam-channel = { workspace = true }
|
crossbeam-channel = { workspace = true }
|
||||||
euclid = { workspace = true }
|
euclid = { workspace = true }
|
||||||
|
fnv = { workspace = true }
|
||||||
fonts = { path = "../../fonts" }
|
fonts = { path = "../../fonts" }
|
||||||
fonts_traits = { workspace = true }
|
fonts_traits = { workspace = true }
|
||||||
html5ever = { workspace = true }
|
html5ever = { workspace = true }
|
||||||
|
|
|
@ -23,6 +23,7 @@ use base::Epoch;
|
||||||
use canvas_traits::canvas::{CanvasId, CanvasMsg};
|
use canvas_traits::canvas::{CanvasId, CanvasMsg};
|
||||||
use euclid::default::{Point2D, Rect};
|
use euclid::default::{Point2D, Rect};
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
|
use fnv::FnvHashMap;
|
||||||
use fonts::SystemFontServiceProxy;
|
use fonts::SystemFontServiceProxy;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
|
@ -257,10 +258,6 @@ pub trait Layout {
|
||||||
fn query_content_boxes(&self, node: OpaqueNode) -> Vec<Rect<Au>>;
|
fn query_content_boxes(&self, node: OpaqueNode) -> Vec<Rect<Au>>;
|
||||||
fn query_client_rect(&self, node: OpaqueNode) -> Rect<i32>;
|
fn query_client_rect(&self, node: OpaqueNode) -> Rect<i32>;
|
||||||
fn query_element_inner_outer_text(&self, node: TrustedNodeAddress) -> String;
|
fn query_element_inner_outer_text(&self, node: TrustedNodeAddress) -> String;
|
||||||
fn query_inner_window_dimension(
|
|
||||||
&self,
|
|
||||||
context: BrowsingContextId,
|
|
||||||
) -> Option<Size2D<f32, CSSPixel>>;
|
|
||||||
fn query_nodes_from_point(
|
fn query_nodes_from_point(
|
||||||
&self,
|
&self,
|
||||||
point: Point2D<f32>,
|
point: Point2D<f32>,
|
||||||
|
@ -400,11 +397,24 @@ pub struct Reflow {
|
||||||
pub page_clip_rect: Rect<Au>,
|
pub page_clip_rect: Rect<Au>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
|
pub struct IFrameSize {
|
||||||
|
pub browsing_context_id: BrowsingContextId,
|
||||||
|
pub pipeline_id: PipelineId,
|
||||||
|
pub size: Size2D<f32, CSSPixel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type IFrameSizes = FnvHashMap<BrowsingContextId, IFrameSize>;
|
||||||
|
|
||||||
/// Information derived from a layout pass that needs to be returned to the script thread.
|
/// Information derived from a layout pass that needs to be returned to the script thread.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ReflowResult {
|
pub struct ReflowResult {
|
||||||
/// The list of images that were encountered that are in progress.
|
/// The list of images that were encountered that are in progress.
|
||||||
pub pending_images: Vec<PendingImage>,
|
pub pending_images: Vec<PendingImage>,
|
||||||
|
/// The list of iframes in this layout and their sizes, used in order
|
||||||
|
/// to communicate them with the Constellation and also the `Window`
|
||||||
|
/// element of their content pages.
|
||||||
|
pub iframe_sizes: IFrameSizes,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information needed for a script-initiated reflow.
|
/// Information needed for a script-initiated reflow.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue