servo: Merge #19366 - style: Move font-family outside of mako (from CYBAI:font-family-out-of-mako); r=emilio

This is a sub-PR of #19015
Besides, this is the last PR for `font.mako.rs`! 🎉
r? emilio

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #19355
- [x] These changes do not require tests

Source-Repo: https://github.com/servo/servo
Source-Revision: 8f61fde3907f2dde3e697791ccfb9a4d86d1a48c

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 1e3e438583f418932f96140dc434e1a64e4aceff
This commit is contained in:
CYBAI 2017-11-25 13:06:31 -06:00
parent b17aa7c172
commit 4fb0a4619e
14 changed files with 595 additions and 569 deletions

View File

@ -26,7 +26,7 @@ use std::sync::{Arc, Mutex};
use std::thread;
use std::u32;
use style::font_face::{EffectiveSources, Source};
use style::properties::longhands::font_family::computed_value::{FontFamily, FamilyName};
use style::values::computed::font::{SingleFontFamily, FamilyName};
use webrender_api;
/// A list of font templates that make up a given font family.
@ -105,7 +105,7 @@ impl FontTemplates {
/// Commands that the FontContext sends to the font cache thread.
#[derive(Debug, Deserialize, Serialize)]
pub enum Command {
GetFontTemplate(FontFamily, FontTemplateDescriptor, IpcSender<Reply>),
GetFontTemplate(SingleFontFamily, FontTemplateDescriptor, IpcSender<Reply>),
GetLastResortFontTemplate(FontTemplateDescriptor, IpcSender<Reply>),
GetFontInstance(webrender_api::FontKey, Au, IpcSender<webrender_api::FontInstanceKey>),
AddWebFont(LowercaseString, EffectiveSources, IpcSender<()>),
@ -124,7 +124,7 @@ pub enum Reply {
struct FontCache {
port: IpcReceiver<Command>,
channel_to_self: IpcSender<Command>,
generic_fonts: HashMap<FontFamily, LowercaseString>,
generic_fonts: HashMap<SingleFontFamily, LowercaseString>,
local_families: HashMap<LowercaseString, FontTemplates>,
web_families: HashMap<LowercaseString, FontTemplates>,
font_context: FontContextHandle,
@ -134,17 +134,17 @@ struct FontCache {
font_instances: HashMap<(webrender_api::FontKey, Au), webrender_api::FontInstanceKey>,
}
fn populate_generic_fonts() -> HashMap<FontFamily, LowercaseString> {
fn populate_generic_fonts() -> HashMap<SingleFontFamily, LowercaseString> {
let mut generic_fonts = HashMap::with_capacity(5);
append_map(&mut generic_fonts, FontFamily::Generic(atom!("serif")), "Times New Roman");
append_map(&mut generic_fonts, FontFamily::Generic(atom!("sans-serif")), SANS_SERIF_FONT_FAMILY);
append_map(&mut generic_fonts, FontFamily::Generic(atom!("cursive")), "Apple Chancery");
append_map(&mut generic_fonts, FontFamily::Generic(atom!("fantasy")), "Papyrus");
append_map(&mut generic_fonts, FontFamily::Generic(atom!("monospace")), "Menlo");
append_map(&mut generic_fonts, SingleFontFamily::Generic(atom!("serif")), "Times New Roman");
append_map(&mut generic_fonts, SingleFontFamily::Generic(atom!("sans-serif")), SANS_SERIF_FONT_FAMILY);
append_map(&mut generic_fonts, SingleFontFamily::Generic(atom!("cursive")), "Apple Chancery");
append_map(&mut generic_fonts, SingleFontFamily::Generic(atom!("fantasy")), "Papyrus");
append_map(&mut generic_fonts, SingleFontFamily::Generic(atom!("monospace")), "Menlo");
fn append_map(generic_fonts: &mut HashMap<FontFamily, LowercaseString>,
font_family: FontFamily,
fn append_map(generic_fonts: &mut HashMap<SingleFontFamily, LowercaseString>,
font_family: SingleFontFamily,
mapped_name: &str) {
let family_name = {
let opt_system_default = system_default_family(font_family.name());
@ -320,7 +320,7 @@ impl FontCache {
});
}
fn transform_family(&self, family: &FontFamily) -> LowercaseString {
fn transform_family(&self, family: &SingleFontFamily) -> LowercaseString {
match self.generic_fonts.get(family) {
None => LowercaseString::new(family.name()),
Some(mapped_family) => (*mapped_family).clone()
@ -351,7 +351,7 @@ impl FontCache {
}
}
fn find_font_in_web_family(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
fn find_font_in_web_family(&mut self, family: &SingleFontFamily, desc: &FontTemplateDescriptor)
-> Option<Arc<FontTemplateData>> {
let family_name = LowercaseString::new(family.name());
@ -385,7 +385,7 @@ impl FontCache {
}
}
fn find_font_template(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
fn find_font_template(&mut self, family: &SingleFontFamily, desc: &FontTemplateDescriptor)
-> Option<FontTemplateInfo> {
let template = self.find_font_in_web_family(family, desc)
.or_else(|| {
@ -453,7 +453,7 @@ impl FontCacheThread {
}
}
pub fn find_font_template(&self, family: FontFamily, desc: FontTemplateDescriptor)
pub fn find_font_template(&self, family: SingleFontFamily, desc: FontTemplateDescriptor)
-> Option<FontTemplateInfo> {
let (response_chan, response_port) =
ipc::channel().expect("failed to create IPC channel");

View File

@ -587,9 +587,9 @@ impl LayoutElementHelpers for LayoutDom<Element> {
shared_lock,
PropertyDeclaration::FontFamily(
font_family::SpecifiedValue::Values(
font_family::computed_value::FontFamilyList::new(vec![
font_family::computed_value::FontFamily::from_atom(
font_family)])))));
computed::font::FontFamilyList::new(Box::new([
computed::font::SingleFontFamily::from_atom(
font_family)]))))));
}
let font_size = self.downcast::<HTMLFontElement>().and_then(|this| this.get_size());

View File

@ -10,7 +10,6 @@
#[cfg(feature = "gecko")]
use computed_values::{font_feature_settings, font_stretch, font_style, font_weight};
use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use cssparser::{SourceLocation, CowRcStr};
use error_reporting::{ContextualParseError, ParseErrorReporter};
@ -23,6 +22,7 @@ use selectors::parser::SelectorParseErrorKind;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use style_traits::{Comma, OneOrMoreSeparated, ParseError, StyleParseErrorKind, ToCss};
use values::computed::font::FamilyName;
use values::specified::url::SpecifiedUrl;
/// A source for a font-face rule.

View File

@ -6,7 +6,6 @@
use byteorder::{BigEndian, WriteBytesExt};
use computed_values::{font_feature_settings, font_stretch, font_style, font_weight};
use computed_values::font_family::FamilyName;
use counter_style;
use cssparser::UnicodeRange;
use font_face::{FontFaceRuleData, Source, FontDisplay, FontWeight};
@ -19,6 +18,7 @@ use nsstring::nsString;
use properties::longhands::font_language_override;
use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard};
use std::{fmt, str};
use values::computed::font::FamilyName;
use values::generics::FontSettings;
/// A @font-face rule

View File

@ -59,7 +59,7 @@ use std::mem::{forget, uninitialized, transmute, zeroed};
use std::{cmp, ops, ptr};
use values::{self, Auto, CustomIdent, Either, KeyframesName, None_};
use values::computed::{NonNegativeLength, ToComputedValue, Percentage};
use values::computed::font::FontSize;
use values::computed::font::{FontSize, SingleFontFamily};
use values::computed::effects::{BoxShadow, Filter, SimpleShadow};
use computed_values::border_style;
@ -2441,7 +2441,7 @@ fn static_assert() {
0
}
pub fn font_family_at(&self, _: usize) -> longhands::font_family::computed_value::FontFamily {
pub fn font_family_at(&self, _: usize) -> SingleFontFamily {
unimplemented!()
}
@ -2457,9 +2457,7 @@ fn static_assert() {
pub fn clone_font_family(&self) -> longhands::font_family::computed_value::T {
use gecko_bindings::structs::FontFamilyType;
use properties::longhands::font_family::computed_value;
use properties::longhands::font_family::computed_value::FontFamily;
use properties::longhands::font_family::computed_value::FontFamilyList;
use values::computed::font::{FontFamily, SingleFontFamily, FontFamilyList};
let fontlist = &self.gecko.mFont.fontlist;
let shared_fontlist = unsafe { fontlist.mFontlist.mBasePtr.to_safe() };
@ -2467,16 +2465,16 @@ fn static_assert() {
if shared_fontlist.mNames.is_empty() {
let default = match fontlist.mDefaultFontType {
FontFamilyType::eFamily_serif => {
FontFamily::Generic(atom!("serif"))
SingleFontFamily::Generic(atom!("serif"))
}
FontFamilyType::eFamily_sans_serif => {
FontFamily::Generic(atom!("sans-serif"))
SingleFontFamily::Generic(atom!("sans-serif"))
}
_ => panic!("Default generic must be serif or sans-serif"),
};
computed_value::T(FontFamilyList::new(vec![default]))
FontFamily(FontFamilyList::new(Box::new([default])))
} else {
computed_value::T(FontFamilyList(shared_fontlist))
FontFamily(FontFamilyList(shared_fontlist))
}
}

View File

@ -7,536 +7,12 @@
<% data.new_style_struct("Font", inherited=True) %>
<%def name="nongecko_unreachable()">
%if product == "gecko":
${caller.body()}
%else:
unreachable!()
%endif
</%def>
<%helpers:longhand name="font-family" animation_value_type="discrete"
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER"
spec="https://drafts.csswg.org/css-fonts/#propdef-font-family">
#[cfg(feature = "gecko")] use gecko_bindings::bindings;
#[cfg(feature = "gecko")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use properties::longhands::system_font::SystemFont;
use self::computed_value::{FontFamily, FontFamilyList, FamilyName};
use std::fmt;
use style_traits::ToCss;
pub mod computed_value {
use cssparser::{CssStringWriter, Parser, serialize_identifier};
#[cfg(feature = "gecko")] use gecko_bindings::{bindings, structs};
#[cfg(feature = "gecko")] use gecko_bindings::sugar::refptr::RefPtr;
#[cfg(feature = "gecko")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use std::fmt::{self, Write};
#[cfg(feature = "gecko")] use std::hash::{Hash, Hasher};
#[cfg(feature = "servo")] use std::slice;
use style_traits::{ToCss, ParseError};
use Atom;
pub use self::FontFamily as SingleComputedValue;
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum FontFamily {
FamilyName(FamilyName),
Generic(Atom),
}
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct FamilyName {
pub name: Atom,
pub syntax: FamilyNameSyntax,
}
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum FamilyNameSyntax {
/// The family name was specified in a quoted form, e.g. "Font Name"
/// or 'Font Name'.
Quoted,
/// The family name was specified in an unquoted form as a sequence of
/// identifiers. The `String` is the serialization of the sequence of
/// identifiers.
Identifiers(String),
}
impl FontFamily {
#[inline]
pub fn atom(&self) -> &Atom {
match *self {
FontFamily::FamilyName(ref family_name) => &family_name.name,
FontFamily::Generic(ref name) => name,
}
}
#[inline]
#[cfg(not(feature = "gecko"))] // Gecko can't borrow atoms as UTF-8.
pub fn name(&self) -> &str {
self.atom()
}
#[cfg(not(feature = "gecko"))] // Gecko can't borrow atoms as UTF-8.
pub fn from_atom(input: Atom) -> FontFamily {
match input {
atom!("serif") |
atom!("sans-serif") |
atom!("cursive") |
atom!("fantasy") |
atom!("monospace") => {
return FontFamily::Generic(input)
}
_ => {}
}
match_ignore_ascii_case! { &input,
"serif" => return FontFamily::Generic(atom!("serif")),
"sans-serif" => return FontFamily::Generic(atom!("sans-serif")),
"cursive" => return FontFamily::Generic(atom!("cursive")),
"fantasy" => return FontFamily::Generic(atom!("fantasy")),
"monospace" => return FontFamily::Generic(atom!("monospace")),
_ => {}
}
// We don't know if it's quoted or not. So we set it to
// quoted by default.
FontFamily::FamilyName(FamilyName {
name: input,
syntax: FamilyNameSyntax::Quoted,
})
}
/// Parse a font-family value
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(value) = input.try(|i| i.expect_string_cloned()) {
return Ok(FontFamily::FamilyName(FamilyName {
name: Atom::from(&*value),
syntax: FamilyNameSyntax::Quoted,
}))
}
let first_ident = input.expect_ident()?.clone();
// FIXME(bholley): The fast thing to do here would be to look up the
// string (as lowercase) in the static atoms table. We don't have an
// API to do that yet though, so we do the simple thing for now.
let mut css_wide_keyword = false;
match_ignore_ascii_case! { &first_ident,
"serif" => return Ok(FontFamily::Generic(atom!("serif"))),
"sans-serif" => return Ok(FontFamily::Generic(atom!("sans-serif"))),
"cursive" => return Ok(FontFamily::Generic(atom!("cursive"))),
"fantasy" => return Ok(FontFamily::Generic(atom!("fantasy"))),
"monospace" => return Ok(FontFamily::Generic(atom!("monospace"))),
% if product == "gecko":
"-moz-fixed" => return Ok(FontFamily::Generic(atom!("-moz-fixed"))),
% endif
// https://drafts.csswg.org/css-fonts/#propdef-font-family
// "Font family names that happen to be the same as a keyword value
// (`inherit`, `serif`, `sans-serif`, `monospace`, `fantasy`, and `cursive`)
// must be quoted to prevent confusion with the keywords with the same names.
// The keywords initial and default are reserved for future use
// and must also be quoted when used as font names.
// UAs must not consider these keywords as matching the <family-name> type."
"inherit" => css_wide_keyword = true,
"initial" => css_wide_keyword = true,
"unset" => css_wide_keyword = true,
"default" => css_wide_keyword = true,
_ => {}
}
let mut value = first_ident.as_ref().to_owned();
let mut serialization = String::new();
serialize_identifier(&first_ident, &mut serialization).unwrap();
// These keywords are not allowed by themselves.
// The only way this value can be valid with with another keyword.
if css_wide_keyword {
let ident = input.expect_ident()?;
value.push(' ');
value.push_str(&ident);
serialization.push(' ');
serialize_identifier(&ident, &mut serialization).unwrap();
}
while let Ok(ident) = input.try(|i| i.expect_ident_cloned()) {
value.push(' ');
value.push_str(&ident);
serialization.push(' ');
serialize_identifier(&ident, &mut serialization).unwrap();
}
Ok(FontFamily::FamilyName(FamilyName {
name: Atom::from(value),
syntax: FamilyNameSyntax::Identifiers(serialization),
}))
}
#[cfg(feature = "gecko")]
/// Return the generic ID for a given generic font name
pub fn generic(name: &Atom) -> (structs::FontFamilyType, u8) {
use gecko_bindings::structs::FontFamilyType;
if *name == atom!("serif") {
(FontFamilyType::eFamily_serif,
structs::kGenericFont_serif)
} else if *name == atom!("sans-serif") {
(FontFamilyType::eFamily_sans_serif,
structs::kGenericFont_sans_serif)
} else if *name == atom!("cursive") {
(FontFamilyType::eFamily_cursive,
structs::kGenericFont_cursive)
} else if *name == atom!("fantasy") {
(FontFamilyType::eFamily_fantasy,
structs::kGenericFont_fantasy)
} else if *name == atom!("monospace") {
(FontFamilyType::eFamily_monospace,
structs::kGenericFont_monospace)
} else if *name == atom!("-moz-fixed") {
(FontFamilyType::eFamily_moz_fixed,
structs::kGenericFont_moz_fixed)
} else {
panic!("Unknown generic {}", name);
}
}
#[cfg(feature = "gecko")]
fn from_font_family_name(family: &structs::FontFamilyName) -> FontFamily {
use gecko_bindings::structs::FontFamilyType;
match family.mType {
FontFamilyType::eFamily_serif => FontFamily::Generic(atom!("serif")),
FontFamilyType::eFamily_sans_serif => FontFamily::Generic(atom!("sans-serif")),
FontFamilyType::eFamily_monospace => FontFamily::Generic(atom!("monospace")),
FontFamilyType::eFamily_cursive => FontFamily::Generic(atom!("cursive")),
FontFamilyType::eFamily_fantasy => FontFamily::Generic(atom!("fantasy")),
FontFamilyType::eFamily_moz_fixed => FontFamily::Generic(Atom::from("-moz-fixed")),
FontFamilyType::eFamily_named => {
let name = Atom::from(&*family.mName);
let mut serialization = String::new();
serialize_identifier(&name.to_string(), &mut serialization).unwrap();
FontFamily::FamilyName(FamilyName {
name: name.clone(),
syntax: FamilyNameSyntax::Identifiers(serialization),
})
},
FontFamilyType::eFamily_named_quoted => FontFamily::FamilyName(FamilyName {
name: (&*family.mName).into(),
syntax: FamilyNameSyntax::Quoted,
}),
x => panic!("Found unexpected font FontFamilyType: {:?}", x),
}
}
}
impl ToCss for FamilyName {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self.syntax {
FamilyNameSyntax::Quoted => {
dest.write_char('"')?;
write!(CssStringWriter::new(dest), "{}", self.name)?;
dest.write_char('"')
}
FamilyNameSyntax::Identifiers(ref serialization) => {
// Note that `serialization` is already escaped/
// serialized appropriately.
dest.write_str(&*serialization)
}
}
}
}
impl ToCss for FontFamily {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
FontFamily::FamilyName(ref name) => name.to_css(dest),
// All generic values accepted by the parser are known to not require escaping.
FontFamily::Generic(ref name) => {
% if product == "gecko":
// We should treat -moz-fixed as monospace
if name == &atom!("-moz-fixed") {
return dest.write_str("monospace");
}
% endif
write!(dest, "{}", name)
},
}
}
}
impl ToCss for T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let mut iter = self.0.iter();
iter.next().unwrap().to_css(dest)?;
for family in iter {
dest.write_str(", ")?;
family.to_css(dest)?;
}
Ok(())
}
}
#[cfg(feature = "servo")]
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct FontFamilyList(Vec<FontFamily>);
#[cfg(feature = "gecko")]
#[derive(Clone, Debug)]
pub struct FontFamilyList(pub RefPtr<structs::SharedFontList>);
#[cfg(feature = "gecko")]
impl Hash for FontFamilyList {
fn hash<H>(&self, state: &mut H) where H: Hasher {
for name in self.0.mNames.iter() {
name.mType.hash(state);
name.mName.hash(state);
}
}
}
#[cfg(feature = "gecko")]
impl PartialEq for FontFamilyList {
fn eq(&self, other: &FontFamilyList) -> bool {
if self.0.mNames.len() != other.0.mNames.len() {
return false;
}
for (a, b) in self.0.mNames.iter().zip(other.0.mNames.iter()) {
if a.mType != b.mType || &*a.mName != &*b.mName {
return false;
}
}
true
}
}
#[cfg(feature = "gecko")]
impl Eq for FontFamilyList {}
impl FontFamilyList {
#[cfg(feature = "servo")]
pub fn new(families: Vec<FontFamily>) -> FontFamilyList {
FontFamilyList(families)
}
#[cfg(feature = "gecko")]
pub fn new(families: Vec<FontFamily>) -> FontFamilyList {
let fontlist;
let names;
unsafe {
fontlist = bindings::Gecko_SharedFontList_Create();
names = &mut (*fontlist).mNames;
names.ensure_capacity(families.len());
};
for family in families {
match family {
FontFamily::FamilyName(ref f) => {
let quoted = matches!(f.syntax, FamilyNameSyntax::Quoted);
unsafe {
bindings::Gecko_nsTArray_FontFamilyName_AppendNamed(
names,
f.name.as_ptr(),
quoted
);
}
}
FontFamily::Generic(ref name) => {
let (family_type, _generic) = FontFamily::generic(name);
unsafe {
bindings::Gecko_nsTArray_FontFamilyName_AppendGeneric(
names,
family_type
);
}
}
}
}
FontFamilyList(unsafe { RefPtr::from_addrefed(fontlist) })
}
#[cfg(feature = "servo")]
pub fn iter(&self) -> slice::Iter<FontFamily> {
self.0.iter()
}
#[cfg(feature = "gecko")]
pub fn iter(&self) -> FontFamilyNameIter {
FontFamilyNameIter {
names: &self.0.mNames,
cur: 0,
}
}
#[cfg(feature = "gecko")]
/// Return the generic ID if it is a single generic font
pub fn single_generic(&self) -> Option<u8> {
let mut iter = self.iter();
if let Some(FontFamily::Generic(ref name)) = iter.next() {
if iter.next().is_none() {
return Some(FontFamily::generic(name).1);
}
}
None
}
}
#[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 = FontFamily;
fn next(&mut self) -> Option<Self::Item> {
if self.cur < self.names.len() {
let item = FontFamily::from_font_family_name(&self.names[self.cur]);
self.cur += 1;
Some(item)
} else {
None
}
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub struct T(pub FontFamilyList);
#[cfg(feature = "gecko")]
impl MallocSizeOf for T {
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.
unsafe {
bindings::Gecko_SharedFontList_SizeOfIncludingThisIfUnshared(
(self.0).0.get()
)
}
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T(
FontFamilyList::new(vec![FontFamily::Generic(atom!("serif"))])
)
}
/// <family-name>#
/// <family-name> = <string> | [ <ident>+ ]
/// TODO: <generic-family>
pub fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
SpecifiedValue::parse(input)
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum SpecifiedValue {
Values(FontFamilyList),
System(SystemFont),
}
#[cfg(feature = "gecko")]
impl SpecifiedValue {
/// Return the generic ID if it is a single generic font
pub fn single_generic(&self) -> Option<u8> {
match *self {
SpecifiedValue::Values(ref values) => values.single_generic(),
_ => None,
}
}
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
fn to_computed_value(&self, _cx: &Context) -> Self::ComputedValue {
match *self {
SpecifiedValue::Values(ref v) => computed_value::T(v.clone()),
SpecifiedValue::System(_) => {
<%self:nongecko_unreachable>
_cx.cached_system_font.as_ref().unwrap().font_family.clone()
</%self:nongecko_unreachable>
}
}
}
fn from_computed_value(other: &computed_value::T) -> Self {
SpecifiedValue::Values(other.0.clone())
}
}
#[cfg(feature = "gecko")]
impl MallocSizeOf for SpecifiedValue {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
match *self {
SpecifiedValue::Values(ref v) => {
// Although a SharedFontList object is refcounted, we always
// attribute its size to the specified value.
unsafe {
bindings::Gecko_SharedFontList_SizeOfIncludingThis(
v.0.get()
)
}
}
SpecifiedValue::System(_) => 0,
}
}
}
impl SpecifiedValue {
pub fn system_font(f: SystemFont) -> Self {
SpecifiedValue::System(f)
}
pub fn get_system(&self) -> Option<SystemFont> {
if let SpecifiedValue::System(s) = *self {
Some(s)
} else {
None
}
}
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.parse_comma_separated(|input| FontFamily::parse(input)).map(|v| {
SpecifiedValue::Values(FontFamilyList::new(v))
})
}
}
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
SpecifiedValue::Values(ref v) => {
let mut iter = v.iter();
iter.next().unwrap().to_css(dest)?;
for family in iter {
dest.write_str(", ")?;
family.to_css(dest)?;
}
Ok(())
}
SpecifiedValue::System(sys) => sys.to_css(dest),
}
}
}
/// `FamilyName::parse` is based on `FontFamily::parse` and not the other way around
/// because we want the former to exclude generic family keywords.
impl Parse for FamilyName {
fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
match FontFamily::parse(input) {
Ok(FontFamily::FamilyName(name)) => Ok(name),
Ok(FontFamily::Generic(_)) => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
Err(e) => Err(e)
}
}
}
</%helpers:longhand>
${helpers.predefined_type("font-family",
"FontFamily",
initial_value="computed::FontFamily::serif()",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-fonts/#propdef-font-family")}
${helpers.single_keyword_system("font-style",
"normal italic oblique",
@ -833,7 +309,7 @@ ${helpers.predefined_type("-x-text-zoom",
use gecko_bindings::bindings;
use gecko_bindings::structs::{LookAndFeel_FontID, nsFont};
use std::mem;
use values::computed::font::FontSize;
use values::computed::font::{FontSize, FontFamilyList};
let id = match *self {
% for font in system_fonts:
@ -855,7 +331,7 @@ ${helpers.predefined_type("-x-text-zoom",
let weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight);
let ret = ComputedSystemFont {
font_family: longhands::font_family::computed_value::T(
longhands::font_family::computed_value::FontFamilyList(
FontFamilyList(
unsafe { system.fontlist.mFontlist.mBasePtr.to_safe() }
)
),

View File

@ -120,7 +120,7 @@
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
let family = FontFamily::parse(input)?;
let family = FontFamily::parse_specified(input)?;
Ok(expanded! {
% for name in "style weight stretch variant_caps".split():
font_${name}: unwrap_or_initial!(font_${name}, ${name}),

View File

@ -7,7 +7,6 @@
//! [font-feature-values]: https://drafts.csswg.org/css-fonts-3/#at-font-feature-values-rule
use Atom;
use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, AtRuleType, BasicParseErrorKind, DeclarationListParser, DeclarationParser, Parser};
use cssparser::{CowRcStr, RuleListParser, SourceLocation, QualifiedRuleParser, Token, serialize_identifier};
use error_reporting::{ContextualParseError, ParseErrorReporter};
@ -20,6 +19,7 @@ use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use style_traits::{ParseError, StyleParseErrorKind, ToCss};
use stylesheets::CssRuleType;
use values::computed::font::FamilyName;
/// A @font-feature-values block declaration.
/// It is `<ident>: <integer>+`.

View File

@ -5,7 +5,6 @@
//! Parsing of the stylesheet contents.
use {Namespace, Prefix};
use computed_values::font_family::FamilyName;
use counter_style::{parse_counter_style_body, parse_counter_style_name};
use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{CowRcStr, SourceLocation, BasicParseError, BasicParseErrorKind};
@ -31,6 +30,7 @@ use stylesheets::supports_rule::SupportsCondition;
use stylesheets::viewport_rule;
use values::CustomIdent;
use values::KeyframesName;
use values::computed::font::FamilyName;
use values::specified::url::SpecifiedUrl;
/// The parser for the top-level rules in a stylesheet.

View File

@ -4,10 +4,22 @@
//! Computed values for font properties
use Atom;
use app_units::Au;
use byteorder::{BigEndian, ByteOrder};
use std::fmt;
use style_traits::ToCss;
use cssparser::{CssStringWriter, Parser, serialize_identifier};
#[cfg(feature = "gecko")]
use gecko_bindings::{bindings, structs};
#[cfg(feature = "gecko")]
use gecko_bindings::sugar::refptr::RefPtr;
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use std::fmt::{self, Write};
#[cfg(feature = "gecko")]
use std::hash::{Hash, Hasher};
#[cfg(feature = "servo")]
use std::slice;
use style_traits::{ToCss, ParseError};
use values::CSSFloat;
use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::computed::{Context, NonNegativeLength, ToComputedValue};
@ -215,6 +227,419 @@ impl ToAnimatedValue for FontSize {
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
/// Specifies a prioritized list of font family names or generic family names.
pub struct FontFamily(pub FontFamilyList);
impl FontFamily {
#[inline]
/// Get default font family as `serif` which is a generic font-family
pub fn serif() -> Self {
FontFamily(
FontFamilyList::new(Box::new([SingleFontFamily::Generic(atom!("serif"))]))
)
}
}
#[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.
unsafe {
bindings::Gecko_SharedFontList_SizeOfIncludingThisIfUnshared(
(self.0).0.get()
)
}
}
}
impl ToCss for FontFamily {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let mut iter = self.0.iter();
iter.next().unwrap().to_css(dest)?;
for family in iter {
dest.write_str(", ")?;
family.to_css(dest)?;
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// The name of a font family of choice
pub struct FamilyName {
/// Name of the font family
pub name: Atom,
/// Syntax of the font family
pub syntax: FamilyNameSyntax,
}
impl ToCss for FamilyName {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self.syntax {
FamilyNameSyntax::Quoted => {
dest.write_char('"')?;
write!(CssStringWriter::new(dest), "{}", self.name)?;
dest.write_char('"')
}
FamilyNameSyntax::Identifiers(ref serialization) => {
// Note that `serialization` is already escaped/
// serialized appropriately.
dest.write_str(&*serialization)
}
}
}
}
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// Font family names must either be given quoted as strings,
/// or unquoted as a sequence of one or more identifiers.
pub enum FamilyNameSyntax {
/// The family name was specified in a quoted form, e.g. "Font Name"
/// or 'Font Name'.
Quoted,
/// The family name was specified in an unquoted form as a sequence of
/// identifiers. The `String` is the serialization of the sequence of
/// identifiers.
Identifiers(String),
}
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// A set of faces that vary in weight, width or slope.
pub enum SingleFontFamily {
/// The name of a font family of choice.
FamilyName(FamilyName),
/// Generic family name.
Generic(Atom),
}
impl SingleFontFamily {
#[inline]
/// Get font family name as Atom
pub fn atom(&self) -> &Atom {
match *self {
SingleFontFamily::FamilyName(ref family_name) => &family_name.name,
SingleFontFamily::Generic(ref name) => name,
}
}
#[inline]
#[cfg(not(feature = "gecko"))] // Gecko can't borrow atoms as UTF-8.
/// Get font family name
pub fn name(&self) -> &str {
self.atom()
}
#[cfg(not(feature = "gecko"))] // Gecko can't borrow atoms as UTF-8.
/// Get the corresponding font-family with Atom
pub fn from_atom(input: Atom) -> SingleFontFamily {
match input {
atom!("serif") |
atom!("sans-serif") |
atom!("cursive") |
atom!("fantasy") |
atom!("monospace") => {
return SingleFontFamily::Generic(input)
}
_ => {}
}
match_ignore_ascii_case! { &input,
"serif" => return SingleFontFamily::Generic(atom!("serif")),
"sans-serif" => return SingleFontFamily::Generic(atom!("sans-serif")),
"cursive" => return SingleFontFamily::Generic(atom!("cursive")),
"fantasy" => return SingleFontFamily::Generic(atom!("fantasy")),
"monospace" => return SingleFontFamily::Generic(atom!("monospace")),
_ => {}
}
// We don't know if it's quoted or not. So we set it to
// quoted by default.
SingleFontFamily::FamilyName(FamilyName {
name: input,
syntax: FamilyNameSyntax::Quoted,
})
}
/// Parse a font-family value
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(value) = input.try(|i| i.expect_string_cloned()) {
return Ok(SingleFontFamily::FamilyName(FamilyName {
name: Atom::from(&*value),
syntax: FamilyNameSyntax::Quoted,
}))
}
let first_ident = input.expect_ident()?.clone();
// FIXME(bholley): The fast thing to do here would be to look up the
// string (as lowercase) in the static atoms table. We don't have an
// API to do that yet though, so we do the simple thing for now.
let mut css_wide_keyword = false;
match_ignore_ascii_case! { &first_ident,
"serif" => return Ok(SingleFontFamily::Generic(atom!("serif"))),
"sans-serif" => return Ok(SingleFontFamily::Generic(atom!("sans-serif"))),
"cursive" => return Ok(SingleFontFamily::Generic(atom!("cursive"))),
"fantasy" => return Ok(SingleFontFamily::Generic(atom!("fantasy"))),
"monospace" => return Ok(SingleFontFamily::Generic(atom!("monospace"))),
#[cfg(feature = "gecko")]
"-moz-fixed" => return Ok(SingleFontFamily::Generic(atom!("-moz-fixed"))),
// https://drafts.csswg.org/css-fonts/#propdef-font-family
// "Font family names that happen to be the same as a keyword value
// (`inherit`, `serif`, `sans-serif`, `monospace`, `fantasy`, and `cursive`)
// must be quoted to prevent confusion with the keywords with the same names.
// The keywords initial and default are reserved for future use
// and must also be quoted when used as font names.
// UAs must not consider these keywords as matching the <family-name> type."
"inherit" => css_wide_keyword = true,
"initial" => css_wide_keyword = true,
"unset" => css_wide_keyword = true,
"default" => css_wide_keyword = true,
_ => {}
}
let mut value = first_ident.as_ref().to_owned();
let mut serialization = String::new();
serialize_identifier(&first_ident, &mut serialization).unwrap();
// These keywords are not allowed by themselves.
// The only way this value can be valid with with another keyword.
if css_wide_keyword {
let ident = input.expect_ident()?;
value.push(' ');
value.push_str(&ident);
serialization.push(' ');
serialize_identifier(&ident, &mut serialization).unwrap();
}
while let Ok(ident) = input.try(|i| i.expect_ident_cloned()) {
value.push(' ');
value.push_str(&ident);
serialization.push(' ');
serialize_identifier(&ident, &mut serialization).unwrap();
}
Ok(SingleFontFamily::FamilyName(FamilyName {
name: Atom::from(value),
syntax: FamilyNameSyntax::Identifiers(serialization),
}))
}
#[cfg(feature = "gecko")]
/// Return the generic ID for a given generic font name
pub fn generic(name: &Atom) -> (structs::FontFamilyType, u8) {
use gecko_bindings::structs::FontFamilyType;
if *name == atom!("serif") {
(FontFamilyType::eFamily_serif,
structs::kGenericFont_serif)
} else if *name == atom!("sans-serif") {
(FontFamilyType::eFamily_sans_serif,
structs::kGenericFont_sans_serif)
} else if *name == atom!("cursive") {
(FontFamilyType::eFamily_cursive,
structs::kGenericFont_cursive)
} else if *name == atom!("fantasy") {
(FontFamilyType::eFamily_fantasy,
structs::kGenericFont_fantasy)
} else if *name == atom!("monospace") {
(FontFamilyType::eFamily_monospace,
structs::kGenericFont_monospace)
} else if *name == atom!("-moz-fixed") {
(FontFamilyType::eFamily_moz_fixed,
structs::kGenericFont_moz_fixed)
} else {
panic!("Unknown generic {}", name);
}
}
#[cfg(feature = "gecko")]
/// Get the corresponding font-family with family name
fn from_font_family_name(family: &structs::FontFamilyName) -> SingleFontFamily {
use gecko_bindings::structs::FontFamilyType;
match family.mType {
FontFamilyType::eFamily_sans_serif => SingleFontFamily::Generic(atom!("sans-serif")),
FontFamilyType::eFamily_serif => SingleFontFamily::Generic(atom!("serif")),
FontFamilyType::eFamily_monospace => SingleFontFamily::Generic(atom!("monospace")),
FontFamilyType::eFamily_cursive => SingleFontFamily::Generic(atom!("cursive")),
FontFamilyType::eFamily_fantasy => SingleFontFamily::Generic(atom!("fantasy")),
FontFamilyType::eFamily_moz_fixed => SingleFontFamily::Generic(Atom::from("-moz-fixed")),
FontFamilyType::eFamily_named => {
let name = Atom::from(&*family.mName);
let mut serialization = String::new();
serialize_identifier(&name.to_string(), &mut serialization).unwrap();
SingleFontFamily::FamilyName(FamilyName {
name: name.clone(),
syntax: FamilyNameSyntax::Identifiers(serialization),
})
},
FontFamilyType::eFamily_named_quoted => SingleFontFamily::FamilyName(FamilyName {
name: (&*family.mName).into(),
syntax: FamilyNameSyntax::Quoted,
}),
x => panic!("Found unexpected font FontFamilyType: {:?}", x),
}
}
}
impl ToCss for SingleFontFamily {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
SingleFontFamily::FamilyName(ref name) => name.to_css(dest),
// All generic values accepted by the parser are known to not require escaping.
SingleFontFamily::Generic(ref name) => {
#[cfg(feature = "gecko")] {
// We should treat -moz-fixed as monospace
if name == &atom!("-moz-fixed") {
return dest.write_str("monospace");
}
}
write!(dest, "{}", name)
},
}
}
}
#[cfg(feature = "servo")]
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
/// A list of SingleFontFamily
pub struct FontFamilyList(Box<[SingleFontFamily]>);
#[cfg(feature = "gecko")]
#[derive(Clone, Debug)]
/// A list of SingleFontFamily
pub struct FontFamilyList(pub RefPtr<structs::SharedFontList>);
#[cfg(feature = "gecko")]
impl Hash for FontFamilyList {
fn hash<H>(&self, state: &mut H) where H: Hasher {
for name in self.0.mNames.iter() {
name.mType.hash(state);
name.mName.hash(state);
}
}
}
#[cfg(feature = "gecko")]
impl PartialEq for FontFamilyList {
fn eq(&self, other: &FontFamilyList) -> bool {
if self.0.mNames.len() != other.0.mNames.len() {
return false;
}
for (a, b) in self.0.mNames.iter().zip(other.0.mNames.iter()) {
if a.mType != b.mType || &*a.mName != &*b.mName {
return false;
}
}
true
}
}
#[cfg(feature = "gecko")]
impl Eq for FontFamilyList {}
impl FontFamilyList {
#[cfg(feature = "servo")]
/// Return FontFamilyList with a vector of SingleFontFamily
pub fn new(families: Box<[SingleFontFamily]>) -> FontFamilyList {
FontFamilyList(families)
}
#[cfg(feature = "gecko")]
/// Return FontFamilyList with a vector of SingleFontFamily
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());
};
for family in families.iter() {
match *family {
SingleFontFamily::FamilyName(ref f) => {
let quoted = matches!(f.syntax, FamilyNameSyntax::Quoted);
unsafe {
bindings::Gecko_nsTArray_FontFamilyName_AppendNamed(
names,
f.name.as_ptr(),
quoted
);
}
}
SingleFontFamily::Generic(ref name) => {
let (family_type, _generic) = SingleFontFamily::generic(name);
unsafe {
bindings::Gecko_nsTArray_FontFamilyName_AppendGeneric(
names,
family_type
);
}
}
}
}
FontFamilyList(unsafe { RefPtr::from_addrefed(fontlist) })
}
#[cfg(feature = "servo")]
/// Return iterator of SingleFontFamily
pub fn iter(&self) -> slice::Iter<SingleFontFamily> {
self.0.iter()
}
#[cfg(feature = "gecko")]
/// Return iterator of SingleFontFamily
pub fn iter(&self) -> FontFamilyNameIter {
FontFamilyNameIter {
names: &self.0.mNames,
cur: 0,
}
}
#[cfg(feature = "gecko")]
/// Return the generic ID if it is a single generic font
pub fn single_generic(&self) -> Option<u8> {
let mut iter = self.iter();
if let Some(SingleFontFamily::Generic(ref name)) = iter.next() {
if iter.next().is_none() {
return Some(SingleFontFamily::generic(name).1);
}
}
None
}
}
#[cfg(feature = "gecko")]
/// Iterator of FontFamily
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
}
}
}
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss)]
/// Preserve the readability of text when font fallback occurs
pub enum FontSizeAdjust {

View File

@ -37,7 +37,7 @@ pub use self::background::{BackgroundSize, BackgroundRepeat};
pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth};
pub use self::border::{BorderRadius, BorderCornerRadius, BorderSpacing};
pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVariantAlternates};
pub use self::font::{FontLanguageOverride, FontVariantSettings, FontVariantEastAsian};
pub use self::font::{FontFamily, FontLanguageOverride, FontVariantSettings, FontVariantEastAsian};
pub use self::font::{FontVariantLigatures, FontVariantNumeric, FontFeatureSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XTextZoom, XLang};
pub use self::box_::{AnimationIterationCount, AnimationName, OverscrollBehavior, ScrollSnapType, VerticalAlign};

