style: Unify font-family storage

This changes font-family storage to reuse the rust types, removing a
bunch of code while at it. This allows us to, for example, use a single
static font family for -moz-bullet and clone it, rather than creating a
lot of expensive copies.

Differential Revision: https://phabricator.services.mozilla.com/D118011
This commit is contained in:
Emilio Cobos Álvarez 2023-05-22 01:07:30 +02:00 committed by Oriol Brufau
parent 837e41c8eb
commit 67f9b97735
8 changed files with 180 additions and 294 deletions

View file

@ -308,11 +308,6 @@ impl_threadsafe_refcount!(
bindings::Gecko_AddRefnsIURIArbitraryThread,
bindings::Gecko_ReleasensIURIArbitraryThread
);
impl_threadsafe_refcount!(
structs::SharedFontList,
bindings::Gecko_AddRefSharedFontListArbitraryThread,
bindings::Gecko_ReleaseSharedFontListArbitraryThread
);
impl_threadsafe_refcount!(
structs::SheetLoadDataHolder,
bindings::Gecko_AddRefSheetLoadDataHolderArbitraryThread,

View file

@ -878,18 +878,19 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
// System fonts are all right, and should have the default font type
// set to none already, so bail out early.
if font.mFont.systemFont {
if font.mFont.family.is_system_font {
debug_assert_eq!(
font.mFont.fontlist.mDefaultFontType,
font.mFont.family.families.fallback,
GenericFontFamily::None
);
return;
}
let generic = font.mFont.family.families.single_generic().unwrap_or(GenericFontFamily::None);
let default_font_type = unsafe {
bindings::Gecko_nsStyleFont_ComputeDefaultFontType(
builder.device.document(),
font.mGenericID,
generic,
font.mLanguage.mRawPtr,
)
};
@ -899,15 +900,15 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
// cursive or fantasy, since they're ignored, see bug 789788), and
// we have a generic family to actually replace it with.
let prioritize_user_fonts = !use_document_fonts &&
default_font_type != GenericFontFamily::None &&
matches!(
font.mGenericID,
generic,
GenericFontFamily::None |
GenericFontFamily::Fantasy |
GenericFontFamily::Cursive
) &&
default_font_type != GenericFontFamily::None;
GenericFontFamily::Fantasy |
GenericFontFamily::Cursive
);
if !prioritize_user_fonts && default_font_type == font.mFont.fontlist.mDefaultFontType {
if !prioritize_user_fonts && default_font_type == font.mFont.family.families.fallback {
// Nothing to do.
return;
}
@ -915,9 +916,9 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
};
let font = builder.mutate_font().gecko_mut();
font.mFont.fontlist.mDefaultFontType = default_font_type;
font.mFont.family.families.fallback = default_font_type;
if prioritize_user_fonts {
unsafe { bindings::Gecko_nsStyleFont_PrioritizeUserFonts(font, default_font_type) }
font.mFont.family.families.prioritize_first_generic_or_prepend(default_font_type);
}
}

View file

