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 <Narfinger@users.noreply.github.com>

Testing: This should be covered by WPT tests and normal browsing
behavior works fine.

---------

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
This commit is contained in:
Narfinger 2025-09-29 12:01:56 +02:00 committed by GitHub
parent 32b656adf4
commit e64f021550
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 240 additions and 63 deletions

1
Cargo.lock generated
View file

@ -2817,6 +2817,7 @@ name = "fonts_traits"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"atomic_refcell", "atomic_refcell",
"base",
"dwrote", "dwrote",
"ipc-channel", "ipc-channel",
"log", "log",

View file

@ -14,7 +14,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use base::Epoch; use base::Epoch;
use base::cross_process_instant::CrossProcessInstant; use base::cross_process_instant::CrossProcessInstant;
use base::generic_channel::{GenericSender, RoutedReceiver}; use base::generic_channel::{GenericSender, RoutedReceiver};
use base::id::{PipelineId, WebViewId}; use base::id::{PipelineId, RenderingGroupId, WebViewId};
use bitflags::bitflags; use bitflags::bitflags;
use compositing_traits::display_list::{CompositorDisplayListInfo, ScrollTree, ScrollType}; use compositing_traits::display_list::{CompositorDisplayListInfo, ScrollTree, ScrollType};
use compositing_traits::rendering_context::RenderingContext; use compositing_traits::rendering_context::RenderingContext;
@ -792,11 +792,13 @@ impl IOCompositor {
number_of_font_keys, number_of_font_keys,
number_of_font_instance_keys, number_of_font_instance_keys,
result_sender, result_sender,
rendering_group_id,
) => { ) => {
self.handle_generate_font_keys( self.handle_generate_font_keys(
number_of_font_keys, number_of_font_keys,
number_of_font_instance_keys, number_of_font_instance_keys,
result_sender, result_sender,
rendering_group_id,
); );
}, },
CompositorMsg::Viewport(webview_id, viewport_description) => { CompositorMsg::Viewport(webview_id, viewport_description) => {
@ -834,11 +836,13 @@ impl IOCompositor {
number_of_font_keys, number_of_font_keys,
number_of_font_instance_keys, number_of_font_instance_keys,
result_sender, result_sender,
rendering_group_id,
) => { ) => {
self.handle_generate_font_keys( self.handle_generate_font_keys(
number_of_font_keys, number_of_font_keys,
number_of_font_instance_keys, number_of_font_instance_keys,
result_sender, result_sender,
rendering_group_id,
); );
}, },
CompositorMsg::NewWebRenderFrameReady(..) => { CompositorMsg::NewWebRenderFrameReady(..) => {
@ -852,11 +856,13 @@ impl IOCompositor {
} }
/// Generate the font keys and send them to the `result_sender`. /// Generate the font keys and send them to the `result_sender`.
/// Currently `RenderingGroupId` is not used.
fn handle_generate_font_keys( fn handle_generate_font_keys(
&self, &self,
number_of_font_keys: usize, number_of_font_keys: usize,
number_of_font_instance_keys: usize, number_of_font_instance_keys: usize,
result_sender: GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>, result_sender: GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
_rendering_group_id: RenderingGroupId,
) { ) {
let font_keys = (0..number_of_font_keys) let font_keys = (0..number_of_font_keys)
.map(|_| self.global.borrow().webrender_api.generate_font_key()) .map(|_| self.global.borrow().webrender_api.generate_font_key())

View file

@ -12,6 +12,7 @@ use std::time::Instant;
use std::{iter, str}; use std::{iter, str};
use app_units::Au; use app_units::Au;
use base::id::RenderingGroupId;
use bitflags::bitflags; use bitflags::bitflags;
use euclid::default::{Point2D, Rect}; use euclid::default::{Point2D, Rect};
use euclid::num::Zero; use euclid::num::Zero;
@ -21,6 +22,7 @@ use malloc_size_of_derive::MallocSizeOf;
use parking_lot::RwLock; use parking_lot::RwLock;
use read_fonts::tables::os2::{Os2, SelectionFlags}; use read_fonts::tables::os2::{Os2, SelectionFlags};
use read_fonts::types::Tag; use read_fonts::types::Tag;
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use smallvec::SmallVec; use smallvec::SmallVec;
use style::computed_values::font_variant_caps; use style::computed_values::font_variant_caps;
@ -223,7 +225,7 @@ pub struct Font {
shaper: OnceLock<Shaper>, shaper: OnceLock<Shaper>,
cached_shape_data: RwLock<CachedShapeData>, cached_shape_data: RwLock<CachedShapeData>,
pub(crate) font_instance_key: OnceLock<FontInstanceKey>, font_instance_key: RwLock<FxHashMap<RenderingGroupId, FontInstanceKey>>,
/// If this is a synthesized small caps font, then this font reference is for /// 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 /// 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 { fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
// TODO: Collect memory usage for platform fonts and for shapers. // TODO: Collect memory usage for platform fonts and for shapers.
// This skips the template, because they are already stored in the template cache. // This skips the template, because they are already stored in the template cache.
self.metrics.size_of(ops) + self.metrics.size_of(ops) +
self.descriptor.size_of(ops) + self.descriptor.size_of(ops) +
self.cached_shape_data.read().size_of(ops) + self.cached_shape_data.read().size_of(ops) +
self.font_instance_key self.font_instance_key
.get() .read()
.map_or(0, |key| key.size_of(ops)) .values()
.map(|key| key.size_of(ops))
.sum::<usize>()
} }
} }
@ -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 *self
.font_instance_key .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 /// Return the data for this `Font`. Note that this is currently highly inefficient for system

View file

@ -10,7 +10,7 @@ use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use app_units::Au; use app_units::Au;
use base::id::WebViewId; use base::id::{RenderingGroupId, WebViewId};
use compositing_traits::CrossProcessCompositorApi; use compositing_traits::CrossProcessCompositorApi;
use fonts_traits::{ use fonts_traits::{
CSSFontFaceDescriptors, FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef, 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() { match font.template.identifier() {
FontIdentifier::Local(_) => self.system_font_service_proxy.get_system_font_instance( FontIdentifier::Local(_) => self.system_font_service_proxy.get_system_font_instance(
font.template.identifier(), font.template.identifier(),
font.descriptor.pt_size, font.descriptor.pt_size,
font.webrender_font_instance_flags(), font.webrender_font_instance_flags(),
font.variations().to_owned(), font.variations().to_owned(),
rendering_group_id,
), ),
FontIdentifier::Web(_) => self.create_web_font_instance( FontIdentifier::Web(_) => self.create_web_font_instance(
font.template.clone(), font.template.clone(),
font.descriptor.pt_size, font.descriptor.pt_size,
font.webrender_font_instance_flags(), font.webrender_font_instance_flags(),
font.variations().to_owned(), font.variations().to_owned(),
rendering_group_id,
), ),
} }
} }
@ -300,6 +306,7 @@ impl FontContext {
pt_size: Au, pt_size: Au,
flags: FontInstanceFlags, flags: FontInstanceFlags,
variations: Vec<FontVariation>, variations: Vec<FontVariation>,
rendering_group_id: RenderingGroupId,
) -> FontInstanceKey { ) -> FontInstanceKey {
let identifier = font_template.identifier().clone(); let identifier = font_template.identifier().clone();
let font_data = self let font_data = self
@ -310,7 +317,9 @@ impl FontContext {
.write() .write()
.entry(identifier.clone()) .entry(identifier.clone())
.or_insert_with(|| { .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( self.compositor_api.lock().add_font(
font_key, font_key,
font_data.as_ipc_shared_memory(), font_data.as_ipc_shared_memory(),
@ -324,7 +333,9 @@ impl FontContext {
.write() .write()
.entry((font_key, pt_size, variations.clone())) .entry((font_key, pt_size, variations.clone()))
.or_insert_with(|| { .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( self.compositor_api.lock().add_font_instance(
font_instance_key, font_instance_key,
font_key, font_key,

View file

@ -8,6 +8,7 @@ use std::collections::HashMap;
use std::thread; use std::thread;
use app_units::Au; use app_units::Au;
use base::id::RenderingGroupId;
use compositing_traits::CrossProcessCompositorApi; use compositing_traits::CrossProcessCompositorApi;
use fonts_traits::{ use fonts_traits::{
FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef, LowercaseFontFamilyName, FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef, LowercaseFontFamilyName,
@ -20,6 +21,7 @@ use profile_traits::mem::{
ProcessReports, ProfilerChan, Report, ReportKind, ReportsChan, perform_memory_report, ProcessReports, ProfilerChan, Report, ReportKind, ReportsChan, perform_memory_report,
}; };
use profile_traits::path; use profile_traits::path;
use rustc_hash::FxHashMap;
use servo_config::pref; use servo_config::pref;
use style::values::computed::font::{GenericFontFamily, SingleFontFamily}; use style::values::computed::font::{GenericFontFamily, SingleFontFamily};
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, FontVariation}; use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, FontVariation};
@ -48,21 +50,23 @@ pub struct SystemFontService {
port: IpcReceiver<SystemFontServiceMessage>, port: IpcReceiver<SystemFontServiceMessage>,
local_families: FontStore, local_families: FontStore,
compositor_api: CrossProcessCompositorApi, compositor_api: CrossProcessCompositorApi,
webrender_fonts: HashMap<FontIdentifier, FontKey>, // keys already have the IdNamespace for webrender
font_instances: HashMap<(FontKey, Au, Vec<FontVariation>), FontInstanceKey>, webrender_fonts: HashMap<(FontIdentifier, RenderingGroupId), FontKey>,
font_instances: HashMap<(FontKey, Au, Vec<FontVariation>, RenderingGroupId), FontInstanceKey>,
generic_fonts: ResolvedGenericFontFamilies, generic_fonts: ResolvedGenericFontFamilies,
/// This is an optimization that allows the [`SystemFontService`] to send font data to /// This is an optimization that allows the [`SystemFontService`] to send font data to
/// the compositor asynchronously for creating WebRender fonts, while immediately /// the compositor asynchronously for creating WebRender fonts, while immediately
/// returning a font key for that data. Once the free keys are exhausted, the /// returning a font key for that data. Once the free keys are exhausted, the
/// [`SystemFontService`] will fetch a new batch. /// [`SystemFontService`] will fetch a new batch.
free_font_keys: Vec<FontKey>, /// TODO: We currently do not delete the free keys if a `WebView` is removed.
free_font_keys: FxHashMap<RenderingGroupId, Vec<FontKey>>,
/// This is an optimization that allows the [`SystemFontService`] to create WebRender font /// This is an optimization that allows the [`SystemFontService`] to create WebRender font
/// instances in the compositor asynchronously, while immediately returning a font /// instances in the compositor asynchronously, while immediately returning a font
/// instance key for the instance. Once the free keys are exhausted, the /// instance key for the instance. Once the free keys are exhausted, the
/// [`SystemFontService`] will fetch a new batch. /// [`SystemFontService`] will fetch a new batch.
free_font_instance_keys: Vec<FontInstanceKey>, free_font_instance_keys: FxHashMap<RenderingGroupId, Vec<FontInstanceKey>>,
} }
impl SystemFontService { impl SystemFontService {
@ -88,7 +92,7 @@ impl SystemFontService {
free_font_instance_keys: Default::default(), free_font_instance_keys: Default::default(),
}; };
cache.fetch_new_keys(); cache.fetch_new_keys(RenderingGroupId::default());
cache.refresh_local_families(); cache.refresh_local_families();
memory_profiler_sender.run_with_memory_reporting( memory_profiler_sender.run_with_memory_reporting(
@ -120,22 +124,41 @@ impl SystemFontService {
result_sender.send(self.get_font_templates(font_descriptor, font_family)); result_sender.send(self.get_font_templates(font_descriptor, font_family));
}, },
SystemFontServiceMessage::GetFontInstance( SystemFontServiceMessage::GetFontInstance(
rendering_group_id,
identifier, identifier,
pt_size, pt_size,
flags, flags,
variations, variations,
result, result,
) => { ) => {
let _ = let _ = result.send(self.get_font_instance(
result.send(self.get_font_instance(identifier, pt_size, flags, variations)); rendering_group_id,
identifier,
pt_size,
flags,
variations,
));
}, },
SystemFontServiceMessage::GetFontKey(result_sender) => { SystemFontServiceMessage::GetFontKey(rendering_group_id, result_sender) => {
self.fetch_new_keys(); self.fetch_new_keys(rendering_group_id);
let _ = result_sender.send(self.free_font_keys.pop().unwrap());
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) => { SystemFontServiceMessage::GetFontInstanceKey(rendering_group_id, result_sender) => {
self.fetch_new_keys(); self.fetch_new_keys(rendering_group_id);
let _ = result_sender.send(self.free_font_instance_keys.pop().unwrap()); 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) => { SystemFontServiceMessage::CollectMemoryReport(report_sender) => {
self.collect_memory_report(report_sender); self.collect_memory_report(report_sender);
@ -161,8 +184,16 @@ impl SystemFontService {
} }
#[servo_tracing::instrument(skip_all)] #[servo_tracing::instrument(skip_all)]
fn fetch_new_keys(&mut self) { fn fetch_new_keys(&mut self, rendering_group_id: RenderingGroupId) {
if !self.free_font_keys.is_empty() && !self.free_font_instance_keys.is_empty() { 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; return;
} }
@ -171,9 +202,15 @@ impl SystemFontService {
let (mut new_font_keys, mut new_font_instance_keys) = self.compositor_api.fetch_font_keys( 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_KEYS_BATCH_SIZE - self.free_font_keys.len(),
FREE_FONT_INSTANCE_KEYS_BATCH_SIZE - self.free_font_instance_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 self.free_font_instance_keys
.entry(rendering_group_id)
.or_default()
.append(&mut new_font_instance_keys); .append(&mut new_font_instance_keys);
} }
@ -228,20 +265,26 @@ impl SystemFontService {
#[servo_tracing::instrument(skip_all)] #[servo_tracing::instrument(skip_all)]
fn get_font_instance( fn get_font_instance(
&mut self, &mut self,
rendering_group_id: RenderingGroupId,
identifier: FontIdentifier, identifier: FontIdentifier,
pt_size: Au, pt_size: Au,
flags: FontInstanceFlags, flags: FontInstanceFlags,
variations: Vec<FontVariation>, variations: Vec<FontVariation>,
) -> FontInstanceKey { ) -> FontInstanceKey {
self.fetch_new_keys(); self.fetch_new_keys(rendering_group_id);
let compositor_api = &self.compositor_api; let compositor_api = &self.compositor_api;
let webrender_fonts = &mut self.webrender_fonts; let webrender_fonts = &mut self.webrender_fonts;
let font_key = *webrender_fonts let font_key = *webrender_fonts
.entry(identifier.clone()) .entry((identifier.clone(), rendering_group_id))
.or_insert_with(|| { .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 { let FontIdentifier::Local(local_font_identifier) = identifier else {
unreachable!("Should never have a web font in the system font service"); unreachable!("Should never have a web font in the system font service");
}; };
@ -252,9 +295,14 @@ impl SystemFontService {
*self *self
.font_instances .font_instances
.entry((font_key, pt_size, variations.clone())) .entry((font_key, pt_size, variations.clone(), rendering_group_id))
.or_insert_with(|| { .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( compositor_api.add_font_instance(
font_instance_key, font_instance_key,
font_key, font_key,

View file

@ -130,11 +130,11 @@ mod font_context {
.collect(), .collect(),
); );
}, },
SystemFontServiceMessage::GetFontInstanceKey(result_sender) | SystemFontServiceMessage::GetFontInstanceKey(_, result_sender) |
SystemFontServiceMessage::GetFontInstance(_, _, _, _, result_sender) => { SystemFontServiceMessage::GetFontInstance(_, _, _, _, _, result_sender) => {
let _ = result_sender.send(FontInstanceKey(IdNamespace(0), 0)); let _ = result_sender.send(FontInstanceKey(IdNamespace(0), 0));
}, },
SystemFontServiceMessage::GetFontKey(result_sender) => { SystemFontServiceMessage::GetFontKey(_, result_sender) => {
let _ = result_sender.send(FontKey(IdNamespace(0), 0)); let _ = result_sender.send(FontKey(IdNamespace(0), 0));
}, },
SystemFontServiceMessage::Exit(result_sender) => { SystemFontServiceMessage::Exit(result_sender) => {

View file

@ -63,6 +63,7 @@ impl<'dom> ModernContainerJob<'dom> {
true, /* has_first_formatted_line */ true, /* has_first_formatted_line */
false, /* is_single_line_text_box */ false, /* is_single_line_text_box */
builder.info.style.to_bidi_level(), builder.info.style.to_bidi_level(),
builder.context.rendering_group_id,
)?; )?;
let block_formatting_context = BlockFormattingContext::from_block_container( let block_formatting_context = BlockFormattingContext::from_block_container(

View file

@ -5,6 +5,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use base::id::RenderingGroupId;
use embedder_traits::UntrustedNodeAddress; use embedder_traits::UntrustedNodeAddress;
use euclid::Size2D; use euclid::Size2D;
use fonts::FontContext; use fonts::FontContext;
@ -44,6 +45,8 @@ pub(crate) struct LayoutContext<'a> {
/// An [`ImageResolver`] used for resolving images during box and fragment /// An [`ImageResolver`] used for resolving images during box and fragment
/// tree construction. Later passed to display list construction. /// tree construction. Later passed to display list construction.
pub image_resolver: Arc<ImageResolver>, pub image_resolver: Arc<ImageResolver>,
pub rendering_group_id: RenderingGroupId,
} }
pub enum ResolvedImage<'a> { pub enum ResolvedImage<'a> {

View file

@ -230,6 +230,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
!self.have_already_seen_first_line_for_text_indent, !self.have_already_seen_first_line_for_text_indent,
self.info.node.is_single_line_text_input(), self.info.node.is_single_line_text_input(),
self.info.style.to_bidi_level(), self.info.style.to_bidi_level(),
self.context.rendering_group_id,
) )
} }

View file

@ -5,6 +5,7 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::char::{ToLowercase, ToUppercase}; use std::char::{ToLowercase, ToUppercase};
use base::id::RenderingGroupId;
use icu_segmenter::WordSegmenter; use icu_segmenter::WordSegmenter;
use itertools::izip; use itertools::izip;
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse; use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
@ -475,6 +476,7 @@ impl InlineFormattingContextBuilder {
has_first_formatted_line, has_first_formatted_line,
/* is_single_line_text_input = */ false, /* is_single_line_text_input = */ false,
default_bidi_level, default_bidi_level,
layout_context.rendering_group_id,
) )
} }
@ -485,6 +487,7 @@ impl InlineFormattingContextBuilder {
has_first_formatted_line: bool, has_first_formatted_line: bool,
is_single_line_text_input: bool, is_single_line_text_input: bool,
default_bidi_level: Level, default_bidi_level: Level,
rendering_group_id: RenderingGroupId,
) -> Option<InlineFormattingContext> { ) -> Option<InlineFormattingContext> {
if self.is_empty { if self.is_empty {
return None; return None;
@ -498,6 +501,7 @@ impl InlineFormattingContextBuilder {
has_first_formatted_line, has_first_formatted_line,
is_single_line_text_input, is_single_line_text_input,
default_bidi_level, default_bidi_level,
rendering_group_id,
)) ))
} }
} }

View file

@ -79,6 +79,7 @@ use std::mem;
use std::rc::Rc; use std::rc::Rc;
use app_units::{Au, MAX_AU}; use app_units::{Au, MAX_AU};
use base::id::RenderingGroupId;
use bitflags::bitflags; use bitflags::bitflags;
use construct::InlineFormattingContextBuilder; use construct::InlineFormattingContextBuilder;
use fonts::{ByteIndex, FontMetrics, GlyphStore}; use fonts::{ByteIndex, FontMetrics, GlyphStore};
@ -1681,6 +1682,7 @@ impl InlineFormattingContext {
has_first_formatted_line: bool, has_first_formatted_line: bool,
is_single_line_text_input: bool, is_single_line_text_input: bool,
starting_bidi_level: Level, starting_bidi_level: Level,
rendering_group_id: RenderingGroupId,
) -> Self { ) -> Self {
// This is to prevent a double borrow. // This is to prevent a double borrow.
let text_content: String = builder.text_segments.into_iter().collect(); let text_content: String = builder.text_segments.into_iter().collect();
@ -1699,6 +1701,7 @@ impl InlineFormattingContext {
&mut new_linebreaker, &mut new_linebreaker,
&mut font_metrics, &mut font_metrics,
&bidi_info, &bidi_info,
rendering_group_id,
); );
}, },
InlineItem::StartInlineBox(inline_box) => { InlineItem::StartInlineBox(inline_box) => {
@ -1711,6 +1714,7 @@ impl InlineFormattingContext {
&font, &font,
&mut font_metrics, &mut font_metrics,
&layout_context.font_context, &layout_context.font_context,
rendering_group_id,
)); ));
} }
}, },

View file

@ -6,6 +6,7 @@ use std::mem;
use std::ops::Range; use std::ops::Range;
use app_units::Au; use app_units::Au;
use base::id::RenderingGroupId;
use base::text::is_bidi_control; use base::text::is_bidi_control;
use fonts::{ use fonts::{
FontContext, FontRef, GlyphRun, LAST_RESORT_GLYPH_ADVANCE, ShapingFlags, ShapingOptions, FontContext, FontRef, GlyphRun, LAST_RESORT_GLYPH_ADVANCE, ShapingFlags, ShapingOptions,
@ -96,6 +97,7 @@ impl TextRunSegment {
bidi_level: Level, bidi_level: Level,
fonts: &[FontKeyAndMetrics], fonts: &[FontKeyAndMetrics],
font_context: &FontContext, font_context: &FontContext,
rendering_group_id: RenderingGroupId,
) -> bool { ) -> bool {
fn is_specific(script: Script) -> bool { fn is_specific(script: Script) -> bool {
script != Script::Common && script != Script::Inherited script != Script::Common && script != Script::Inherited
@ -106,7 +108,7 @@ impl TextRunSegment {
} }
let current_font_key_and_metrics = &fonts[self.font_index]; 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 new_font.descriptor.pt_size != current_font_key_and_metrics.pt_size
{ {
return false; return false;
@ -371,6 +373,7 @@ impl TextRun {
linebreaker: &mut LineBreaker, linebreaker: &mut LineBreaker,
font_cache: &mut Vec<FontKeyAndMetrics>, font_cache: &mut Vec<FontKeyAndMetrics>,
bidi_info: &BidiInfo, bidi_info: &BidiInfo,
rendering_group_id: RenderingGroupId,
) { ) {
let parent_style = self.inline_styles.style.borrow().clone(); let parent_style = self.inline_styles.style.borrow().clone();
let inherited_text_style = parent_style.get_inherited_text().clone(); let inherited_text_style = parent_style.get_inherited_text().clone();
@ -403,6 +406,7 @@ impl TextRun {
font_cache, font_cache,
bidi_info, bidi_info,
&parent_style, &parent_style,
rendering_group_id,
) )
.into_iter() .into_iter()
.map(|(mut segment, font)| { .map(|(mut segment, font)| {
@ -451,6 +455,7 @@ impl TextRun {
font_cache: &mut Vec<FontKeyAndMetrics>, font_cache: &mut Vec<FontKeyAndMetrics>,
bidi_info: &BidiInfo, bidi_info: &BidiInfo,
parent_style: &Arc<ComputedValues>, parent_style: &Arc<ComputedValues>,
rendering_group_id: RenderingGroupId,
) -> Vec<(TextRunSegment, FontRef)> { ) -> Vec<(TextRunSegment, FontRef)> {
let font_group = font_context.font_group(parent_style.clone_font()); let font_group = font_context.font_group(parent_style.clone_font());
let mut current: Option<(TextRunSegment, FontRef)> = None; let mut current: Option<(TextRunSegment, FontRef)> = None;
@ -497,12 +502,13 @@ impl TextRun {
bidi_level, bidi_level,
font_cache, font_cache,
font_context, font_context,
rendering_group_id,
) { ) {
continue; 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 // 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 // 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. // of those cases, just use the first font.
if current.is_none() { if current.is_none() {
current = font_group.write().first(font_context).map(|font| { 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( TextRunSegment::new(
font_index, font_index,
@ -597,8 +604,9 @@ pub(super) fn add_or_get_font(
font: &FontRef, font: &FontRef,
ifc_fonts: &mut Vec<FontKeyAndMetrics>, ifc_fonts: &mut Vec<FontKeyAndMetrics>,
font_context: &FontContext, font_context: &FontContext,
rendering_group_id: RenderingGroupId,
) -> usize { ) -> 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() { for (index, ifc_font_info) in ifc_fonts.iter().enumerate() {
if ifc_font_info.key == font_instance_key && if ifc_font_info.key == font_instance_key &&
ifc_font_info.pt_size == font.descriptor.pt_size ifc_font_info.pt_size == font.descriptor.pt_size

View file

@ -997,6 +997,7 @@ impl LayoutThread {
iframe_sizes: Mutex::default(), iframe_sizes: Mutex::default(),
use_rayon: rayon_pool.is_some(), use_rayon: rayon_pool.is_some(),
image_resolver: image_resolver.clone(), image_resolver: image_resolver.clone(),
rendering_group_id: self.webview_id.into(),
}; };
let restyle = reflow_request let restyle = reflow_request

View file

@ -7,7 +7,7 @@ use std::hash::Hash;
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use std::time::Duration; use std::time::Duration;
use base::id::WebViewId; use base::id::{RenderingGroupId, WebViewId};
use compositing::IOCompositor; use compositing::IOCompositor;
use compositing_traits::WebViewTrait; use compositing_traits::WebViewTrait;
use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection}; use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection};
@ -90,6 +90,8 @@ pub(crate) struct WebViewInner {
focused: bool, focused: bool,
animating: bool, animating: bool,
cursor: Cursor, cursor: Cursor,
rendering_group_id: RenderingGroupId,
} }
impl Drop for WebViewInner { impl Drop for WebViewInner {
@ -132,16 +134,18 @@ impl WebView {
focused: false, focused: false,
animating: false, animating: false,
cursor: Cursor::Pointer, cursor: Cursor::Pointer,
rendering_group_id: builder.group_id.unwrap_or_default(),
}))); })));
let viewport_details = webview.viewport_details(); let viewport_details = webview.viewport_details();
servo.compositor.borrow_mut().add_webview( let wv = Box::new(ServoRendererWebView {
Box::new(ServoRendererWebView {
weak_handle: webview.weak_handle(), weak_handle: webview.weak_handle(),
id, id,
}), });
viewport_details, servo
); .compositor
.borrow_mut()
.add_webview(wv, viewport_details);
servo servo
.webviews .webviews
@ -213,6 +217,10 @@ impl WebView {
self.inner().id self.inner().id
} }
pub fn rendering_group_id(&self) -> RenderingGroupId {
self.inner().rendering_group_id
}
pub fn load_status(&self) -> LoadStatus { pub fn load_status(&self) -> LoadStatus {
self.inner().load_status self.inner().load_status
} }
@ -604,6 +612,10 @@ impl WebViewTrait for ServoRendererWebView {
webview.set_animating(new_value); webview.set_animating(new_value);
} }
} }
fn rendering_group_id(&self) -> Option<RenderingGroupId> {
WebView::from_weak_handle(&self.weak_handle).map(|webview| webview.rendering_group_id())
}
} }
pub struct WebViewBuilder<'servo> { pub struct WebViewBuilder<'servo> {
@ -613,6 +625,7 @@ pub struct WebViewBuilder<'servo> {
url: Option<Url>, url: Option<Url>,
size: Option<PhysicalSize<u32>>, size: Option<PhysicalSize<u32>>,
hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>, hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
group_id: Option<RenderingGroupId>,
} }
impl<'servo> WebViewBuilder<'servo> { impl<'servo> WebViewBuilder<'servo> {
@ -624,6 +637,7 @@ impl<'servo> WebViewBuilder<'servo> {
size: None, size: None,
hidpi_scale_factor: Scale::new(1.0), hidpi_scale_factor: Scale::new(1.0),
delegate: Rc::new(DefaultWebViewDelegate), delegate: Rc::new(DefaultWebViewDelegate),
group_id: None,
} }
} }

View file

@ -10,7 +10,7 @@ use std::cell::Cell;
use std::fmt; use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use std::sync::{Arc, LazyLock}; use std::sync::{Arc, LazyLock, RwLock};
use malloc_size_of::MallocSizeOfOps; use malloc_size_of::MallocSizeOfOps;
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
@ -302,10 +302,10 @@ thread_local!(pub static WEBVIEW_ID: Cell<Option<WebViewId>> =
#[derive( #[derive(
Clone, Copy, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize, 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!(WebViewId, 12);
size_of_test!(Option<WebViewId>, 8); size_of_test!(Option<WebViewId>, 12);
impl fmt::Debug for WebViewId { impl fmt::Debug for WebViewId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -315,13 +315,17 @@ impl fmt::Debug for WebViewId {
impl fmt::Display for WebViewId { impl fmt::Display for WebViewId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "TopLevel{}", self.0) write!(f, "RenderingGroup {}, TopLevel{}", self.0, self.1)
} }
} }
impl WebViewId { impl WebViewId {
pub fn new() -> 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, /// 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 { pub fn mock_for_testing(browsing_context_id: BrowsingContextId) -> WebViewId {
WebViewId(browsing_context_id) WebViewId(RenderingGroupId::default(), browsing_context_id)
} }
} }
impl From<WebViewId> for BrowsingContextId { impl From<WebViewId> for BrowsingContextId {
fn from(id: WebViewId) -> BrowsingContextId { fn from(id: WebViewId) -> BrowsingContextId {
id.1
}
}
impl From<WebViewId> for RenderingGroupId {
fn from(id: WebViewId) -> RenderingGroupId {
id.0 id.0
} }
} }
impl PartialEq<WebViewId> for BrowsingContextId { impl PartialEq<WebViewId> for BrowsingContextId {
fn eq(&self, rhs: &WebViewId) -> bool { fn eq(&self, rhs: &WebViewId) -> bool {
self.eq(&rhs.0) self.eq(&rhs.1)
} }
} }
impl PartialEq<BrowsingContextId> for WebViewId { impl PartialEq<BrowsingContextId> for WebViewId {
fn eq(&self, rhs: &BrowsingContextId) -> bool { 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, 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 /// 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 /// 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. /// The index of this scroll tree node in the tree's array of nodes.
pub index: usize, 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<RenderingGroupId> = 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
}
}

View file

@ -7,7 +7,7 @@
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
use base::Epoch; use base::Epoch;
use base::id::{PipelineId, WebViewId}; use base::id::{PipelineId, RenderingGroupId, WebViewId};
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use embedder_traits::{AnimationState, EventLoopWaker, TouchEventResult}; use embedder_traits::{AnimationState, EventLoopWaker, TouchEventResult};
use log::warn; use log::warn;
@ -143,6 +143,7 @@ pub enum CompositorMsg {
usize, usize,
usize, usize,
GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>, GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
RenderingGroupId,
), ),
/// Add a font with the given data and font key. /// Add a font with the given data and font key.
AddFont(FontKey, Arc<IpcSharedMemory>, u32), AddFont(FontKey, Arc<IpcSharedMemory>, u32),
@ -372,12 +373,14 @@ impl CrossProcessCompositorApi {
&self, &self,
number_of_font_keys: usize, number_of_font_keys: usize,
number_of_font_instance_keys: usize, number_of_font_instance_keys: usize,
rendering_group_id: RenderingGroupId,
) -> (Vec<FontKey>, Vec<FontInstanceKey>) { ) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
let (sender, receiver) = generic_channel::channel().expect("Could not create IPC channel"); let (sender, receiver) = generic_channel::channel().expect("Could not create IPC channel");
let _ = self.0.send(CompositorMsg::GenerateFontKeys( let _ = self.0.send(CompositorMsg::GenerateFontKeys(
number_of_font_keys, number_of_font_keys,
number_of_font_instance_keys, number_of_font_instance_keys,
sender, sender,
rendering_group_id,
)); ));
receiver.recv().unwrap() receiver.recv().unwrap()
} }
@ -608,6 +611,7 @@ impl From<SerializableImageData> for ImageData {
/// layer. /// layer.
pub trait WebViewTrait { pub trait WebViewTrait {
fn id(&self) -> WebViewId; fn id(&self) -> WebViewId;
fn rendering_group_id(&self) -> Option<RenderingGroupId>;
fn screen_geometry(&self) -> Option<ScreenGeometry>; fn screen_geometry(&self) -> Option<ScreenGeometry>;
fn set_animating(&self, new_value: bool); fn set_animating(&self, new_value: bool);
} }

View file

@ -13,6 +13,7 @@ path = "lib.rs"
[dependencies] [dependencies]
atomic_refcell = { workspace = true } atomic_refcell = { workspace = true }
base = { workspace = true }
ipc-channel = { workspace = true } ipc-channel = { workspace = true }
log = { workspace = true } log = { workspace = true }
malloc_size_of = { workspace = true } malloc_size_of = { workspace = true }

View file

@ -4,6 +4,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use base::id::RenderingGroupId;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use log::debug; use log::debug;
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
@ -25,14 +26,15 @@ pub enum SystemFontServiceMessage {
IpcSender<Vec<FontTemplate>>, IpcSender<Vec<FontTemplate>>,
), ),
GetFontInstance( GetFontInstance(
RenderingGroupId,
FontIdentifier, FontIdentifier,
Au, Au,
FontInstanceFlags, FontInstanceFlags,
Vec<FontVariation>, Vec<FontVariation>,
IpcSender<FontInstanceKey>, IpcSender<FontInstanceKey>,
), ),
GetFontKey(IpcSender<FontKey>), GetFontKey(RenderingGroupId, IpcSender<FontKey>),
GetFontInstanceKey(IpcSender<FontInstanceKey>), GetFontInstanceKey(RenderingGroupId, IpcSender<FontInstanceKey>),
CollectMemoryReport(ReportsChan), CollectMemoryReport(ReportsChan),
Exit(IpcSender<()>), Exit(IpcSender<()>),
Ping, Ping,
@ -85,10 +87,12 @@ impl SystemFontServiceProxy {
size: Au, size: Au,
flags: FontInstanceFlags, flags: FontInstanceFlags,
variations: Vec<FontVariation>, variations: Vec<FontVariation>,
rendering_group_id: RenderingGroupId,
) -> FontInstanceKey { ) -> FontInstanceKey {
let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel"); let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel");
self.sender self.sender
.send(SystemFontServiceMessage::GetFontInstance( .send(SystemFontServiceMessage::GetFontInstance(
rendering_group_id,
identifier, identifier,
size, size,
flags, flags,
@ -151,22 +155,31 @@ impl SystemFontServiceProxy {
templates templates
} }
pub fn generate_font_key(&self) -> FontKey { pub fn generate_font_key(&self, rendering_group_id: RenderingGroupId) -> FontKey {
let (result_sender, result_receiver) = let (result_sender, result_receiver) =
ipc::channel().expect("failed to create IPC channel"); ipc::channel().expect("failed to create IPC channel");
self.sender self.sender
.send(SystemFontServiceMessage::GetFontKey(result_sender)) .send(SystemFontServiceMessage::GetFontKey(
rendering_group_id,
result_sender,
))
.expect("failed to send message to system font service"); .expect("failed to send message to system font service");
result_receiver result_receiver
.recv() .recv()
.expect("Failed to communicate with system font service.") .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) = let (result_sender, result_receiver) =
ipc::channel().expect("failed to create IPC channel"); ipc::channel().expect("failed to create IPC channel");
self.sender self.sender
.send(SystemFontServiceMessage::GetFontInstanceKey(result_sender)) .send(SystemFontServiceMessage::GetFontInstanceKey(
rendering_group_id,
result_sender,
))
.expect("failed to send message to system font service"); .expect("failed to send message to system font service");
result_receiver result_receiver
.recv() .recv()