mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 07:15:46 +00:00
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:
parent
b17aa7c172
commit
4fb0a4619e
@ -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");
|
||||
|
@ -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());
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() }
|
||||
)
|
||||
),
|
||||
|
@ -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}),
|
||||
|
@ -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>+`.
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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};
|
||||
|
@ -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 {
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user