@ -22,7 +22,6 @@ use crate::gecko_bindings::bindings::Gecko_CopyConstruct_${style_struct.gecko_ff
use crate::gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name};
% endfor
use crate::gecko_bindings::bindings::Gecko_CopyCounterStyle;
use crate::gecko_bindings::bindings::Gecko_CopyFontFamilyFrom;
use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom;
@ -848,52 +847,6 @@ fn static_assert() {
<% impl_font_settings("font_feature_settings", "gfxFontFeature", "FeatureTagValue", "i32", "u32") %>
<% impl_font_settings("font_variation_settings", "gfxFontVariation", "VariationValue", "f32", "f32") %>
pub fn set_font_family(&mut self, v: longhands::font_family::computed_value::T) {
use crate::values::computed::font::GenericFontFamily;
let is_system_font = v.is_system_font;
self.gecko.mFont.systemFont = is_system_font;
self.gecko.mGenericID = if is_system_font {
GenericFontFamily::None
} else {
v.families.single_generic().unwrap_or(GenericFontFamily::None)
};
self.gecko.mFont.fontlist.mFontlist.mBasePtr.set_move(
v.families.shared_font_list().clone()
);
// Fixed-up if needed in Cascade::fixup_font_stuff.
self.gecko.mFont.fontlist.mDefaultFontType = GenericFontFamily::None;
}
pub fn copy_font_family_from(&mut self, other: &Self) {
unsafe { Gecko_CopyFontFamilyFrom(&mut self.gecko.mFont, &other.gecko.mFont); }
self.gecko.mGenericID = other.gecko.mGenericID;
self.gecko.mFont.systemFont = other.gecko.mFont.systemFont;
}
pub fn reset_font_family(&mut self, other: &Self) {
self.copy_font_family_from(other)
}
pub fn clone_font_family(&self) -> longhands::font_family::computed_value::T {
use crate::values::computed::font::{FontFamily, SingleFontFamily, FontFamilyList};
let fontlist = &self.gecko.mFont.fontlist;
let shared_fontlist = unsafe { fontlist.mFontlist.mBasePtr.to_safe() };
let families = if shared_fontlist.mNames.is_empty() {
let default = SingleFontFamily::Generic(fontlist.mDefaultFontType);
FontFamilyList::new(Box::new([default]))
} else {
FontFamilyList::SharedFontList(shared_fontlist)
};
FontFamily {
families,
is_system_font: self.gecko.mFont.systemFont,
}
}
pub fn unzoom_fonts(&mut self, device: &Device) {
use crate::values::generics::NonNegative;
self.gecko.mSize = NonNegative(device.unzoom_text(self.gecko.mSize.0));
@ -1001,6 +954,8 @@ fn static_assert() {
${impl_simple("font_size_adjust", "mFont.sizeAdjust")}
${impl_simple("font_family", "mFont.family")}
#[allow(non_snake_case)]
pub fn set__x_lang(&mut self, v: longhands::_x_lang::computed_value::T) {
let ptr = v.0.as_ptr();

View file

@ -314,7 +314,6 @@ pub mod system_font {
//! variable reference. We may want to improve this behavior at some
//! point. See also https://github.com/w3c/csswg-drafts/issues/1586.
use crate::values::computed::font::GenericFontFamily;
use crate::properties::longhands;
use std::hash::{Hash, Hasher};
use crate::values::computed::{ToComputedValue, Context};
@ -356,7 +355,7 @@ pub mod system_font {
use std::mem;
use crate::values::computed::Percentage;
use crate::values::specified::font::KeywordInfo;
use crate::values::computed::font::{FontFamily, FontSize, FontStretch, FontStyle, FontFamilyList};
use crate::values::computed::font::{FontSize, FontStretch, FontStyle};
use crate::values::generics::NonNegative;
let mut system = mem::MaybeUninit::<nsFont>::uninit();
@ -375,12 +374,7 @@ pub mod system_font {
})));
let font_style = FontStyle::from_gecko(system.style);
let ret = ComputedSystemFont {
font_family: FontFamily {
families: FontFamilyList::SharedFontList(
unsafe { system.fontlist.mFontlist.mBasePtr.to_safe() }
),
is_system_font: true,
},
font_family: system.family.clone(),
font_size: FontSize {
size: NonNegative(cx.maybe_zoom_text(system.size.0)),
keyword_info: KeywordInfo::none()
@ -403,7 +397,6 @@ pub mod system_font {
font_variation_settings: longhands::font_variation_settings::get_initial_value(),
font_variant_alternates: longhands::font_variant_alternates::get_initial_value(),
system_font: *self,
default_font_type: system.fontlist.mDefaultFontType,
};
unsafe { bindings::Gecko_nsFont_Destroy(system); }
ret
@ -435,7 +428,6 @@ pub mod system_font {
pub ${name}: longhands::${name}::computed_value::T,
% endfor
pub system_font: SystemFont,
pub default_font_type: GenericFontFamily,
}
}

View file

@ -830,7 +830,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// the same font as its fallback ('list-style-type') in case it fails to load.
#[cfg(feature = "gecko")]
fn adjust_for_marker_pseudo(&mut self) {
use crate::values::computed::font::{FamilyName, FontFamily, FontFamilyList, FontFamilyNameSyntax, FontSynthesis, SingleFontFamily};
use crate::values::computed::font::{FontFamily, FontSynthesis};
use crate::values::computed::text::{LetterSpacing, WordSpacing};
let is_legacy_marker = self.style.pseudo.map_or(false, |p| p.is_marker()) &&
@ -840,14 +840,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
return;
}
if !self.style.flags.get().contains(ComputedValueFlags::HAS_AUTHOR_SPECIFIED_FONT_FAMILY) {
let moz_bullet_font_family = FontFamily {
families: FontFamilyList::new(Box::new([SingleFontFamily::FamilyName(FamilyName {
name: atom!("-moz-bullet-font"),
syntax: FontFamilyNameSyntax::Identifiers,
})])),
is_system_font: false,
};
self.style.mutate_font().set_font_family(moz_bullet_font_family);
self.style.mutate_font().set_font_family(FontFamily::moz_bullet().clone());
// FIXME(mats): We can remove this if support for font-synthesis is added to @font-face rules.
// Then we can add it to the @font-face rule in html.css instead.

View file

@ -4,8 +4,6 @@
//! Computed values for font properties
#[cfg(feature = "gecko")]
use crate::gecko_bindings::sugar::refptr::RefPtr;
#[cfg(feature = "gecko")]
use crate::gecko_bindings::{bindings, structs};
use crate::values::animated::ToAnimatedValue;
@ -26,13 +24,7 @@ use cssparser::{serialize_identifier, CssStringWriter, Parser};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
#[cfg(feature = "gecko")]
use std::mem::{self, ManuallyDrop};
#[cfg(feature = "servo")]
use std::slice;
use style_traits::{CssWriter, ParseError, ToCss};
#[cfg(feature = "gecko")]
use to_shmem::{self, SharedMemoryBuilder, ToShmem};
pub use crate::values::computed::Length as MozScriptMinSize;
pub use crate::values::specified::font::{FontSynthesis, MozScriptSizeMultiplier};
@ -183,6 +175,7 @@ impl ToAnimatedValue for FontSize {
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToResolvedValue)]
#[cfg_attr(feature = "servo", derive(Hash, MallocSizeOf, Serialize, Deserialize))]
/// Specifies a prioritized list of font family names or generic family names.
#[repr(C)]
pub struct FontFamily {
/// The actual list of family names.
pub families: FontFamilyList,
@ -190,27 +183,95 @@ pub struct FontFamily {
pub is_system_font: bool,
}
macro_rules! static_font_family {
($ident:ident, $family:expr) => {
lazy_static! {
static ref $ident: FontFamily = FontFamily {
families: FontFamilyList {
list: crate::ArcSlice::from_iter_leaked(std::iter::once($family)),
fallback: GenericFontFamily::None,
},
is_system_font: false,
};
}
};
}
impl FontFamily {
#[inline]
/// Get default font family as `serif` which is a generic font-family
pub fn serif() -> Self {
FontFamily {
families: FontFamilyList::new(Box::new([SingleFontFamily::Generic(
GenericFontFamily::Serif,
)])),
is_system_font: false,
Self::generic(GenericFontFamily::Serif).clone()
}
/// Returns the font family for `-moz-bullet-font`.
pub(crate) fn moz_bullet() -> &'static Self {
static_font_family!(MOZ_BULLET, SingleFontFamily::FamilyName(FamilyName {
name: atom!("-moz-bullet-font"),
syntax: FontFamilyNameSyntax::Identifiers,
}));
&*MOZ_BULLET
}
/// Returns a font family for a single system font.
pub fn for_system_font(name: &str) -> Self {
Self {
families: FontFamilyList {
list: crate::ArcSlice::from_iter(std::iter::once(SingleFontFamily::FamilyName(FamilyName {
name: Atom::from(name),
syntax: FontFamilyNameSyntax::Identifiers,
}))),
fallback: GenericFontFamily::None,
},
is_system_font: true,
}
}
/// Returns a generic font family.
pub fn generic(generic: GenericFontFamily) -> &'static Self {
macro_rules! generic_font_family {
($ident:ident, $family:ident) => {
static_font_family!($ident, SingleFontFamily::Generic(GenericFontFamily::$family))
}
}
generic_font_family!(SERIF, Serif);
generic_font_family!(SANS_SERIF, SansSerif);
generic_font_family!(MONOSPACE, Monospace);
generic_font_family!(CURSIVE, Cursive);
generic_font_family!(FANTASY, Fantasy);
generic_font_family!(MOZ_EMOJI, MozEmoji);
match generic {
GenericFontFamily::None => {
debug_assert!(false, "Bogus caller!");
&*SERIF
}
GenericFontFamily::Serif => &*SERIF,
GenericFontFamily::SansSerif => &*SANS_SERIF,
GenericFontFamily::Monospace => &*MONOSPACE,
GenericFontFamily::Cursive => &*CURSIVE,
GenericFontFamily::Fantasy => &*FANTASY,
GenericFontFamily::MozEmoji => &*MOZ_EMOJI,
}
}
}
#[cfg(feature = "gecko")]
impl MallocSizeOf for FontFamily {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
// SharedFontList objects are generally shared from the pointer
// stored in the specified value. So only count this if the
// SharedFontList is unshared.
let shared_font_list = self.families.shared_font_list().get();
unsafe { bindings::Gecko_SharedFontList_SizeOfIncludingThisIfUnshared(shared_font_list) }
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
use malloc_size_of::MallocUnconditionalSizeOf;
// SharedFontList objects are generally measured from the pointer stored
// in the specified value. So only count this if the SharedFontList is
// unshared.
let shared_font_list = &self.families.list;
if shared_font_list.is_unique() {
shared_font_list.unconditional_size_of(ops)
} else {
0
}
}
}
@ -220,7 +281,10 @@ impl ToCss for FontFamily {
W: fmt::Write,
{
let mut iter = self.families.iter();
iter.next().unwrap().to_css(dest)?;
match iter.next() {
Some(f) => f.to_css(dest)?,
None => return self.families.fallback.to_css(dest),
}
for family in iter {
dest.write_str(", ")?;
family.to_css(dest)?;
@ -229,15 +293,16 @@ impl ToCss for FontFamily {
}
}
/// The name of a font family of choice.
#[derive(
Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// The name of a font family of choice
#[repr(C)]
pub struct FamilyName {
/// Name of the font family
/// Name of the font family.
pub name: Atom,
/// Syntax of the font family
/// Syntax of the font family.
pub syntax: FontFamilyNameSyntax,
}
@ -291,11 +356,13 @@ pub enum FontFamilyNameSyntax {
Identifiers,
}
/// A set of faces that vary in weight, width or slope.
/// cbindgen:derive-mut-casts=true
#[derive(
Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToComputedValue, ToResolvedValue, ToShmem,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, Hash))]
/// A set of faces that vary in weight, width or slope.
#[repr(u8)]
pub enum SingleFontFamily {
/// The name of a font family of choice.
FamilyName(FamilyName),
@ -429,145 +496,57 @@ impl SingleFontFamily {
syntax: FontFamilyNameSyntax::Quoted,
})
}
#[cfg(feature = "gecko")]
/// Get the corresponding font-family with family name
fn from_font_family_name(family: &structs::FontFamilyName) -> SingleFontFamily {
if family.mName.mRawPtr.is_null() {
debug_assert_ne!(family.mGeneric, GenericFontFamily::None);
return SingleFontFamily::Generic(family.mGeneric);
}
let name = unsafe { Atom::from_raw(family.mName.mRawPtr) };
SingleFontFamily::FamilyName(FamilyName {
name,
syntax: family.mSyntax,
})
}
}
#[cfg(feature = "servo")]
#[derive(
Clone,
Debug,
Deserialize,
Eq,
Hash,
MallocSizeOf,
PartialEq,
Serialize,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
/// A list of SingleFontFamily
pub struct FontFamilyList(Box<[SingleFontFamily]>);
#[cfg(feature = "gecko")]
#[derive(Clone, Debug, ToComputedValue, ToResolvedValue)]
/// A list of SingleFontFamily
pub enum FontFamilyList {
/// A strong reference to a Gecko SharedFontList object.
SharedFontList(
#[compute(no_field_bound)]
#[resolve(no_field_bound)]
RefPtr<structs::SharedFontList>,
),
/// A font-family generic ID.
Generic(GenericFontFamily),
/// A list of font families.
#[derive(Clone, Debug, ToComputedValue, ToResolvedValue, ToShmem, PartialEq, Eq)]
#[repr(C)]
pub struct FontFamilyList {
/// The actual list of font families specified.
pub list: crate::ArcSlice<SingleFontFamily>,
/// A fallback font type (none, serif, or sans-serif, generally).
pub fallback: GenericFontFamily,
}
#[cfg(feature = "gecko")]
impl ToShmem for FontFamilyList {
fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
// In practice, the only SharedFontList objects we create from shared
// style sheets are ones with a single generic entry.
Ok(ManuallyDrop::new(match *self {
FontFamilyList::SharedFontList(ref r) => {
if !(r.mNames.len() == 1 && r.mNames[0].mName.mRawPtr.is_null()) {
return Err(String::from(
"ToShmem failed for FontFamilyList: cannot handle non-generic families",
));
}
FontFamilyList::Generic(r.mNames[0].mGeneric)
},
FontFamilyList::Generic(t) => FontFamilyList::Generic(t),
}))
}
}
#[cfg(feature = "gecko")]
impl PartialEq for FontFamilyList {
fn eq(&self, other: &FontFamilyList) -> bool {
let self_list = self.shared_font_list();
let other_list = other.shared_font_list();
if self_list.mNames.len() != other_list.mNames.len() {
return false;
}
for (a, b) in self_list.mNames.iter().zip(other_list.mNames.iter()) {
if a.mSyntax != b.mSyntax ||
a.mName.mRawPtr != b.mName.mRawPtr ||
a.mGeneric != b.mGeneric
{
return false;
}
}
true
}
}
#[cfg(feature = "gecko")]
impl Eq for FontFamilyList {}
impl FontFamilyList {
/// Return FontFamilyList with a vector of SingleFontFamily
#[cfg(feature = "servo")]
pub fn new(families: Box<[SingleFontFamily]>) -> FontFamilyList {
FontFamilyList(families)
/// Return iterator of SingleFontFamily
pub fn iter(&self) -> impl Iterator<Item = &SingleFontFamily> {
self.list.iter()
}
/// Return FontFamilyList with a vector of SingleFontFamily
#[cfg(feature = "gecko")]
pub fn new(families: Box<[SingleFontFamily]>) -> FontFamilyList {
let fontlist;
let names;
unsafe {
fontlist = bindings::Gecko_SharedFontList_Create();
names = &mut (*fontlist).mNames;
names.ensure_capacity(families.len());
/// Puts the fallback in the list if needed.
pub fn normalize(&mut self) {
if self.fallback == GenericFontFamily::None {
return;
}
let mut new_list = self.list.iter().cloned().collect::<Vec<_>>();
new_list.push(SingleFontFamily::Generic(self.fallback));
self.list = crate::ArcSlice::from_iter(new_list.into_iter());
}
/// If there's a generic font family on the list (which isn't cursive or
/// fantasy), then move it to the front of the list. Otherwise, prepend the
/// default generic.
pub (crate) fn prioritize_first_generic_or_prepend(&mut self, generic: GenericFontFamily) {
let index_of_first_generic = self.iter().position(|f| {
match *f {
SingleFontFamily::Generic(f) => f != GenericFontFamily::Cursive && f != GenericFontFamily::Fantasy,
_ => false,
}
});
if let Some(0) = index_of_first_generic {
return; // Already first
}
let mut new_list = self.list.iter().cloned().collect::<Vec<_>>();
let element_to_prepend = match index_of_first_generic {
Some(i) => new_list.remove(i),
None => SingleFontFamily::Generic(generic),
};
for family in families.iter() {
match *family {
SingleFontFamily::FamilyName(ref f) => unsafe {
bindings::Gecko_nsTArray_FontFamilyName_AppendNamed(
names,
f.name.as_ptr(),
f.syntax,
);
},
SingleFontFamily::Generic(family) => unsafe {
bindings::Gecko_nsTArray_FontFamilyName_AppendGeneric(names, family);
},
}
}
FontFamilyList::SharedFontList(unsafe { RefPtr::from_addrefed(fontlist) })
}
/// Return iterator of SingleFontFamily
#[cfg(feature = "servo")]
pub fn iter(&self) -> slice::Iter<SingleFontFamily> {
self.0.iter()
}
/// Return iterator of SingleFontFamily
#[cfg(feature = "gecko")]
pub fn iter(&self) -> FontFamilyNameIter {
FontFamilyNameIter {
names: &self.shared_font_list().mNames,
cur: 0,
}
new_list.insert(0, element_to_prepend);
self.list = crate::ArcSlice::from_iter(new_list.into_iter());
}
/// Return the generic ID if it is a single generic font
@ -580,46 +559,6 @@ impl FontFamilyList {
}
None
}
/// Return a reference to the Gecko SharedFontList.
#[cfg(feature = "gecko")]
pub fn shared_font_list(&self) -> &RefPtr<structs::SharedFontList> {
match *self {
FontFamilyList::SharedFontList(ref r) => r,
FontFamilyList::Generic(t) => {
unsafe {
// TODO(heycam): Should really add StaticRefPtr sugar.
let index = t as usize;
mem::transmute::<
&structs::StaticRefPtr<structs::SharedFontList>,
&RefPtr<structs::SharedFontList>,
>(&structs::SharedFontList_sSingleGenerics[index])
}
},
}
}
}
/// Iterator of FontFamily
#[cfg(feature = "gecko")]
pub struct FontFamilyNameIter<'a> {
names: &'a structs::nsTArray<structs::FontFamilyName>,
cur: usize,
}
#[cfg(feature = "gecko")]
impl<'a> Iterator for FontFamilyNameIter<'a> {
type Item = SingleFontFamily;
fn next(&mut self) -> Option<Self::Item> {
if self.cur < self.names.len() {
let item = SingleFontFamily::from_font_family_name(&self.names[self.cur]);
self.cur += 1;
Some(item)
} else {
None
}
}
}
/// Preserve the readability of text when font fallback occurs

View file

@ -6,8 +6,6 @@
#[cfg(feature = "gecko")]
use crate::context::QuirksMode;
#[cfg(feature = "gecko")]
use crate::gecko_bindings::bindings;
use crate::parser::{Parse, ParserContext};
use crate::values::computed::font::{FamilyName, FontFamilyList, FontStyleAngle, SingleFontFamily};
use crate::values::computed::{font as computed, Length, NonNegativeLength};
@ -24,7 +22,7 @@ use crate::values::CustomIdent;
use crate::Atom;
use cssparser::{Parser, Token};
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalSizeOf};
use std::fmt::{self, Write};
use style_traits::values::SequenceWriter;
use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
@ -687,9 +685,10 @@ impl FontFamily {
/// Parse a specified font-family value
pub fn parse_specified<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let values = input.parse_comma_separated(SingleFontFamily::parse)?;
Ok(FontFamily::Values(FontFamilyList::new(
values.into_boxed_slice(),
)))
Ok(FontFamily::Values(FontFamilyList {
list: crate::ArcSlice::from_iter(values.into_iter()),
fallback: computed::GenericFontFamily::None,
}))
}
}
@ -698,8 +697,8 @@ impl ToComputedValue for FontFamily {
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
FontFamily::Values(ref v) => computed::FontFamily {
families: v.clone(),
FontFamily::Values(ref list) => computed::FontFamily {
families: list.clone(),
is_system_font: false,
},
FontFamily::System(_) => self.compute_system(context),
@ -713,18 +712,12 @@ impl ToComputedValue for FontFamily {
#[cfg(feature = "gecko")]
impl MallocSizeOf for FontFamily {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
match *self {
FontFamily::Values(ref v) => {
// Although a SharedFontList object is refcounted, we always
// attribute its size to the specified value, as long as it's
// not a value in SharedFontList::sSingleGenerics.
if matches!(v, FontFamilyList::SharedFontList(_)) {
let ptr = v.shared_font_list().get();
unsafe { bindings::Gecko_SharedFontList_SizeOfIncludingThis(ptr) }
} else {
0
}
// Although the family list is refcounted, we always attribute
// its size to the specified value.
v.list.unconditional_size_of(ops)
},
FontFamily::System(_) => 0,
}

View file

@ -13,6 +13,8 @@ use std::ptr::NonNull;
use std::{iter, mem};
use to_shmem_derive::ToShmem;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalSizeOf};
/// A canary that we stash in ArcSlices.
///
/// Given we cannot use a zero-sized-type for the header, since well, C++
@ -137,6 +139,22 @@ impl<T> ArcSlice<T> {
std::mem::forget(empty);
ptr as *mut _
}
/// Returns whether there's only one reference to this ArcSlice.
pub fn is_unique(&self) -> bool {
self.0.with_arc(|arc| arc.is_unique())
}
}
impl<T: MallocSizeOf> MallocUnconditionalSizeOf for ArcSlice<T> {
#[allow(unsafe_code)]
fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
let mut size = unsafe { ops.malloc_size_of(self.0.heap_ptr()) };
for el in self.iter() {
size += el.size_of(ops);
}
size
}
}
/// The inner pointer of an ArcSlice<T>, to be sent via FFI.