aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/devtools/actors/inspector.rs2
-rw-r--r--components/devtools/actors/inspector/highlighter.rs52
-rw-r--r--components/layout/context.rs3
-rw-r--r--components/layout/display_list/mod.rs212
-rw-r--r--components/layout/layout_impl.rs3
-rw-r--r--components/net/Cargo.toml1
-rw-r--r--components/net/image_cache.rs26
-rw-r--r--components/script/devtools.rs18
-rw-r--r--components/script/dom/document.rs11
-rw-r--r--components/script/dom/messageport.rs4
-rw-r--r--components/script/dom/window.rs3
-rw-r--r--components/script/script_thread.rs34
-rw-r--r--components/servo/tests/webview.rs14
-rw-r--r--components/shared/devtools/lib.rs2
-rw-r--r--components/shared/net/image_cache.rs6
-rw-r--r--components/shared/script_layout/lib.rs2
-rw-r--r--tests/wpt/meta/content-security-policy/generic/invalid-characters-in-policy.html.ini14
-rw-r--r--tests/wpt/meta/content-security-policy/generic/only-valid-whitespaces-are-allowed.html.ini47
-rw-r--r--tests/wpt/meta/content-security-policy/inheritance/history-iframe.sub.html.ini6
-rw-r--r--tests/wpt/meta/content-security-policy/inheritance/iframe-all-local-schemes.sub.html.ini12
-rw-r--r--tests/wpt/meta/content-security-policy/inheritance/iframe-srcdoc-inheritance.html.ini4
-rw-r--r--tests/wpt/meta/content-security-policy/inheritance/location-reload.html.ini3
-rw-r--r--tests/wpt/meta/css/css-backgrounds/background-image-shared-stylesheet.html.ini2
-rw-r--r--tests/wpt/meta/fetch/stale-while-revalidate/stale-image.html.ini3
-rw-r--r--tests/wpt/meta/quirks/line-height-calculation.html.ini3
-rw-r--r--tests/wpt/meta/quirks/table-cell-width-calculation.html.ini17
26 files changed, 394 insertions, 110 deletions
diff --git a/components/devtools/actors/inspector.rs b/components/devtools/actors/inspector.rs
index d41777f56c6..28a4d7ccf94 100644
--- a/components/devtools/actors/inspector.rs
+++ b/components/devtools/actors/inspector.rs
@@ -166,6 +166,8 @@ impl Actor for InspectorActor {
if self.highlighter.borrow().is_none() {
let highlighter_actor = HighlighterActor {
name: registry.new_name("highlighter"),
+ pipeline,
+ script_sender: self.script_chan.clone(),
};
let mut highlighter = self.highlighter.borrow_mut();
*highlighter = Some(highlighter_actor.name());
diff --git a/components/devtools/actors/inspector/highlighter.rs b/components/devtools/actors/inspector/highlighter.rs
index f75d25f2175..0dbf2b1e52f 100644
--- a/components/devtools/actors/inspector/highlighter.rs
+++ b/components/devtools/actors/inspector/highlighter.rs
@@ -7,6 +7,9 @@
use std::net::TcpStream;
+use base::id::PipelineId;
+use devtools_traits::DevtoolScriptControlMsg;
+use ipc_channel::ipc::IpcSender;
use serde::Serialize;
use serde_json::{self, Map, Value};
@@ -21,6 +24,8 @@ pub struct HighlighterMsg {
pub struct HighlighterActor {
pub name: String,
+ pub script_sender: IpcSender<DevtoolScriptControlMsg>,
+ pub pipeline: PipelineId,
}
#[derive(Serialize)]
@@ -41,14 +46,39 @@ impl Actor for HighlighterActor {
/// - `hide`: Disables highlighting for the selected node
fn handle_message(
&self,
- _registry: &ActorRegistry,
+ registry: &ActorRegistry,
msg_type: &str,
- _msg: &Map<String, Value>,
+ msg: &Map<String, Value>,
stream: &mut TcpStream,
_id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"show" => {
+ let Some(node_actor) = msg.get("node") else {
+ // TODO: send missing parameter error
+ return Ok(ActorMessageStatus::Ignored);
+ };
+
+ let Some(node_actor_name) = node_actor.as_str() else {
+ // TODO: send invalid parameter error
+ return Ok(ActorMessageStatus::Ignored);
+ };
+
+ if node_actor_name.starts_with("inspector") {
+ // TODO: For some reason, the client initially asks us to highlight
+ // the inspector? Investigate what this is supposed to mean.
+ let msg = ShowReply {
+ from: self.name(),
+ value: false,
+ };
+ let _ = stream.write_json_packet(&msg);
+ return Ok(ActorMessageStatus::Processed);
+ }
+
+ self.instruct_script_thread_to_highlight_node(
+ Some(node_actor_name.to_owned()),
+ registry,
+ );
let msg = ShowReply {
from: self.name(),
value: true,
@@ -58,6 +88,8 @@ impl Actor for HighlighterActor {
},
"hide" => {
+ self.instruct_script_thread_to_highlight_node(None, registry);
+
let msg = EmptyReplyMsg { from: self.name() };
let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
@@ -67,3 +99,19 @@ impl Actor for HighlighterActor {
})
}
}
+
+impl HighlighterActor {
+ fn instruct_script_thread_to_highlight_node(
+ &self,
+ node_actor: Option<String>,
+ registry: &ActorRegistry,
+ ) {
+ let node_id = node_actor.map(|node_actor| registry.actor_to_script(node_actor));
+ self.script_sender
+ .send(DevtoolScriptControlMsg::HighlightDomNode(
+ self.pipeline,
+ node_id,
+ ))
+ .unwrap();
+ }
+}
diff --git a/components/layout/context.rs b/components/layout/context.rs
index 62f8a8cdae9..3411eed486c 100644
--- a/components/layout/context.rs
+++ b/components/layout/context.rs
@@ -46,6 +46,9 @@ pub struct LayoutContext<'a> {
Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo>>>,
pub node_image_animation_map: Arc<RwLock<FxHashMap<OpaqueNode, ImageAnimationState>>>,
+
+ /// The DOM node that is highlighted by the devtools inspector, if any
+ pub highlighted_dom_node: Option<OpaqueNode>,
}
pub enum ResolvedImage<'a> {
diff --git a/components/layout/display_list/mod.rs b/components/layout/display_list/mod.rs
index 3908da69ce1..8799dd2da0c 100644
--- a/components/layout/display_list/mod.rs
+++ b/components/layout/display_list/mod.rs
@@ -31,13 +31,15 @@ use style::values::generics::NonNegative;
use style::values::generics::rect::Rect;
use style::values::specified::text::TextDecorationLine;
use style::values::specified::ui::CursorKind;
+use style_traits::CSSPixel;
use webrender_api::units::{DevicePixel, LayoutPixel, LayoutRect, LayoutSize};
use webrender_api::{
self as wr, BorderDetails, BoxShadowClipMode, ClipChainId, CommonItemProperties,
- ImageRendering, NinePatchBorder, NinePatchBorderSource, units,
+ ImageRendering, NinePatchBorder, NinePatchBorderSource, SpatialId, units,
};
use wr::units::LayoutVector2D;
+use crate::cell::ArcRefCell;
use crate::context::{LayoutContext, ResolvedImage};
pub use crate::display_list::conversions::ToWebRender;
use crate::display_list::stacking_context::StackingContextSection;
@@ -161,10 +163,49 @@ pub(crate) struct DisplayListBuilder<'a> {
/// The [DisplayList] used to collect display list items and metadata.
pub display_list: &'a mut DisplayList,
+
+ /// Data about the fragments that are highlighted by the inspector, if any.
+ ///
+ /// This data is collected during the traversal of the fragment tree and used
+ /// to paint the highlight at the very end.
+ inspector_highlight: Option<InspectorHighlight>,
+}
+
+struct InspectorHighlight {
+ /// The node that should be highlighted
+ tag: Tag,
+
+ /// Accumulates information about the fragments that belong to the highlighted node.
+ ///
+ /// This information is collected as the fragment tree is traversed to build the
+ /// display list.
+ state: Option<HighlightTraversalState>,
+}
+
+struct HighlightTraversalState {
+ /// The smallest rectangle that fully encloses all fragments created by the highlighted
+ /// dom node, if any.
+ content_box: euclid::Rect<Au, CSSPixel>,
+
+ spatial_id: SpatialId,
+
+ clip_chain_id: ClipChainId,
+
+ /// When the highlighted fragment is a box fragment we remember the information
+ /// needed to paint padding, border and margin areas.
+ maybe_box_fragment: Option<ArcRefCell<BoxFragment>>,
+}
+
+impl InspectorHighlight {
+ fn for_node(node: OpaqueNode) -> Self {
+ Self {
+ tag: Tag::new(node),
+ state: None,
+ }
+ }
}
impl DisplayList {
- /// Build the display list, returning true if it was contentful.
pub fn build(
&mut self,
context: &LayoutContext,
@@ -180,8 +221,19 @@ impl DisplayList {
element_for_canvas_background: fragment_tree.canvas_background.from_element,
context,
display_list: self,
+ inspector_highlight: context
+ .highlighted_dom_node
+ .map(InspectorHighlight::for_node),
};
fragment_tree.build_display_list(&mut builder, root_stacking_context);
+
+ if let Some(highlight) = builder
+ .inspector_highlight
+ .take()
+ .and_then(|highlight| highlight.state)
+ {
+ builder.paint_dom_inspector_highlight(highlight);
+ }
}
}
@@ -233,6 +285,150 @@ impl DisplayListBuilder<'_> {
self.display_list.compositor_info.epoch.as_u16(),
))
}
+
+ /// Draw highlights around the node that is currently hovered in the devtools.
+ fn paint_dom_inspector_highlight(&mut self, highlight: HighlightTraversalState) {
+ const CONTENT_BOX_HIGHLIGHT_COLOR: webrender_api::ColorF = webrender_api::ColorF {
+ r: 0.23,
+ g: 0.7,
+ b: 0.87,
+ a: 0.5,
+ };
+
+ const PADDING_BOX_HIGHLIGHT_COLOR: webrender_api::ColorF = webrender_api::ColorF {
+ r: 0.49,
+ g: 0.3,
+ b: 0.7,
+ a: 0.5,
+ };
+
+ const BORDER_BOX_HIGHLIGHT_COLOR: webrender_api::ColorF = webrender_api::ColorF {
+ r: 0.2,
+ g: 0.2,
+ b: 0.2,
+ a: 0.5,
+ };
+
+ const MARGIN_BOX_HIGHLIGHT_COLOR: webrender_api::ColorF = webrender_api::ColorF {
+ r: 1.,
+ g: 0.93,
+ b: 0.,
+ a: 0.5,
+ };
+
+ // Highlight content box
+ let content_box = highlight.content_box.to_webrender();
+ let properties = wr::CommonItemProperties {
+ clip_rect: content_box,
+ spatial_id: highlight.spatial_id,
+ clip_chain_id: highlight.clip_chain_id,
+ flags: wr::PrimitiveFlags::default(),
+ };
+
+ self.display_list
+ .wr
+ .push_rect(&properties, content_box, CONTENT_BOX_HIGHLIGHT_COLOR);
+
+ // Highlight margin, border and padding
+ if let Some(box_fragment) = highlight.maybe_box_fragment {
+ let mut paint_highlight =
+ |color: webrender_api::ColorF,
+ fragment_relative_bounds: PhysicalRect<Au>,
+ widths: webrender_api::units::LayoutSideOffsets| {
+ if widths.is_zero() {
+ return;
+ }
+
+ let bounds = box_fragment
+ .borrow()
+ .offset_by_containing_block(&fragment_relative_bounds)
+ .to_webrender();
+
+ // We paint each highlighted area as if it was a border for simplicity
+ let border_style = wr::BorderSide {
+ color,
+ style: webrender_api::BorderStyle::Solid,
+ };
+
+ let details = wr::BorderDetails::Normal(wr::NormalBorder {
+ top: border_style,
+ right: border_style,
+ bottom: border_style,
+ left: border_style,
+ radius: webrender_api::BorderRadius::default(),
+ do_aa: true,
+ });
+
+ let common = wr::CommonItemProperties {
+ clip_rect: bounds,
+ spatial_id: highlight.spatial_id,
+ clip_chain_id: highlight.clip_chain_id,
+ flags: wr::PrimitiveFlags::default(),
+ };
+ self.wr().push_border(&common, bounds, widths, details)
+ };
+
+ let box_fragment = box_fragment.borrow();
+ paint_highlight(
+ PADDING_BOX_HIGHLIGHT_COLOR,
+ box_fragment.padding_rect(),
+ box_fragment.padding.to_webrender(),
+ );
+ paint_highlight(
+ BORDER_BOX_HIGHLIGHT_COLOR,
+ box_fragment.border_rect(),
+ box_fragment.border.to_webrender(),
+ );
+ paint_highlight(
+ MARGIN_BOX_HIGHLIGHT_COLOR,
+ box_fragment.margin_rect(),
+ box_fragment.margin.to_webrender(),
+ );
+ }
+ }
+}
+
+impl InspectorHighlight {
+ fn register_fragment_of_highlighted_dom_node(
+ &mut self,
+ fragment: &Fragment,
+ spatial_id: SpatialId,
+ clip_chain_id: ClipChainId,
+ containing_block: &PhysicalRect<Au>,
+ ) {
+ let state = self.state.get_or_insert(HighlightTraversalState {
+ content_box: euclid::Rect::zero(),
+ spatial_id,
+ clip_chain_id,
+ maybe_box_fragment: None,
+ });
+
+ // We expect all fragments generated by one node to be in the same scroll tree node and clip node
+ debug_assert_eq!(spatial_id, state.spatial_id);
+ if clip_chain_id != ClipChainId::INVALID && state.clip_chain_id != ClipChainId::INVALID {
+ debug_assert_eq!(
+ clip_chain_id, state.clip_chain_id,
+ "Fragments of the same node must either have no clip chain or the same one"
+ );
+ }
+
+ let fragment_relative_rect = match fragment {
+ Fragment::Box(fragment) | Fragment::Float(fragment) => {
+ state.maybe_box_fragment = Some(fragment.clone());
+
+ fragment.borrow().content_rect
+ },
+ Fragment::Positioning(fragment) => fragment.borrow().rect,
+ Fragment::Text(fragment) => fragment.borrow().rect,
+ Fragment::Image(image_fragment) => image_fragment.borrow().rect,
+ Fragment::AbsoluteOrFixedPositioned(_) => return,
+ Fragment::IFrame(iframe_fragment) => iframe_fragment.borrow().rect,
+ };
+
+ state.content_box = state
+ .content_box
+ .union(&fragment_relative_rect.translate(containing_block.origin.to_vector()));
+ }
}
impl Fragment {
@@ -244,6 +440,17 @@ impl Fragment {
is_hit_test_for_scrollable_overflow: bool,
is_collapsed_table_borders: bool,
) {
+ if let Some(inspector_highlight) = &mut builder.inspector_highlight {
+ if self.tag() == Some(inspector_highlight.tag) {
+ inspector_highlight.register_fragment_of_highlighted_dom_node(
+ self,
+ builder.current_scroll_node_id.spatial_id,
+ builder.current_clip_chain_id,
+ containing_block,
+ );
+ }
+ }
+
match self {
Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => {
let box_fragment = &*box_fragment.borrow();
@@ -739,6 +946,7 @@ impl<'a> BuilderForBoxFragment<'a> {
{
return;
}
+
self.build_background(builder);
self.build_box_shadow(builder);
self.build_border(builder);
diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs
index 68219e9f156..efd31057127 100644
--- a/components/layout/layout_impl.rs
+++ b/components/layout/layout_impl.rs
@@ -452,6 +452,8 @@ impl Layout for LayoutThread {
.map(|tree| tree.conditional_size_of(ops))
.unwrap_or_default(),
});
+
+ reports.push(self.image_cache.memory_report(formatted_url, ops));
}
fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) {
@@ -649,6 +651,7 @@ impl LayoutThread {
))),
iframe_sizes: Mutex::default(),
use_rayon: rayon_pool.is_some(),
+ highlighted_dom_node: reflow_request.highlighted_dom_node,
};
self.restyle_and_build_trees(
diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml
index 04ef7ac190c..9af310f32bc 100644
--- a/components/net/Cargo.toml
+++ b/components/net/Cargo.toml
@@ -75,6 +75,7 @@ webpki-roots = { workspace = true }
webrender_api = { workspace = true }
[dev-dependencies]
+embedder_traits = { workspace = true, features = ["baked-default-resources"] }
flate2 = "1"
futures = { version = "0.3", features = ["compat"] }
hyper = { workspace = true, features = ["full"] }
diff --git a/components/net/image_cache.rs b/components/net/image_cache.rs
index eab2f9c08fe..e3d31b11736 100644
--- a/components/net/image_cache.rs
+++ b/components/net/image_cache.rs
@@ -431,7 +431,7 @@ pub struct ImageCacheImpl {
store: Arc<Mutex<ImageCacheStore>>,
/// Thread pool for image decoding
- thread_pool: CoreResourceThreadPool,
+ thread_pool: Arc<CoreResourceThreadPool>,
}
impl ImageCache for ImageCacheImpl {
@@ -454,7 +454,10 @@ impl ImageCache for ImageCacheImpl {
placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(),
compositor_api,
})),
- thread_pool: CoreResourceThreadPool::new(thread_count, "ImageCache".to_string()),
+ thread_pool: Arc::new(CoreResourceThreadPool::new(
+ thread_count,
+ "ImageCache".to_string(),
+ )),
}
}
@@ -651,6 +654,25 @@ impl ImageCache for ImageCacheImpl {
},
}
}
+
+ fn create_new_image_cache(
+ &self,
+ compositor_api: CrossProcessCompositorApi,
+ ) -> Arc<dyn ImageCache> {
+ let store = self.store.lock().unwrap();
+ let placeholder_image = store.placeholder_image.clone();
+ let placeholder_url = store.placeholder_url.clone();
+ Arc::new(ImageCacheImpl {
+ store: Arc::new(Mutex::new(ImageCacheStore {
+ pending_loads: AllPendingLoads::new(),
+ completed_loads: HashMap::new(),
+ placeholder_image,
+ placeholder_url,
+ compositor_api,
+ })),
+ thread_pool: self.thread_pool.clone(),
+ })
+ }
}
impl ImageCacheImpl {
diff --git a/components/script/devtools.rs b/components/script/devtools.rs
index c9d7c3094db..93212887dc8 100644
--- a/components/script/devtools.rs
+++ b/components/script/devtools.rs
@@ -538,3 +538,21 @@ pub(crate) fn handle_get_css_database(reply: IpcSender<HashMap<String, CssDataba
.collect();
let _ = reply.send(database);
}
+
+pub(crate) fn handle_highlight_dom_node(
+ documents: &DocumentCollection,
+ id: PipelineId,
+ node_id: Option<String>,
+) {
+ let node = node_id.and_then(|node_id| {
+ let node = find_node_by_unique_id(documents, id, &node_id);
+ if node.is_none() {
+ log::warn!("Node id {node_id} for pipeline id {id} is not found",);
+ }
+ node
+ });
+
+ if let Some(window) = documents.find_window(id) {
+ window.Document().highlight_dom_node(node.as_deref());
+ }
+}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 9ce24038259..bb30a84172c 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -565,6 +565,8 @@ pub(crate) struct Document {
/// The active keyboard modifiers for the WebView. This is updated when receiving any input event.
#[no_trace]
active_keyboard_modifiers: Cell<Modifiers>,
+ /// The node that is currently highlighted by the devtools
+ highlighted_dom_node: MutNullableDom<Node>,
}
#[allow(non_snake_case)]
@@ -4222,6 +4224,7 @@ impl Document {
intersection_observer_task_queued: Cell::new(false),
intersection_observers: Default::default(),
active_keyboard_modifiers: Cell::new(Modifiers::empty()),
+ highlighted_dom_node: Default::default(),
}
}
@@ -5213,6 +5216,14 @@ impl Document {
self.has_trustworthy_ancestor_origin.get() ||
self.origin().immutable().is_potentially_trustworthy()
}
+ pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
+ self.highlighted_dom_node.set(node);
+ self.set_needs_paint(true);
+ }
+
+ pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
+ self.highlighted_dom_node.get()
+ }
}
#[allow(non_snake_case)]
diff --git a/components/script/dom/messageport.rs b/components/script/dom/messageport.rs
index d70d3139b96..d9cd6c50768 100644
--- a/components/script/dom/messageport.rs
+++ b/components/script/dom/messageport.rs
@@ -338,10 +338,6 @@ impl MessagePortMethods<crate::DomTypeHolder> for MessagePort {
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
fn Close(&self, can_gc: CanGc) {
- if self.detached.get() {
- return;
- }
-
// Set this's [[Detached]] internal slot value to true.
self.detached.set(true);
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index b115add8611..d888cc8d917 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -2142,6 +2142,8 @@ impl Window {
.or_else(|| document.GetDocumentElement())
.map(|root| root.upcast::<Node>().to_trusted_node_address());
+ let highlighted_dom_node = document.highlighted_dom_node().map(|node| node.to_opaque());
+
// Send new document and relevant styles to layout.
let reflow = ReflowRequest {
reflow_info: Reflow {
@@ -2161,6 +2163,7 @@ impl Window {
.image_animation_manager_mut()
.take_image_animate_set(),
theme: self.theme.get(),
+ highlighted_dom_node,
};
let Some(results) = self.layout.borrow_mut().reflow(reflow) else {
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 7241c115a2a..54cf89a213f 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -745,7 +745,9 @@ impl ScriptThread {
.senders
.pipeline_to_constellation_sender
.clone(),
- image_cache: script_thread.image_cache.clone(),
+ image_cache: script_thread
+ .image_cache
+ .create_new_image_cache(script_thread.compositor_api.clone()),
#[cfg(feature = "webgpu")]
gpu_id_hub: script_thread.gpu_id_hub.clone(),
inherited_secure_context: script_thread.inherited_secure_context,
@@ -2067,6 +2069,9 @@ impl ScriptThread {
None => warn!("Message sent to closed pipeline {}.", id),
}
},
+ DevtoolScriptControlMsg::HighlightDomNode(id, node_id) => {
+ devtools::handle_highlight_dom_node(&documents, id, node_id)
+ },
}
}
@@ -2443,8 +2448,6 @@ impl ScriptThread {
let prefix = format!("url({urls})");
reports.extend(self.get_cx().get_reports(prefix.clone(), ops));
-
- reports.push(self.image_cache.memory_report(&prefix, ops));
});
reports_chan.send(ProcessReports::new(reports));
@@ -2813,8 +2816,6 @@ impl ScriptThread {
) {
debug!("{id}: Starting pipeline exit.");
- self.closed_pipelines.borrow_mut().insert(id);
-
// Abort the parser, if any,
// to prevent any further incoming networking messages from being handled.
let document = self.documents.borrow_mut().remove(id);
@@ -2835,12 +2836,6 @@ impl ScriptThread {
debug!("{id}: Shutting down layout");
document.window().layout_mut().exit_now();
- debug!("{id}: Sending PipelineExited message to constellation");
- self.senders
- .pipeline_to_constellation_sender
- .send((id, ScriptToConstellationMessage::PipelineExited))
- .ok();
-
// Clear any active animations and unroot all of the associated DOM objects.
debug!("{id}: Clearing animations");
document.animations().clear();
@@ -2863,6 +2858,15 @@ impl ScriptThread {
window.clear_js_runtime();
}
+ // Prevent any further work for this Pipeline.
+ self.closed_pipelines.borrow_mut().insert(id);
+
+ debug!("{id}: Sending PipelineExited message to constellation");
+ self.senders
+ .pipeline_to_constellation_sender
+ .send((id, ScriptToConstellationMessage::PipelineExited))
+ .ok();
+
debug!("{id}: Finished pipeline exit");
}
@@ -3145,13 +3149,17 @@ impl ScriptThread {
self.resource_threads.clone(),
));
+ let image_cache = self
+ .image_cache
+ .create_new_image_cache(self.compositor_api.clone());
+
let layout_config = LayoutConfig {
id: incomplete.pipeline_id,
webview_id: incomplete.webview_id,
url: final_url.clone(),
is_iframe: incomplete.parent_info.is_some(),
script_chan: self.senders.constellation_sender.clone(),
- image_cache: self.image_cache.clone(),
+ image_cache: image_cache.clone(),
font_context: font_context.clone(),
time_profiler_chan: self.senders.time_profiler_sender.clone(),
compositor_api: self.compositor_api.clone(),
@@ -3166,7 +3174,7 @@ impl ScriptThread {
self.layout_factory.create(layout_config),
font_context,
self.senders.image_cache_sender.clone(),
- self.image_cache.clone(),
+ image_cache.clone(),
self.resource_threads.clone(),
#[cfg(feature = "bluetooth")]
self.senders.bluetooth_sender.clone(),
diff --git a/components/servo/tests/webview.rs b/components/servo/tests/webview.rs
index 4ed06e412da..89fbe2025a3 100644
--- a/components/servo/tests/webview.rs
+++ b/components/servo/tests/webview.rs
@@ -44,6 +44,18 @@ fn test_create_webview(servo_test: &ServoTest) -> Result<(), anyhow::Error> {
Ok(())
}
+fn test_create_webview_and_immediately_drop_webview_before_shutdown(
+ servo_test: &ServoTest,
+) -> Result<(), anyhow::Error> {
+ WebViewBuilder::new(servo_test.servo()).build();
+ Ok(())
+}
+
fn main() {
- run_api_tests!(test_create_webview);
+ run_api_tests!(
+ test_create_webview,
+ // This test needs to be last, as it tests creating and dropping
+ // a WebView right before shutdown.
+ test_create_webview_and_immediately_drop_webview_before_shutdown
+ );
}
diff --git a/components/shared/devtools/lib.rs b/components/shared/devtools/lib.rs
index c07f4529073..628d76bd25d 100644
--- a/components/shared/devtools/lib.rs
+++ b/components/shared/devtools/lib.rs
@@ -273,6 +273,8 @@ pub enum DevtoolScriptControlMsg {
GetCssDatabase(IpcSender<HashMap<String, CssDatabaseProperty>>),
/// Simulates a light or dark color scheme for the given pipeline
SimulateColorScheme(PipelineId, Theme),
+ /// Highlight the given DOM node
+ HighlightDomNode(PipelineId, Option<String>),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
diff --git a/components/shared/net/image_cache.rs b/components/shared/net/image_cache.rs
index 8fb329d304f..3f316388755 100644
--- a/components/shared/net/image_cache.rs
+++ b/components/shared/net/image_cache.rs
@@ -141,4 +141,10 @@ pub trait ImageCache: Sync + Send {
/// Inform the image cache about a response for a pending request.
fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg);
+
+ /// Create new image cache based on this one, while reusing the existing thread_pool.
+ fn create_new_image_cache(
+ &self,
+ compositor_api: CrossProcessCompositorApi,
+ ) -> Arc<dyn ImageCache>;
}
diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs
index 66baccd5147..8c5d4edc4e0 100644
--- a/components/shared/script_layout/lib.rs
+++ b/components/shared/script_layout/lib.rs
@@ -428,6 +428,8 @@ pub struct ReflowRequest {
pub node_to_image_animation_map: FxHashMap<OpaqueNode, ImageAnimationState>,
/// The theme for the window
pub theme: PrefersColorScheme,
+ /// The node highlighted by the devtools, if any
+ pub highlighted_dom_node: Option<OpaqueNode>,
}
/// A pending restyle.
diff --git a/tests/wpt/meta/content-security-policy/generic/invalid-characters-in-policy.html.ini b/tests/wpt/meta/content-security-policy/generic/invalid-characters-in-policy.html.ini
index ccb770e00d4..395e5cf9f3f 100644
--- a/tests/wpt/meta/content-security-policy/generic/invalid-characters-in-policy.html.ini
+++ b/tests/wpt/meta/content-security-policy/generic/invalid-characters-in-policy.html.ini
@@ -1,18 +1,12 @@
[invalid-characters-in-policy.html]
- [Should not load image with 'none' CSP - meta tag]
- expected: FAIL
-
- [Should not load image with 'none' CSP - HTTP header]
- expected: FAIL
-
- [Non-ASCII character in directive value should not affect other directives. - meta tag]
+ [Non-ASCII character in directive value should not affect other directives. - HTTP header]
expected: FAIL
- [Non-ASCII character in directive value should not affect other directives. - HTTP header]
+ [Non-ASCII character in directive name should not affect other directives. - HTTP header]
expected: FAIL
- [Non-ASCII character in directive name should not affect other directives. - meta tag]
+ [Non-ASCII character in directive value should drop the whole directive. - meta tag]
expected: FAIL
- [Non-ASCII character in directive name should not affect other directives. - HTTP header]
+ [Non-ASCII quote character in directive value should drop the whole directive. - meta tag]
expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/generic/only-valid-whitespaces-are-allowed.html.ini b/tests/wpt/meta/content-security-policy/generic/only-valid-whitespaces-are-allowed.html.ini
index a8dd0149615..e3648061bc3 100644
--- a/tests/wpt/meta/content-security-policy/generic/only-valid-whitespaces-are-allowed.html.ini
+++ b/tests/wpt/meta/content-security-policy/generic/only-valid-whitespaces-are-allowed.html.ini
@@ -6,50 +6,5 @@
[U+000C FF should be properly parsed inside directive value - HTTP header]
expected: TIMEOUT
- [Should not load image with 'none' CSP - meta tag]
- expected: FAIL
-
- [Should not load image with 'none' CSP - HTTP header]
- expected: FAIL
-
- [U+0009 TAB should be properly parsed between directive name and value - meta tag]
- expected: FAIL
-
- [U+0009 TAB should be properly parsed between directive name and value - HTTP header]
- expected: FAIL
-
- [U+000C FF should be properly parsed between directive name and value - meta tag]
- expected: FAIL
-
- [U+000A LF should be properly parsed between directive name and value - meta tag]
- expected: FAIL
-
- [U+000D CR should be properly parsed between directive name and value - meta tag]
- expected: FAIL
-
- [U+0020 SPACE should be properly parsed between directive name and value - meta tag]
- expected: FAIL
-
- [U+0020 SPACE should be properly parsed between directive name and value - HTTP header]
- expected: FAIL
-
- [U+0009 TAB should be properly parsed inside directive value - meta tag]
- expected: FAIL
-
- [U+0009 TAB should be properly parsed inside directive value - HTTP header]
- expected: FAIL
-
- [U+000C FF should be properly parsed inside directive value - meta tag]
- expected: FAIL
-
- [U+000A LF should be properly parsed inside directive value - meta tag]
- expected: FAIL
-
- [U+000D CR should be properly parsed inside directive value - meta tag]
- expected: FAIL
-
- [U+0020 SPACE should be properly parsed inside directive value - meta tag]
- expected: FAIL
-
- [U+0020 SPACE should be properly parsed inside directive value - HTTP header]
+ [U+00A0 NBSP should not be parsed inside directive value - meta tag]
expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/inheritance/history-iframe.sub.html.ini b/tests/wpt/meta/content-security-policy/inheritance/history-iframe.sub.html.ini
index d629ffef04f..73a32477504 100644
--- a/tests/wpt/meta/content-security-policy/inheritance/history-iframe.sub.html.ini
+++ b/tests/wpt/meta/content-security-policy/inheritance/history-iframe.sub.html.ini
@@ -16,9 +16,3 @@
[History navigation in iframe: data URL document is navigated back from history cross-origin.]
expected: FAIL
-
- [History navigation in iframe: srcdoc iframe is navigated back from history same-origin.]
- expected: FAIL
-
- [History navigation in iframe: srcdoc iframe is navigated back from history cross-origin.]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/inheritance/iframe-all-local-schemes.sub.html.ini b/tests/wpt/meta/content-security-policy/inheritance/iframe-all-local-schemes.sub.html.ini
index af308a4588e..fcd96aa7a47 100644
--- a/tests/wpt/meta/content-security-policy/inheritance/iframe-all-local-schemes.sub.html.ini
+++ b/tests/wpt/meta/content-security-policy/inheritance/iframe-all-local-schemes.sub.html.ini
@@ -4,3 +4,15 @@
[<iframe sandbox src='blob:...'>'s inherits policy. (opaque origin sandbox)]
expected: FAIL
+
+ [window about:blank inherits policy.]
+ expected: FAIL
+
+ [<iframe src='blob:...'>'s inherits policy.]
+ expected: FAIL
+
+ [window url='blob:...' inherits policy.]
+ expected: FAIL
+
+ [window url='javascript:...'>'s inherits policy (static <img> is blocked)]
+ expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/inheritance/iframe-srcdoc-inheritance.html.ini b/tests/wpt/meta/content-security-policy/inheritance/iframe-srcdoc-inheritance.html.ini
deleted file mode 100644
index b37ad96bcc3..00000000000
--- a/tests/wpt/meta/content-security-policy/inheritance/iframe-srcdoc-inheritance.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[iframe-srcdoc-inheritance.html]
- expected: TIMEOUT
- [Second image should be blocked]
- expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/inheritance/location-reload.html.ini b/tests/wpt/meta/content-security-policy/inheritance/location-reload.html.ini
index 6a4ec8e2baa..4efb1bf017b 100644
--- a/tests/wpt/meta/content-security-policy/inheritance/location-reload.html.ini
+++ b/tests/wpt/meta/content-security-policy/inheritance/location-reload.html.ini
@@ -2,3 +2,6 @@
expected: TIMEOUT
[location.reload() of srcdoc iframe.]
expected: TIMEOUT
+
+ [location.reload() of blob URL iframe.]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-backgrounds/background-image-shared-stylesheet.html.ini b/tests/wpt/meta/css/css-backgrounds/background-image-shared-stylesheet.html.ini
deleted file mode 100644
index c4d14766411..00000000000
--- a/tests/wpt/meta/css/css-backgrounds/background-image-shared-stylesheet.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[background-image-shared-stylesheet.html]
- expected: TIMEOUT
diff --git a/tests/wpt/meta/fetch/stale-while-revalidate/stale-image.html.ini b/tests/wpt/meta/fetch/stale-while-revalidate/stale-image.html.ini
index e95e391fd91..2a23c41e9d8 100644
--- a/tests/wpt/meta/fetch/stale-while-revalidate/stale-image.html.ini
+++ b/tests/wpt/meta/fetch/stale-while-revalidate/stale-image.html.ini
@@ -1,4 +1,3 @@
[stale-image.html]
- expected: TIMEOUT
[Cache returns stale resource]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/meta/quirks/line-height-calculation.html.ini b/tests/wpt/meta/quirks/line-height-calculation.html.ini
index 248da212174..42e4c8c0007 100644
--- a/tests/wpt/meta/quirks/line-height-calculation.html.ini
+++ b/tests/wpt/meta/quirks/line-height-calculation.html.ini
@@ -7,3 +7,6 @@
[The line height calculation quirk, <table><tr><td id=test><img src="{png}"> <img src="{png}"><tr><td id=ref>x<tr><td id=s_ref>x</table>]
expected: FAIL
+
+ [The line height calculation quirk, #test img { padding:1px }<div id=test><img src="{png}"></div><img id=ref src="{png}" height=3><div id=s_ref>x</div>]
+ expected: FAIL
diff --git a/tests/wpt/meta/quirks/table-cell-width-calculation.html.ini b/tests/wpt/meta/quirks/table-cell-width-calculation.html.ini
index 3d66c4f26ac..8bdfbfb0a63 100644
--- a/tests/wpt/meta/quirks/table-cell-width-calculation.html.ini
+++ b/tests/wpt/meta/quirks/table-cell-width-calculation.html.ini
@@ -1,18 +1,3 @@
[table-cell-width-calculation.html]
- [The table cell width calculation quirk, basic]
- expected: FAIL
-
- [The table cell width calculation quirk, inline-block]
- expected: FAIL
-
- [The table cell width calculation quirk, img in span]
- expected: FAIL
-
- [The table cell width calculation quirk, the don't-wrap rule is only for the purpose of calculating the width of the cell]
- expected: FAIL
-
- [The table cell width calculation quirk, display:table-cell on span]
- expected: FAIL
-
- [The table cell width calculation quirk, display:table-cell on span, wbr]
+ [The table cell width calculation quirk, the quirk shouldn't apply for <video poster>]
expected: FAIL