From e64f0215507ee08dd513cdca3cdc856caa271c79 Mon Sep 17 00:00:00 2001 From: Narfinger Date: Mon, 29 Sep 2025 12:01:56 +0200 Subject: [PATCH] Allow WebViews and fonts to have a RenderingGroupId. (#39140) Motivation: The font cache currently has to store a cache of Keys which need to be given by the webrender instance. Having a cache for every WebViewId in the future when we have every webview have the different webrender::DocumentId might be too wasteful to store this key cache per DocumentId. This proposes to include in the WebViewId another id, the RenderingGroupId. This id can be easily changed to be equivalent to the DocumentId when we support multiple DocumentIds for a unique Webrender instance. Additionally this will keep it easier to integrate the currently out of tree patches for multiple rendering contexts with different webrenders. Change: We introduce the RenderingGroupId in the WebViewId and allow a method to extract it. The font key cache uses this cache and forwards it to the Compositor when requesting new changes. The compositor currently ignores this id. Additionally, the WebView can return the RenderingGroupId. The WebViewId also has an appropiate constructor for specifying a RenderingGroupId. Because there currently will be only one RenderingGroupId the performance will be minimal. Signed-off-by: Narfinger Testing: This should be covered by WPT tests and normal browsing behavior works fine. --------- Signed-off-by: Narfinger --- Cargo.lock | 1 + components/compositing/compositor.rs | 8 +- components/fonts/font.rs | 21 +++-- components/fonts/font_context.rs | 19 +++- components/fonts/system_font_service.rs | 90 ++++++++++++++----- components/fonts/tests/font_context.rs | 6 +- components/layout/construct_modern.rs | 1 + components/layout/context.rs | 3 + components/layout/flow/construct.rs | 1 + components/layout/flow/inline/construct.rs | 4 + components/layout/flow/inline/mod.rs | 4 + components/layout/flow/inline/text_run.rs | 16 +++- components/layout/layout_impl.rs | 1 + components/servo/webview.rs | 30 +++++-- components/shared/base/id.rs | 66 +++++++++++--- components/shared/compositing/lib.rs | 6 +- components/shared/fonts/Cargo.toml | 1 + .../shared/fonts/system_font_service_proxy.rs | 25 ++++-- 18 files changed, 240 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 540af7029e3..400d9618696 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2817,6 +2817,7 @@ name = "fonts_traits" version = "0.0.1" dependencies = [ "atomic_refcell", + "base", "dwrote", "ipc-channel", "log", diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 352f5a9ae2c..13ea3a32428 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -14,7 +14,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use base::Epoch; use base::cross_process_instant::CrossProcessInstant; use base::generic_channel::{GenericSender, RoutedReceiver}; -use base::id::{PipelineId, WebViewId}; +use base::id::{PipelineId, RenderingGroupId, WebViewId}; use bitflags::bitflags; use compositing_traits::display_list::{CompositorDisplayListInfo, ScrollTree, ScrollType}; use compositing_traits::rendering_context::RenderingContext; @@ -792,11 +792,13 @@ impl IOCompositor { number_of_font_keys, number_of_font_instance_keys, result_sender, + rendering_group_id, ) => { self.handle_generate_font_keys( number_of_font_keys, number_of_font_instance_keys, result_sender, + rendering_group_id, ); }, CompositorMsg::Viewport(webview_id, viewport_description) => { @@ -834,11 +836,13 @@ impl IOCompositor { number_of_font_keys, number_of_font_instance_keys, result_sender, + rendering_group_id, ) => { self.handle_generate_font_keys( number_of_font_keys, number_of_font_instance_keys, result_sender, + rendering_group_id, ); }, CompositorMsg::NewWebRenderFrameReady(..) => { @@ -852,11 +856,13 @@ impl IOCompositor { } /// Generate the font keys and send them to the `result_sender`. + /// Currently `RenderingGroupId` is not used. fn handle_generate_font_keys( &self, number_of_font_keys: usize, number_of_font_instance_keys: usize, result_sender: GenericSender<(Vec, Vec)>, + _rendering_group_id: RenderingGroupId, ) { let font_keys = (0..number_of_font_keys) .map(|_| self.global.borrow().webrender_api.generate_font_key()) diff --git a/components/fonts/font.rs b/components/fonts/font.rs index 5a787fd6ea4..543936db63b 100644 --- a/components/fonts/font.rs +++ b/components/fonts/font.rs @@ -12,6 +12,7 @@ use std::time::Instant; use std::{iter, str}; use app_units::Au; +use base::id::RenderingGroupId; use bitflags::bitflags; use euclid::default::{Point2D, Rect}; use euclid::num::Zero; @@ -21,6 +22,7 @@ use malloc_size_of_derive::MallocSizeOf; use parking_lot::RwLock; use read_fonts::tables::os2::{Os2, SelectionFlags}; use read_fonts::types::Tag; +use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use style::computed_values::font_variant_caps; @@ -223,7 +225,7 @@ pub struct Font { shaper: OnceLock, cached_shape_data: RwLock, - pub(crate) font_instance_key: OnceLock, + font_instance_key: RwLock>, /// If this is a synthesized small caps font, then this font reference is for /// the version of the font used to replace lowercase ASCII letters. It's up @@ -248,12 +250,15 @@ impl malloc_size_of::MallocSizeOf for Font { fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize { // TODO: Collect memory usage for platform fonts and for shapers. // This skips the template, because they are already stored in the template cache. + self.metrics.size_of(ops) + self.descriptor.size_of(ops) + self.cached_shape_data.read().size_of(ops) + self.font_instance_key - .get() - .map_or(0, |key| key.size_of(ops)) + .read() + .values() + .map(|key| key.size_of(ops)) + .sum::() } } @@ -306,10 +311,16 @@ impl Font { }) } - pub fn key(&self, font_context: &FontContext) -> FontInstanceKey { + pub fn key( + &self, + rendering_group_id: RenderingGroupId, + font_context: &FontContext, + ) -> FontInstanceKey { *self .font_instance_key - .get_or_init(|| font_context.create_font_instance_key(self)) + .write() + .entry(rendering_group_id) + .or_insert_with(|| font_context.create_font_instance_key(self, rendering_group_id)) } /// Return the data for this `Font`. Note that this is currently highly inefficient for system diff --git a/components/fonts/font_context.rs b/components/fonts/font_context.rs index 38f189ab136..345d045b61e 100644 --- a/components/fonts/font_context.rs +++ b/components/fonts/font_context.rs @@ -10,7 +10,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use app_units::Au; -use base::id::WebViewId; +use base::id::{RenderingGroupId, WebViewId}; use compositing_traits::CrossProcessCompositorApi; use fonts_traits::{ CSSFontFaceDescriptors, FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef, @@ -277,19 +277,25 @@ impl FontContext { )?))) } - pub(crate) fn create_font_instance_key(&self, font: &Font) -> FontInstanceKey { + pub(crate) fn create_font_instance_key( + &self, + font: &Font, + rendering_group_id: RenderingGroupId, + ) -> FontInstanceKey { match font.template.identifier() { FontIdentifier::Local(_) => self.system_font_service_proxy.get_system_font_instance( font.template.identifier(), font.descriptor.pt_size, font.webrender_font_instance_flags(), font.variations().to_owned(), + rendering_group_id, ), FontIdentifier::Web(_) => self.create_web_font_instance( font.template.clone(), font.descriptor.pt_size, font.webrender_font_instance_flags(), font.variations().to_owned(), + rendering_group_id, ), } } @@ -300,6 +306,7 @@ impl FontContext { pt_size: Au, flags: FontInstanceFlags, variations: Vec, + rendering_group_id: RenderingGroupId, ) -> FontInstanceKey { let identifier = font_template.identifier().clone(); let font_data = self @@ -310,7 +317,9 @@ impl FontContext { .write() .entry(identifier.clone()) .or_insert_with(|| { - let font_key = self.system_font_service_proxy.generate_font_key(); + let font_key = self + .system_font_service_proxy + .generate_font_key(rendering_group_id); self.compositor_api.lock().add_font( font_key, font_data.as_ipc_shared_memory(), @@ -324,7 +333,9 @@ impl FontContext { .write() .entry((font_key, pt_size, variations.clone())) .or_insert_with(|| { - let font_instance_key = self.system_font_service_proxy.generate_font_instance_key(); + let font_instance_key = self + .system_font_service_proxy + .generate_font_instance_key(rendering_group_id); self.compositor_api.lock().add_font_instance( font_instance_key, font_key, diff --git a/components/fonts/system_font_service.rs b/components/fonts/system_font_service.rs index eaaa0bb52db..4d9100316f9 100644 --- a/components/fonts/system_font_service.rs +++ b/components/fonts/system_font_service.rs @@ -8,6 +8,7 @@ use std::collections::HashMap; use std::thread; use app_units::Au; +use base::id::RenderingGroupId; use compositing_traits::CrossProcessCompositorApi; use fonts_traits::{ FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef, LowercaseFontFamilyName, @@ -20,6 +21,7 @@ use profile_traits::mem::{ ProcessReports, ProfilerChan, Report, ReportKind, ReportsChan, perform_memory_report, }; use profile_traits::path; +use rustc_hash::FxHashMap; use servo_config::pref; use style::values::computed::font::{GenericFontFamily, SingleFontFamily}; use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, FontVariation}; @@ -48,21 +50,23 @@ pub struct SystemFontService { port: IpcReceiver, local_families: FontStore, compositor_api: CrossProcessCompositorApi, - webrender_fonts: HashMap, - font_instances: HashMap<(FontKey, Au, Vec), FontInstanceKey>, + // keys already have the IdNamespace for webrender + webrender_fonts: HashMap<(FontIdentifier, RenderingGroupId), FontKey>, + font_instances: HashMap<(FontKey, Au, Vec, RenderingGroupId), FontInstanceKey>, generic_fonts: ResolvedGenericFontFamilies, /// This is an optimization that allows the [`SystemFontService`] to send font data to /// the compositor asynchronously for creating WebRender fonts, while immediately /// returning a font key for that data. Once the free keys are exhausted, the /// [`SystemFontService`] will fetch a new batch. - free_font_keys: Vec, + /// TODO: We currently do not delete the free keys if a `WebView` is removed. + free_font_keys: FxHashMap>, /// This is an optimization that allows the [`SystemFontService`] to create WebRender font /// instances in the compositor asynchronously, while immediately returning a font /// instance key for the instance. Once the free keys are exhausted, the /// [`SystemFontService`] will fetch a new batch. - free_font_instance_keys: Vec, + free_font_instance_keys: FxHashMap>, } impl SystemFontService { @@ -88,7 +92,7 @@ impl SystemFontService { free_font_instance_keys: Default::default(), }; - cache.fetch_new_keys(); + cache.fetch_new_keys(RenderingGroupId::default()); cache.refresh_local_families(); memory_profiler_sender.run_with_memory_reporting( @@ -120,22 +124,41 @@ impl SystemFontService { result_sender.send(self.get_font_templates(font_descriptor, font_family)); }, SystemFontServiceMessage::GetFontInstance( + rendering_group_id, identifier, pt_size, flags, variations, result, ) => { - let _ = - result.send(self.get_font_instance(identifier, pt_size, flags, variations)); + let _ = result.send(self.get_font_instance( + rendering_group_id, + identifier, + pt_size, + flags, + variations, + )); }, - SystemFontServiceMessage::GetFontKey(result_sender) => { - self.fetch_new_keys(); - let _ = result_sender.send(self.free_font_keys.pop().unwrap()); + SystemFontServiceMessage::GetFontKey(rendering_group_id, result_sender) => { + self.fetch_new_keys(rendering_group_id); + + let _ = result_sender.send( + self.free_font_keys + .get_mut(&rendering_group_id) + .expect("We just filled the keys") + .pop() + .unwrap(), + ); }, - SystemFontServiceMessage::GetFontInstanceKey(result_sender) => { - self.fetch_new_keys(); - let _ = result_sender.send(self.free_font_instance_keys.pop().unwrap()); + SystemFontServiceMessage::GetFontInstanceKey(rendering_group_id, result_sender) => { + self.fetch_new_keys(rendering_group_id); + let _ = result_sender.send( + self.free_font_instance_keys + .get_mut(&rendering_group_id) + .expect("We just filled the keys") + .pop() + .unwrap(), + ); }, SystemFontServiceMessage::CollectMemoryReport(report_sender) => { self.collect_memory_report(report_sender); @@ -161,8 +184,16 @@ impl SystemFontService { } #[servo_tracing::instrument(skip_all)] - fn fetch_new_keys(&mut self) { - if !self.free_font_keys.is_empty() && !self.free_font_instance_keys.is_empty() { + fn fetch_new_keys(&mut self, rendering_group_id: RenderingGroupId) { + if !self + .free_font_keys + .get(&rendering_group_id) + .is_none_or(|v| v.is_empty()) && + !self + .free_font_instance_keys + .get(&rendering_group_id) + .is_none_or(|v| v.is_empty()) + { return; } @@ -171,9 +202,15 @@ impl SystemFontService { let (mut new_font_keys, mut new_font_instance_keys) = self.compositor_api.fetch_font_keys( FREE_FONT_KEYS_BATCH_SIZE - self.free_font_keys.len(), FREE_FONT_INSTANCE_KEYS_BATCH_SIZE - self.free_font_instance_keys.len(), + rendering_group_id, ); - self.free_font_keys.append(&mut new_font_keys); + self.free_font_keys + .entry(rendering_group_id) + .or_default() + .append(&mut new_font_keys); self.free_font_instance_keys + .entry(rendering_group_id) + .or_default() .append(&mut new_font_instance_keys); } @@ -228,20 +265,26 @@ impl SystemFontService { #[servo_tracing::instrument(skip_all)] fn get_font_instance( &mut self, + rendering_group_id: RenderingGroupId, identifier: FontIdentifier, pt_size: Au, flags: FontInstanceFlags, variations: Vec, ) -> FontInstanceKey { - self.fetch_new_keys(); + self.fetch_new_keys(rendering_group_id); let compositor_api = &self.compositor_api; let webrender_fonts = &mut self.webrender_fonts; let font_key = *webrender_fonts - .entry(identifier.clone()) + .entry((identifier.clone(), rendering_group_id)) .or_insert_with(|| { - let font_key = self.free_font_keys.pop().unwrap(); + let font_key = self + .free_font_keys + .get_mut(&rendering_group_id) + .expect("We just filled the keys") + .pop() + .unwrap(); let FontIdentifier::Local(local_font_identifier) = identifier else { unreachable!("Should never have a web font in the system font service"); }; @@ -252,9 +295,14 @@ impl SystemFontService { *self .font_instances - .entry((font_key, pt_size, variations.clone())) + .entry((font_key, pt_size, variations.clone(), rendering_group_id)) .or_insert_with(|| { - let font_instance_key = self.free_font_instance_keys.pop().unwrap(); + let font_instance_key = self + .free_font_instance_keys + .get_mut(&rendering_group_id) + .expect("We just filled the keys") + .pop() + .unwrap(); compositor_api.add_font_instance( font_instance_key, font_key, diff --git a/components/fonts/tests/font_context.rs b/components/fonts/tests/font_context.rs index b25f59bf86e..d91f09d83c3 100644 --- a/components/fonts/tests/font_context.rs +++ b/components/fonts/tests/font_context.rs @@ -130,11 +130,11 @@ mod font_context { .collect(), ); }, - SystemFontServiceMessage::GetFontInstanceKey(result_sender) | - SystemFontServiceMessage::GetFontInstance(_, _, _, _, result_sender) => { + SystemFontServiceMessage::GetFontInstanceKey(_, result_sender) | + SystemFontServiceMessage::GetFontInstance(_, _, _, _, _, result_sender) => { let _ = result_sender.send(FontInstanceKey(IdNamespace(0), 0)); }, - SystemFontServiceMessage::GetFontKey(result_sender) => { + SystemFontServiceMessage::GetFontKey(_, result_sender) => { let _ = result_sender.send(FontKey(IdNamespace(0), 0)); }, SystemFontServiceMessage::Exit(result_sender) => { diff --git a/components/layout/construct_modern.rs b/components/layout/construct_modern.rs index 5ccaf88e20d..7725e94ba8d 100644 --- a/components/layout/construct_modern.rs +++ b/components/layout/construct_modern.rs @@ -63,6 +63,7 @@ impl<'dom> ModernContainerJob<'dom> { true, /* has_first_formatted_line */ false, /* is_single_line_text_box */ builder.info.style.to_bidi_level(), + builder.context.rendering_group_id, )?; let block_formatting_context = BlockFormattingContext::from_block_container( diff --git a/components/layout/context.rs b/components/layout/context.rs index 2267597c487..1436056ce7e 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -5,6 +5,7 @@ use std::collections::HashMap; use std::sync::Arc; +use base::id::RenderingGroupId; use embedder_traits::UntrustedNodeAddress; use euclid::Size2D; use fonts::FontContext; @@ -44,6 +45,8 @@ pub(crate) struct LayoutContext<'a> { /// An [`ImageResolver`] used for resolving images during box and fragment /// tree construction. Later passed to display list construction. pub image_resolver: Arc, + + pub rendering_group_id: RenderingGroupId, } pub enum ResolvedImage<'a> { diff --git a/components/layout/flow/construct.rs b/components/layout/flow/construct.rs index 35feab41cde..aa5feefb103 100644 --- a/components/layout/flow/construct.rs +++ b/components/layout/flow/construct.rs @@ -230,6 +230,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> { !self.have_already_seen_first_line_for_text_indent, self.info.node.is_single_line_text_input(), self.info.style.to_bidi_level(), + self.context.rendering_group_id, ) } diff --git a/components/layout/flow/inline/construct.rs b/components/layout/flow/inline/construct.rs index 120a6a5b8b3..779a095fa08 100644 --- a/components/layout/flow/inline/construct.rs +++ b/components/layout/flow/inline/construct.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use std::char::{ToLowercase, ToUppercase}; +use base::id::RenderingGroupId; use icu_segmenter::WordSegmenter; use itertools::izip; use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse; @@ -475,6 +476,7 @@ impl InlineFormattingContextBuilder { has_first_formatted_line, /* is_single_line_text_input = */ false, default_bidi_level, + layout_context.rendering_group_id, ) } @@ -485,6 +487,7 @@ impl InlineFormattingContextBuilder { has_first_formatted_line: bool, is_single_line_text_input: bool, default_bidi_level: Level, + rendering_group_id: RenderingGroupId, ) -> Option { if self.is_empty { return None; @@ -498,6 +501,7 @@ impl InlineFormattingContextBuilder { has_first_formatted_line, is_single_line_text_input, default_bidi_level, + rendering_group_id, )) } } diff --git a/components/layout/flow/inline/mod.rs b/components/layout/flow/inline/mod.rs index 7034144a79d..3bf9f05782d 100644 --- a/components/layout/flow/inline/mod.rs +++ b/components/layout/flow/inline/mod.rs @@ -79,6 +79,7 @@ use std::mem; use std::rc::Rc; use app_units::{Au, MAX_AU}; +use base::id::RenderingGroupId; use bitflags::bitflags; use construct::InlineFormattingContextBuilder; use fonts::{ByteIndex, FontMetrics, GlyphStore}; @@ -1681,6 +1682,7 @@ impl InlineFormattingContext { has_first_formatted_line: bool, is_single_line_text_input: bool, starting_bidi_level: Level, + rendering_group_id: RenderingGroupId, ) -> Self { // This is to prevent a double borrow. let text_content: String = builder.text_segments.into_iter().collect(); @@ -1699,6 +1701,7 @@ impl InlineFormattingContext { &mut new_linebreaker, &mut font_metrics, &bidi_info, + rendering_group_id, ); }, InlineItem::StartInlineBox(inline_box) => { @@ -1711,6 +1714,7 @@ impl InlineFormattingContext { &font, &mut font_metrics, &layout_context.font_context, + rendering_group_id, )); } }, diff --git a/components/layout/flow/inline/text_run.rs b/components/layout/flow/inline/text_run.rs index e37be9a5687..6e73659198a 100644 --- a/components/layout/flow/inline/text_run.rs +++ b/components/layout/flow/inline/text_run.rs @@ -6,6 +6,7 @@ use std::mem; use std::ops::Range; use app_units::Au; +use base::id::RenderingGroupId; use base::text::is_bidi_control; use fonts::{ FontContext, FontRef, GlyphRun, LAST_RESORT_GLYPH_ADVANCE, ShapingFlags, ShapingOptions, @@ -96,6 +97,7 @@ impl TextRunSegment { bidi_level: Level, fonts: &[FontKeyAndMetrics], font_context: &FontContext, + rendering_group_id: RenderingGroupId, ) -> bool { fn is_specific(script: Script) -> bool { script != Script::Common && script != Script::Inherited @@ -106,7 +108,7 @@ impl TextRunSegment { } let current_font_key_and_metrics = &fonts[self.font_index]; - if new_font.key(font_context) != current_font_key_and_metrics.key || + if new_font.key(rendering_group_id, font_context) != current_font_key_and_metrics.key || new_font.descriptor.pt_size != current_font_key_and_metrics.pt_size { return false; @@ -371,6 +373,7 @@ impl TextRun { linebreaker: &mut LineBreaker, font_cache: &mut Vec, bidi_info: &BidiInfo, + rendering_group_id: RenderingGroupId, ) { let parent_style = self.inline_styles.style.borrow().clone(); let inherited_text_style = parent_style.get_inherited_text().clone(); @@ -403,6 +406,7 @@ impl TextRun { font_cache, bidi_info, &parent_style, + rendering_group_id, ) .into_iter() .map(|(mut segment, font)| { @@ -451,6 +455,7 @@ impl TextRun { font_cache: &mut Vec, bidi_info: &BidiInfo, parent_style: &Arc, + rendering_group_id: RenderingGroupId, ) -> Vec<(TextRunSegment, FontRef)> { let font_group = font_context.font_group(parent_style.clone_font()); let mut current: Option<(TextRunSegment, FontRef)> = None; @@ -497,12 +502,13 @@ impl TextRun { bidi_level, font_cache, font_context, + rendering_group_id, ) { continue; } } - let font_index = add_or_get_font(&font, font_cache, font_context); + let font_index = add_or_get_font(&font, font_cache, font_context, rendering_group_id); // Add the new segment and finish the existing one, if we had one. If the first // characters in the run were control characters we may be creating the first @@ -527,7 +533,8 @@ impl TextRun { // of those cases, just use the first font. if current.is_none() { current = font_group.write().first(font_context).map(|font| { - let font_index = add_or_get_font(&font, font_cache, font_context); + let font_index = + add_or_get_font(&font, font_cache, font_context, rendering_group_id); ( TextRunSegment::new( font_index, @@ -597,8 +604,9 @@ pub(super) fn add_or_get_font( font: &FontRef, ifc_fonts: &mut Vec, font_context: &FontContext, + rendering_group_id: RenderingGroupId, ) -> usize { - let font_instance_key = font.key(font_context); + let font_instance_key = font.key(rendering_group_id, font_context); for (index, ifc_font_info) in ifc_fonts.iter().enumerate() { if ifc_font_info.key == font_instance_key && ifc_font_info.pt_size == font.descriptor.pt_size diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index 671e12e5022..77c174b4188 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -997,6 +997,7 @@ impl LayoutThread { iframe_sizes: Mutex::default(), use_rayon: rayon_pool.is_some(), image_resolver: image_resolver.clone(), + rendering_group_id: self.webview_id.into(), }; let restyle = reflow_request diff --git a/components/servo/webview.rs b/components/servo/webview.rs index c423279d4f4..5ac0f6e91ec 100644 --- a/components/servo/webview.rs +++ b/components/servo/webview.rs @@ -7,7 +7,7 @@ use std::hash::Hash; use std::rc::{Rc, Weak}; use std::time::Duration; -use base::id::WebViewId; +use base::id::{RenderingGroupId, WebViewId}; use compositing::IOCompositor; use compositing_traits::WebViewTrait; use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection}; @@ -90,6 +90,8 @@ pub(crate) struct WebViewInner { focused: bool, animating: bool, cursor: Cursor, + + rendering_group_id: RenderingGroupId, } impl Drop for WebViewInner { @@ -132,16 +134,18 @@ impl WebView { focused: false, animating: false, cursor: Cursor::Pointer, + rendering_group_id: builder.group_id.unwrap_or_default(), }))); let viewport_details = webview.viewport_details(); - servo.compositor.borrow_mut().add_webview( - Box::new(ServoRendererWebView { - weak_handle: webview.weak_handle(), - id, - }), - viewport_details, - ); + let wv = Box::new(ServoRendererWebView { + weak_handle: webview.weak_handle(), + id, + }); + servo + .compositor + .borrow_mut() + .add_webview(wv, viewport_details); servo .webviews @@ -213,6 +217,10 @@ impl WebView { self.inner().id } + pub fn rendering_group_id(&self) -> RenderingGroupId { + self.inner().rendering_group_id + } + pub fn load_status(&self) -> LoadStatus { self.inner().load_status } @@ -604,6 +612,10 @@ impl WebViewTrait for ServoRendererWebView { webview.set_animating(new_value); } } + + fn rendering_group_id(&self) -> Option { + WebView::from_weak_handle(&self.weak_handle).map(|webview| webview.rendering_group_id()) + } } pub struct WebViewBuilder<'servo> { @@ -613,6 +625,7 @@ pub struct WebViewBuilder<'servo> { url: Option, size: Option>, hidpi_scale_factor: Scale, + group_id: Option, } impl<'servo> WebViewBuilder<'servo> { @@ -624,6 +637,7 @@ impl<'servo> WebViewBuilder<'servo> { size: None, hidpi_scale_factor: Scale::new(1.0), delegate: Rc::new(DefaultWebViewDelegate), + group_id: None, } } diff --git a/components/shared/base/id.rs b/components/shared/base/id.rs index c0c9f203201..e8df1c25d13 100644 --- a/components/shared/base/id.rs +++ b/components/shared/base/id.rs @@ -10,7 +10,7 @@ use std::cell::Cell; use std::fmt; use std::marker::PhantomData; use std::num::NonZeroU32; -use std::sync::{Arc, LazyLock}; +use std::sync::{Arc, LazyLock, RwLock}; use malloc_size_of::MallocSizeOfOps; use malloc_size_of_derive::MallocSizeOf; @@ -302,10 +302,10 @@ thread_local!(pub static WEBVIEW_ID: Cell> = #[derive( Clone, Copy, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize, )] -pub struct WebViewId(BrowsingContextId); +pub struct WebViewId(RenderingGroupId, BrowsingContextId); -size_of_test!(WebViewId, 8); -size_of_test!(Option, 8); +size_of_test!(WebViewId, 12); +size_of_test!(Option, 12); impl fmt::Debug for WebViewId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -315,13 +315,17 @@ impl fmt::Debug for WebViewId { impl fmt::Display for WebViewId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "TopLevel{}", self.0) + write!(f, "RenderingGroup {}, TopLevel{}", self.0, self.1) } } impl WebViewId { pub fn new() -> WebViewId { - WebViewId(BrowsingContextId::new()) + WebViewId(RenderingGroupId::default(), BrowsingContextId::new()) + } + + pub fn new_with_rendering_group(rendering_group_id: RenderingGroupId) -> WebViewId { + WebViewId(rendering_group_id, BrowsingContextId::new()) } /// Each script and layout thread should have the top-level browsing context id installed, @@ -335,25 +339,31 @@ impl WebViewId { } pub fn mock_for_testing(browsing_context_id: BrowsingContextId) -> WebViewId { - WebViewId(browsing_context_id) + WebViewId(RenderingGroupId::default(), browsing_context_id) } } impl From for BrowsingContextId { fn from(id: WebViewId) -> BrowsingContextId { + id.1 + } +} + +impl From for RenderingGroupId { + fn from(id: WebViewId) -> RenderingGroupId { id.0 } } impl PartialEq for BrowsingContextId { fn eq(&self, rhs: &WebViewId) -> bool { - self.eq(&rhs.0) + self.eq(&rhs.1) } } impl PartialEq for WebViewId { fn eq(&self, rhs: &BrowsingContextId) -> bool { - self.0.eq(rhs) + self.1.eq(rhs) } } @@ -404,7 +414,10 @@ pub const TEST_BROWSING_CONTEXT_ID: BrowsingContextId = BrowsingContextId { index: TEST_BROWSING_CONTEXT_INDEX, }; -pub const TEST_WEBVIEW_ID: WebViewId = WebViewId(TEST_BROWSING_CONTEXT_ID); +pub const TEST_WEBVIEW_ID: WebViewId = WebViewId( + RenderingGroupId::mock_rendering_id(), + TEST_BROWSING_CONTEXT_ID, +); /// An id for a ScrollTreeNode in the ScrollTree. This contains both the index /// to the node in the tree's array of nodes as well as the corresponding SpatialId @@ -414,3 +427,36 @@ pub struct ScrollTreeNodeId { /// The index of this scroll tree node in the tree's array of nodes. pub index: usize, } + +#[derive( + Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Hash, Eq, Serialize, Deserialize, MallocSizeOf, +)] +pub struct RenderingGroupId(u32); + +impl fmt::Display for RenderingGroupId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "RenderingGroup: {}", self.0) + } +} + +static RENDER_GROUP_COUNTER: RwLock = RwLock::new(RenderingGroupId(1)); + +impl Default for RenderingGroupId { + fn default() -> Self { + Self(RENDER_GROUP_COUNTER.read().unwrap().0) + } +} + +impl RenderingGroupId { + const fn mock_rendering_id() -> RenderingGroupId { + RenderingGroupId(0) + } + + /// the new rendering group id. The first returned id will be 1. + pub fn new() -> RenderingGroupId { + let mut cur = RENDER_GROUP_COUNTER.write().unwrap(); + let n = RenderingGroupId(cur.0 + 1); + *cur = n; + n + } +} diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs index ebde61789fd..148328d949b 100644 --- a/components/shared/compositing/lib.rs +++ b/components/shared/compositing/lib.rs @@ -7,7 +7,7 @@ use std::fmt::{Debug, Error, Formatter}; use base::Epoch; -use base::id::{PipelineId, WebViewId}; +use base::id::{PipelineId, RenderingGroupId, WebViewId}; use crossbeam_channel::Sender; use embedder_traits::{AnimationState, EventLoopWaker, TouchEventResult}; use log::warn; @@ -143,6 +143,7 @@ pub enum CompositorMsg { usize, usize, GenericSender<(Vec, Vec)>, + RenderingGroupId, ), /// Add a font with the given data and font key. AddFont(FontKey, Arc, u32), @@ -372,12 +373,14 @@ impl CrossProcessCompositorApi { &self, number_of_font_keys: usize, number_of_font_instance_keys: usize, + rendering_group_id: RenderingGroupId, ) -> (Vec, Vec) { let (sender, receiver) = generic_channel::channel().expect("Could not create IPC channel"); let _ = self.0.send(CompositorMsg::GenerateFontKeys( number_of_font_keys, number_of_font_instance_keys, sender, + rendering_group_id, )); receiver.recv().unwrap() } @@ -608,6 +611,7 @@ impl From for ImageData { /// layer. pub trait WebViewTrait { fn id(&self) -> WebViewId; + fn rendering_group_id(&self) -> Option; fn screen_geometry(&self) -> Option; fn set_animating(&self, new_value: bool); } diff --git a/components/shared/fonts/Cargo.toml b/components/shared/fonts/Cargo.toml index be02bf7b7e9..e80e58958cc 100644 --- a/components/shared/fonts/Cargo.toml +++ b/components/shared/fonts/Cargo.toml @@ -13,6 +13,7 @@ path = "lib.rs" [dependencies] atomic_refcell = { workspace = true } +base = { workspace = true } ipc-channel = { workspace = true } log = { workspace = true } malloc_size_of = { workspace = true } diff --git a/components/shared/fonts/system_font_service_proxy.rs b/components/shared/fonts/system_font_service_proxy.rs index 8b32fcedde5..d2a4b2289d2 100644 --- a/components/shared/fonts/system_font_service_proxy.rs +++ b/components/shared/fonts/system_font_service_proxy.rs @@ -4,6 +4,7 @@ use std::collections::HashMap; +use base::id::RenderingGroupId; use ipc_channel::ipc::{self, IpcSender}; use log::debug; use malloc_size_of_derive::MallocSizeOf; @@ -25,14 +26,15 @@ pub enum SystemFontServiceMessage { IpcSender>, ), GetFontInstance( + RenderingGroupId, FontIdentifier, Au, FontInstanceFlags, Vec, IpcSender, ), - GetFontKey(IpcSender), - GetFontInstanceKey(IpcSender), + GetFontKey(RenderingGroupId, IpcSender), + GetFontInstanceKey(RenderingGroupId, IpcSender), CollectMemoryReport(ReportsChan), Exit(IpcSender<()>), Ping, @@ -85,10 +87,12 @@ impl SystemFontServiceProxy { size: Au, flags: FontInstanceFlags, variations: Vec, + rendering_group_id: RenderingGroupId, ) -> FontInstanceKey { let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel"); self.sender .send(SystemFontServiceMessage::GetFontInstance( + rendering_group_id, identifier, size, flags, @@ -151,22 +155,31 @@ impl SystemFontServiceProxy { templates } - pub fn generate_font_key(&self) -> FontKey { + pub fn generate_font_key(&self, rendering_group_id: RenderingGroupId) -> FontKey { let (result_sender, result_receiver) = ipc::channel().expect("failed to create IPC channel"); self.sender - .send(SystemFontServiceMessage::GetFontKey(result_sender)) + .send(SystemFontServiceMessage::GetFontKey( + rendering_group_id, + result_sender, + )) .expect("failed to send message to system font service"); result_receiver .recv() .expect("Failed to communicate with system font service.") } - pub fn generate_font_instance_key(&self) -> FontInstanceKey { + pub fn generate_font_instance_key( + &self, + rendering_group_id: RenderingGroupId, + ) -> FontInstanceKey { let (result_sender, result_receiver) = ipc::channel().expect("failed to create IPC channel"); self.sender - .send(SystemFontServiceMessage::GetFontInstanceKey(result_sender)) + .send(SystemFontServiceMessage::GetFontInstanceKey( + rendering_group_id, + result_sender, + )) .expect("failed to send message to system font service"); result_receiver .recv()