View File

@ -8,6 +8,10 @@ use Atom;
use app_units::Au;
use byteorder::{BigEndian, ByteOrder};
use cssparser::{Parser, Token};
#[cfg(feature = "gecko")]
use gecko_bindings::bindings;
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use parser::{Parse, ParserContext};
use properties::longhands::system_font::SystemFont;
#[allow(unused_imports)]
@ -16,6 +20,7 @@ use std::fmt;
use style_traits::{ToCss, StyleParseErrorKind, ParseError};
use values::CustomIdent;
use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue};
use values::computed::font::{SingleFontFamily, FontFamilyList, FamilyName};
use values::generics::{FontSettings, FontSettingTagFloat};
use values::specified::{AllowQuirks, LengthOrPercentage, NoCalcLength, Number};
use values::specified::length::{AU_PER_PT, AU_PER_PX, FontBaseSize};
@ -156,6 +161,128 @@ impl From<LengthOrPercentage> for FontSize {
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
/// Specifies a prioritized list of font family names or generic family names
pub enum FontFamily {
/// List of `font-family`
Values(FontFamilyList),
/// System font
System(SystemFont),
}
impl FontFamily {
/// Get `font-family` with system font
pub fn system_font(f: SystemFont) -> Self {
FontFamily::System(f)
}
/// Get system font
pub fn get_system(&self) -> Option<SystemFont> {
if let FontFamily::System(s) = *self {
Some(s)
} else {
None
}
}
/// Parse a specified font-family value
pub fn parse_specified<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.parse_comma_separated(|input| SingleFontFamily::parse(input)).map(|v| {
FontFamily::Values(FontFamilyList::new(v.into_boxed_slice()))
})
}
#[cfg(feature = "gecko")]
/// Return the generic ID if it is a single generic font
pub fn single_generic(&self) -> Option<u8> {
match *self {
FontFamily::Values(ref values) => values.single_generic(),
_ => None,
}
}
}
impl ToComputedValue for FontFamily {
type ComputedValue = computed::FontFamily;
fn to_computed_value(&self, _cx: &Context) -> Self::ComputedValue {
match *self {
FontFamily::Values(ref v) => computed::FontFamily(v.clone()),
FontFamily::System(_) => {
#[cfg(feature = "gecko")] {
_cx.cached_system_font.as_ref().unwrap().font_family.clone()
}
#[cfg(feature = "servo")] {
unreachable!()
}
}
}
}
fn from_computed_value(other: &computed::FontFamily) -> Self {
FontFamily::Values(other.0.clone())
}
}
#[cfg(feature = "gecko")]
impl MallocSizeOf for FontFamily {
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.
unsafe {
bindings::Gecko_SharedFontList_SizeOfIncludingThis(
v.0.get()
)
}
}
FontFamily::System(_) => 0,
}
}
}
impl ToCss for FontFamily {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
FontFamily::Values(ref v) => {
let mut iter = v.iter();
iter.next().unwrap().to_css(dest)?;
for family in iter {
dest.write_str(", ")?;
family.to_css(dest)?;
}
Ok(())
}
FontFamily::System(sys) => sys.to_css(dest),
}
}
}
impl Parse for FontFamily {
/// <family-name>#
/// <family-name> = <string> | [ <ident>+ ]
/// TODO: <generic-family>
fn parse<'i, 't>(
_: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<FontFamily, ParseError<'i>> {
FontFamily::parse_specified(input)
}
}
/// `FamilyName::parse` is based on `SingleFontFamily::parse` and not the other way around
/// because we want the former to exclude generic family keywords.
impl Parse for FamilyName {
fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
match SingleFontFamily::parse(input) {
Ok(SingleFontFamily::FamilyName(name)) => Ok(name),
Ok(SingleFontFamily::Generic(_)) => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
Err(e) => Err(e)
}
}
}
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)]
/// Preserve the readability of text when font fallback occurs
pub enum FontSizeAdjust {

View File

@ -31,7 +31,7 @@ pub use self::background::{BackgroundRepeat, BackgroundSize};
pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth};
pub use self::border::{BorderImageSideWidth, BorderRadius, BorderSideWidth, BorderSpacing};
pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVariantAlternates};
pub use self::font::{FontLanguageOverride, FontVariantSettings, FontVariantEastAsian};
pub use self::font::{FontFamily, FontLanguageOverride, FontVariantSettings, FontVariantEastAsian};
pub use self::font::{FontVariantLigatures, FontVariantNumeric, FontFeatureSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XTextZoom, XLang};
pub use self::box_::{AnimationIterationCount, AnimationName, OverscrollBehavior, ScrollSnapType, VerticalAlign};

View File

@ -3337,7 +3337,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(
let string = unsafe { (*value).to_string() };
let mut input = ParserInput::new(&string);
let mut parser = Parser::new(&mut input);
let result = FontFamily::parse(&mut parser);
let result = FontFamily::parse_specified(&mut parser);
if let Ok(family) = result {
if parser.is_exhausted() {
let decl = PropertyDeclaration::FontFamily(family);