diff options
author | Martin Robinson <mrobinson@igalia.com> | 2024-05-03 11:54:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-03 09:54:29 +0000 |
commit | 1c9120c293cc16c11637feb6003117d4093642b5 (patch) | |
tree | 86bdaaca73012869546e6c44e0a68e4e35021665 | |
parent | 160c7c0b0f061afa1277fa56cdd1d898379a8223 (diff) | |
download | servo-1c9120c293cc16c11637feb6003117d4093642b5.tar.gz servo-1c9120c293cc16c11637feb6003117d4093642b5.zip |
fonts: Add `MallocSizeOf` implementation for `FontContext` (#32206)
* fonts: Add `MallocSizeOf` implementation for `FontContext`
Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
* android: remove unused imports in font_list.rs
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
---------
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | components/gfx/Cargo.toml | 1 | ||||
-rw-r--r-- | components/gfx/font.rs | 44 | ||||
-rw-r--r-- | components/gfx/font_cache_thread.rs | 3 | ||||
-rw-r--r-- | components/gfx/font_context.rs | 42 | ||||
-rw-r--r-- | components/gfx/font_template.rs | 12 | ||||
-rw-r--r-- | components/gfx/platform/freetype/android/font_list.rs | 6 | ||||
-rw-r--r-- | components/gfx/platform/freetype/font_list.rs | 3 | ||||
-rw-r--r-- | components/gfx/platform/macos/font_list.rs | 3 | ||||
-rw-r--r-- | components/gfx/platform/windows/font_list.rs | 4 | ||||
-rw-r--r-- | components/gfx/text/glyph.rs | 11 | ||||
-rw-r--r-- | components/layout_thread/lib.rs | 6 | ||||
-rw-r--r-- | components/layout_thread_2020/lib.rs | 8 |
13 files changed, 119 insertions, 25 deletions
diff --git a/Cargo.lock b/Cargo.lock index 6c805a71f0d..98a10487c44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1993,6 +1993,7 @@ dependencies = [ "libc", "log", "malloc_size_of", + "malloc_size_of_derive", "net_traits", "parking_lot", "range", diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml index 5174f593572..f7153a155e3 100644 --- a/components/gfx/Cargo.toml +++ b/components/gfx/Cargo.toml @@ -28,6 +28,7 @@ lazy_static = { workspace = true } libc = { workspace = true } log = { workspace = true } malloc_size_of = { workspace = true } +malloc_size_of_derive = { workspace = true } net_traits = { workspace = true } parking_lot = { workspace = true } range = { path = "../range" } diff --git a/components/gfx/font.rs b/components/gfx/font.rs index fe899a4ea82..07db050eff2 100644 --- a/components/gfx/font.rs +++ b/components/gfx/font.rs @@ -13,6 +13,7 @@ use app_units::Au; use bitflags::bitflags; use euclid::default::{Point2D, Rect, Size2D}; use log::debug; +use malloc_size_of_derive::MallocSizeOf; use parking_lot::RwLock; use serde::{Deserialize, Serialize}; use servo_atoms::{atom, Atom}; @@ -116,7 +117,7 @@ pub trait FontTableMethods { fn buffer(&self) -> &[u8]; } -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct FontMetrics { pub underline_size: Au, pub underline_offset: Au, @@ -161,7 +162,7 @@ impl FontMetrics { /// template at a particular size, with a particular font-variant-caps applied, etc. This contrasts /// with `FontTemplateDescriptor` in that the latter represents only the parameters inherent in the /// font data (weight, stretch, etc.). -#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct FontDescriptor { pub weight: FontWeight, pub stretch: FontStretch, @@ -191,6 +192,19 @@ struct CachedShapeData { shaped_text: HashMap<ShapeCacheEntry, Arc<GlyphStore>>, } +impl malloc_size_of::MallocSizeOf for CachedShapeData { + fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize { + // Estimate the size of the shaped text cache. This will be smaller, because + // HashMap has some overhead, but we are mainly interested in the actual data. + let shaped_text_size = self + .shaped_text + .iter() + .map(|(key, value)| key.size_of(ops) + (*value).size_of(ops)) + .sum::<usize>(); + self.glyph_advances.size_of(ops) + self.glyph_indices.size_of(ops) + shaped_text_size + } +} + #[derive(Debug)] pub struct Font { pub handle: PlatformFont, @@ -207,6 +221,17 @@ pub struct Font { pub synthesized_small_caps: Option<FontRef>, } +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_key.size_of(ops) + } +} + impl Font { pub fn new( template: FontTemplateRef, @@ -428,10 +453,11 @@ pub type FontRef = Arc<Font>; /// A `FontGroup` is a prioritised list of fonts for a given set of font styles. It is used by /// `TextRun` to decide which font to render a character with. If none of the fonts listed in the /// styles are suitable, a fallback font may be used. -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] pub struct FontGroup { descriptor: FontDescriptor, families: SmallVec<[FontGroupFamily; 8]>, + #[ignore_malloc_size_of = "This measured in the FontContext font cache."] last_matching_fallback: Option<FontRef>, } @@ -584,9 +610,11 @@ impl FontGroup { /// `unicode-range` descriptors. In this case, font selection will select a single member /// that contains the necessary unicode character. Unicode ranges are specified by the /// [`FontGroupFamilyMember::template`] member. -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] struct FontGroupFamilyMember { + #[ignore_malloc_size_of = "This measured in the FontContext template cache."] template: FontTemplateRef, + #[ignore_malloc_size_of = "This measured in the FontContext font cache."] font: Option<FontRef>, loaded: bool, } @@ -595,7 +623,7 @@ struct FontGroupFamilyMember { /// families listed in the `font-family` CSS property. The corresponding font data is lazy-loaded, /// only if actually needed. A single `FontGroupFamily` can have multiple fonts, in the case that /// individual fonts only cover part of the Unicode range. -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] struct FontGroupFamily { family_descriptor: FontFamilyDescriptor, members: Option<Vec<FontGroupFamilyMember>>, @@ -700,7 +728,7 @@ pub fn get_and_reset_text_shaping_performance_counter() -> usize { } /// The scope within which we will look for a font. -#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum FontSearchScope { /// All fonts will be searched, including those specified via `@font-face` rules. Any, @@ -710,7 +738,7 @@ pub enum FontSearchScope { } /// A font family name used in font selection. -#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum FontFamilyName { /// A specific name such as `"Arial"` Specific(Atom), @@ -755,7 +783,7 @@ impl<'a> From<&'a str> for FontFamilyName { } /// The font family parameters for font selection. -#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct FontFamilyDescriptor { pub name: FontFamilyName, pub scope: FontSearchScope, diff --git a/components/gfx/font_cache_thread.rs b/components/gfx/font_cache_thread.rs index 22cd5edee47..aea32225e24 100644 --- a/components/gfx/font_cache_thread.rs +++ b/components/gfx/font_cache_thread.rs @@ -13,6 +13,7 @@ use atomic_refcell::AtomicRefCell; use gfx_traits::WebrenderApi; use ipc_channel::ipc::{self, IpcBytesSender, IpcReceiver, IpcSender}; use log::{debug, trace}; +use malloc_size_of_derive::MallocSizeOf; use net_traits::request::{Destination, Referrer, RequestBuilder}; use net_traits::{fetch_async, CoreResourceThread, FetchResponseMsg}; use serde::{Deserialize, Serialize}; @@ -46,7 +47,7 @@ pub struct FontTemplates { templates: Vec<FontTemplateRef>, } -#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum FontIdentifier { Local(LocalFontIdentifier), Web(ServoUrl), diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs index c08764f7a70..51bd239b8f2 100644 --- a/components/gfx/font_context.rs +++ b/components/gfx/font_context.rs @@ -10,6 +10,8 @@ use std::sync::Arc; use app_units::Au; use fnv::FnvHasher; use log::debug; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +use malloc_size_of_derive::MallocSizeOf; use parking_lot::{Mutex, RwLock}; use servo_arc::Arc as ServoArc; use style::computed_values::font_variant_caps::T as FontVariantCaps; @@ -55,6 +57,39 @@ pub struct FontContext<S: FontSource> { RwLock<HashMap<FontGroupCacheKey, Arc<RwLock<FontGroup>>, BuildHasherDefault<FnvHasher>>>, } +impl<S: FontSource> MallocSizeOf for FontContext<S> { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let font_cache_size = self + .font_cache + .read() + .iter() + .map(|(key, font)| { + key.size_of(ops) + font.as_ref().map_or(0, |font| (*font).size_of(ops)) + }) + .sum::<usize>(); + let font_template_cache_size = self + .font_template_cache + .read() + .iter() + .map(|(key, templates)| { + let templates_size = templates + .iter() + .map(|template| template.borrow().size_of(ops)) + .sum::<usize>(); + key.size_of(ops) + templates_size + }) + .sum::<usize>(); + let font_group_cache_size = self + .font_group_cache + .read() + .iter() + .map(|(key, font_group)| key.size_of(ops) + (*font_group.read()).size_of(ops)) + .sum::<usize>(); + + font_cache_size + font_template_cache_size + font_group_cache_size + } +} + impl<S: FontSource> FontContext<S> { pub fn new(font_source: S) -> FontContext<S> { #[allow(clippy::default_constructed_unit_structs)] @@ -226,20 +261,21 @@ impl<S: FontSource> FontContext<S> { } } -#[derive(Debug, Eq, Hash, PartialEq)] +#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)] struct FontCacheKey { font_identifier: FontIdentifier, font_descriptor: FontDescriptor, } -#[derive(Debug, Eq, Hash, PartialEq)] +#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)] struct FontTemplateCacheKey { font_descriptor: FontDescriptor, family_descriptor: FontFamilyDescriptor, } -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] struct FontGroupCacheKey { + #[ignore_malloc_size_of = "This is also stored as part of styling."] style: ServoArc<FontStyleStruct>, size: Au, } diff --git a/components/gfx/font_template.rs b/components/gfx/font_template.rs index 0af8aa75443..67f98b17c98 100644 --- a/components/gfx/font_template.rs +++ b/components/gfx/font_template.rs @@ -7,6 +7,7 @@ use std::ops::RangeInclusive; use std::sync::Arc; use atomic_refcell::AtomicRefCell; +use malloc_size_of_derive::MallocSizeOf; use serde::{Deserialize, Serialize}; use servo_url::ServoUrl; use style::computed_values::font_stretch::T as FontStretch; @@ -27,11 +28,12 @@ pub type FontTemplateRef = Arc<AtomicRefCell<FontTemplate>>; /// to be expanded or refactored when we support more of the font styling parameters. /// /// NB: If you change this, you will need to update `style::properties::compute_font_hash()`. -#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct FontTemplateDescriptor { pub weight: (FontWeight, FontWeight), pub stretch: (FontStretch, FontStretch), pub style: (FontStyle, FontStyle), + #[ignore_malloc_size_of = "MallocSizeOf does not yet support RangeInclusive"] pub unicode_range: Option<Vec<RangeInclusive<u32>>>, } @@ -134,6 +136,14 @@ pub struct FontTemplate { pub data: Option<Arc<Vec<u8>>>, } +impl malloc_size_of::MallocSizeOf for FontTemplate { + fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize { + self.identifier.size_of(ops) + + self.descriptor.size_of(ops) + + self.data.as_ref().map_or(0, |data| (*data).size_of(ops)) + } +} + impl Debug for FontTemplate { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.identifier.fmt(f) diff --git a/components/gfx/platform/freetype/android/font_list.rs b/components/gfx/platform/freetype/android/font_list.rs index c29069156c5..97276c35468 100644 --- a/components/gfx/platform/freetype/android/font_list.rs +++ b/components/gfx/platform/freetype/android/font_list.rs @@ -4,16 +4,16 @@ use std::fs::File; use std::io::Read; -use std::path::{Path, PathBuf}; +use std::path::Path; use log::warn; +use malloc_size_of_derive::MallocSizeOf; use serde::{Deserialize, Serialize}; use style::values::computed::{ FontStretch as StyleFontStretch, FontStyle as StyleFontStyle, FontWeight as StyleFontWeight, }; use style::Atom; use ucd::{Codepoint, UnicodeBlock}; -use webrender_api::NativeFontHandle; use super::xml::{Attribute, Node}; use crate::font_template::{FontTemplate, FontTemplateDescriptor}; @@ -24,7 +24,7 @@ lazy_static::lazy_static! { } /// An identifier for a local font on Android systems. -#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct LocalFontIdentifier { /// The path to the font. pub path: Atom, diff --git a/components/gfx/platform/freetype/font_list.rs b/components/gfx/platform/freetype/font_list.rs index a958248f8c5..1462b37ca56 100644 --- a/components/gfx/platform/freetype/font_list.rs +++ b/components/gfx/platform/freetype/font_list.rs @@ -24,6 +24,7 @@ use fontconfig_sys::{ }; use libc::{c_char, c_int}; use log::debug; +use malloc_size_of_derive::MallocSizeOf; use serde::{Deserialize, Serialize}; use style::values::computed::{FontStretch, FontStyle, FontWeight}; use style::Atom; @@ -34,7 +35,7 @@ use crate::font_template::{FontTemplate, FontTemplateDescriptor}; use crate::text::util::is_cjk; /// An identifier for a local font on systems using Freetype. -#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct LocalFontIdentifier { /// The path to the font. pub path: Atom, diff --git a/components/gfx/platform/macos/font_list.rs b/components/gfx/platform/macos/font_list.rs index d4063576316..272916e2d07 100644 --- a/components/gfx/platform/macos/font_list.rs +++ b/components/gfx/platform/macos/font_list.rs @@ -7,6 +7,7 @@ use std::io::Read; use std::path::Path; use log::debug; +use malloc_size_of_derive::MallocSizeOf; use serde::{Deserialize, Serialize}; use style::Atom; use ucd::{Codepoint, UnicodeBlock}; @@ -20,7 +21,7 @@ use crate::text::util::unicode_plane; /// An identifier for a local font on a MacOS system. These values comes from the CoreText /// CTFontCollection. Note that `path` here is required. We do not load fonts that do not /// have paths. -#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct LocalFontIdentifier { pub postscript_name: Atom, pub path: Atom, diff --git a/components/gfx/platform/windows/font_list.rs b/components/gfx/platform/windows/font_list.rs index fa96c7de226..9cfdbfd988e 100644 --- a/components/gfx/platform/windows/font_list.rs +++ b/components/gfx/platform/windows/font_list.rs @@ -6,6 +6,7 @@ use std::hash::Hash; use std::sync::Arc; use dwrote::{Font, FontCollection, FontDescriptor, FontStretch, FontStyle}; +use malloc_size_of_derive::MallocSizeOf; use serde::{Deserialize, Serialize}; use style::values::computed::{FontStyle as StyleFontStyle, FontWeight as StyleFontWeight}; use style::values::specified::font::FontStretchKeyword; @@ -31,9 +32,10 @@ where } /// An identifier for a local font on a Windows system. -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct LocalFontIdentifier { /// The FontDescriptor of this font. + #[ignore_malloc_size_of = "dwrote does not support MallocSizeOf"] pub font_descriptor: Arc<FontDescriptor>, } diff --git a/components/gfx/text/glyph.rs b/components/gfx/text/glyph.rs index 3b42af4b4d5..5be5af3708a 100644 --- a/components/gfx/text/glyph.rs +++ b/components/gfx/text/glyph.rs @@ -10,6 +10,7 @@ use app_units::Au; use euclid::default::Point2D; pub use gfx_traits::ByteIndex; use log::debug; +use malloc_size_of_derive::MallocSizeOf; use range::{self, EachIndex, Range, RangeIndex}; use serde::{Deserialize, Serialize}; @@ -21,7 +22,7 @@ use serde::{Deserialize, Serialize}; /// In the uncommon case (multiple glyphs per unicode character, large glyph index/advance, or /// glyph offsets), we pack the glyph count into GlyphEntry, and store the other glyph information /// in DetailedGlyphStore. -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct GlyphEntry { value: u32, } @@ -145,7 +146,7 @@ impl GlyphEntry { // Stores data for a detailed glyph, in the case that several glyphs // correspond to one character, or the glyph's data couldn't be packed. -#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)] struct DetailedGlyph { id: GlyphId, // glyph's advance, in the text's direction (LTR or RTL) @@ -164,7 +165,7 @@ impl DetailedGlyph { } } -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] struct DetailedGlyphRecord { // source string offset/GlyphEntry offset in the TextRun entry_offset: ByteIndex, @@ -188,7 +189,7 @@ impl PartialOrd for DetailedGlyphRecord { // until a lookup is actually performed; this matches the expected // usage pattern of setting/appending all the detailed glyphs, and // then querying without setting. -#[derive(Clone, Deserialize, Serialize)] +#[derive(Clone, Deserialize, MallocSizeOf, Serialize)] struct DetailedGlyphStore { // TODO(pcwalton): Allocation of this buffer is expensive. Consider a small-vector // optimization. @@ -416,7 +417,7 @@ impl<'a> GlyphInfo<'a> { /// | +---+---+ | /// +---------------------------------------------+ /// ~~~ -#[derive(Clone, Deserialize, Serialize)] +#[derive(Clone, Deserialize, MallocSizeOf, Serialize)] pub struct GlyphStore { // TODO(pcwalton): Allocation of this buffer is expensive. Consider a small-vector // optimization. diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 589a2744364..b242ecd934f 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -530,6 +530,12 @@ impl Layout for LayoutThread { kind: ReportKind::ExplicitJemallocHeapSize, size: self.stylist.size_of(&mut ops), }); + + reports.push(Report { + path: path![formatted_url, "layout-thread", "font-context"], + kind: ReportKind::ExplicitJemallocHeapSize, + size: self.font_context.size_of(&mut ops), + }); } fn reflow(&mut self, script_reflow: script_layout_interface::ScriptReflow) { diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index c23e6f55fd4..170d7f165ec 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -425,7 +425,7 @@ impl Layout for LayoutThread { // malloc_enclosing_size_of function. let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None); - // FIXME(njn): Just measuring the display tree for now. + // TODO: Measure more than just display list, stylist, and font context. let formatted_url = &format!("url({})", self.url); reports.push(Report { path: path![formatted_url, "layout-thread", "display-list"], @@ -438,6 +438,12 @@ impl Layout for LayoutThread { kind: ReportKind::ExplicitJemallocHeapSize, size: self.stylist.size_of(&mut ops), }); + + reports.push(Report { + path: path![formatted_url, "layout-thread", "font-context"], + kind: ReportKind::ExplicitJemallocHeapSize, + size: self.font_context.size_of(&mut ops), + }); } fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) { |