Auto merge of #19366 - CYBAI:font-family-out-of-mako, r=emilio

style: Move font-family outside of mako

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

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19366)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-11-25 13:06:31 -06:00 committed by GitHub
commit 8f61fde390
14 changed files with 595 additions and 569 deletions

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};