--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -844,16 +844,22 @@ SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIO
#undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
nsIAtom*
Gecko_Atomize(const char* aString, uint32_t aLength)
{
return NS_Atomize(nsDependentCSubstring(aString, aLength)).take();
}
+nsIAtom*
+Gecko_Atomize16(const nsAString* aString)
+{
+ return NS_Atomize(*aString).take();
+}
+
void
Gecko_AddRefAtom(nsIAtom* aAtom)
{
NS_ADDREF(aAtom);
}
void
Gecko_ReleaseAtom(nsIAtom* aAtom)
@@ -918,16 +924,43 @@ Gecko_FontFamilyList_AppendGeneric(FontF
void
Gecko_CopyFontFamilyFrom(nsFont* dst, const nsFont* src)
{
dst->fontlist = src->fontlist;
}
void
+Gecko_nsFont_InitSystem(nsFont* aDest, int32_t aFontId,
+ const nsStyleFont* aFont, RawGeckoPresContextBorrowed aPresContext)
+{
+
+ const nsFont* defaultVariableFont =
+ aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
+ aFont->mLanguage);
+
+ // We have passed uninitialized memory to this function,
+ // initialize it. We can't simply return an nsFont because then
+ // we need to know its size beforehand. Servo cannot initialize nsFont
+ // itself, so this will do.
+ nsFont* system = new (aDest) nsFont(*defaultVariableFont);
+
+ *system = *defaultVariableFont;
+ LookAndFeel::FontID fontID = static_cast<LookAndFeel::FontID>(aFontId);
+ nsRuleNode::ComputeSystemFont(system, fontID, aPresContext);
+}
+
+void
+Gecko_nsFont_Destroy(nsFont* aDest)
+{
+ aDest->~nsFont();
+}
+
+
+void
Gecko_SetImageOrientation(nsStyleVisibility* aVisibility,
double aRadians, bool aFlip)
{
aVisibility->mImageOrientation =
nsStyleImageOrientation::CreateAsAngleAndFlip(aRadians, aFlip);
}
void
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -215,27 +215,33 @@ double Gecko_GetPositionInSegment(
// |aBaseStyles| is nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>.
// We use void* to avoid exposing nsRefPtrHashtable in FFI.
RawServoAnimationValueBorrowedOrNull Gecko_AnimationGetBaseStyle(
void* aBaseStyles,
nsCSSPropertyID aProperty);
// Atoms.
nsIAtom* Gecko_Atomize(const char* aString, uint32_t aLength);
+nsIAtom* Gecko_Atomize16(const nsAString* aString);
void Gecko_AddRefAtom(nsIAtom* aAtom);
void Gecko_ReleaseAtom(nsIAtom* aAtom);
const uint16_t* Gecko_GetAtomAsUTF16(nsIAtom* aAtom, uint32_t* aLength);
bool Gecko_AtomEqualsUTF8(nsIAtom* aAtom, const char* aString, uint32_t aLength);
bool Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom* aAtom, const char* aString, uint32_t aLength);
// Font style
void Gecko_FontFamilyList_Clear(FontFamilyList* aList);
void Gecko_FontFamilyList_AppendNamed(FontFamilyList* aList, nsIAtom* aName, bool aQuoted);
void Gecko_FontFamilyList_AppendGeneric(FontFamilyList* list, FontFamilyType familyType);
void Gecko_CopyFontFamilyFrom(nsFont* dst, const nsFont* src);
+// will not run destructors on dst, give it uninitialized memory
+// font_id is LookAndFeel::FontID
+void Gecko_nsFont_InitSystem(nsFont* dst, int32_t font_id,
+ const nsStyleFont* font, RawGeckoPresContextBorrowed pres_context);
+void Gecko_nsFont_Destroy(nsFont* dst);
// Visibility style
void Gecko_SetImageOrientation(nsStyleVisibility* aVisibility,
double aRadians,
bool aFlip);
void Gecko_SetImageOrientationAsFromImage(nsStyleVisibility* aVisibility);
void Gecko_CopyImageOrientationFrom(nsStyleVisibility* aDst,
const nsStyleVisibility* aSrc);
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -1082,31 +1082,32 @@ public:
// Fill unspecified layers by cycling through their values
// till they all are of length aMaxItemCount
static void FillAllBackgroundLists(nsStyleImageLayers& aLayers,
uint32_t aMaxItemCount);
static void FillAllMaskLists(nsStyleImageLayers& aLayers,
uint32_t aMaxItemCount);
+ static void ComputeSystemFont(nsFont* aSystemFont,
+ mozilla::LookAndFeel::FontID aFontID,
+ const nsPresContext* aPresContext);
+
private:
#ifdef DEBUG
// non-inline helper function to allow assertions without incomplete
// type errors
bool ContextHasCachedData(nsStyleContext* aContext, nsStyleStructID aSID);
#endif
// Store style struct on the style context and tell the style context
// that it doesn't own the data
static void StoreStyleOnContext(nsStyleContext* aContext,
nsStyleStructID aSID,
void* aStruct);
- static void ComputeSystemFont(nsFont* aSystemFont,
- mozilla::LookAndFeel::FontID aFontID,
- const nsPresContext* aPresContext);
};
/**
* We allocate arrays of CSS values with alloca. (These arrays are a
* fixed size per style struct, but we don't want to waste the
* allocation and construction/destruction costs of the big structs when
* we're handling much smaller ones.) Since the lifetime of an alloca
* allocation is the life of the calling function, the caller must call
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -463,17 +463,17 @@ impl LayoutElementHelpers for LayoutJS<E
} else {
None
};
if let Some(font_family) = font_family {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::FontFamily(
- font_family::computed_value::T(vec![
+ font_family::SpecifiedValue::Values(vec![
font_family::computed_value::FontFamily::from_atom(
font_family)]))));
}
let font_size = self.downcast::<HTMLFontElement>().and_then(|this| this.get_size());
if let Some(font_size) = font_size {
hints.push(from_declaration(
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -666,16 +666,19 @@ extern "C" {
aProperty: nsCSSPropertyID)
-> RawServoAnimationValueBorrowedOrNull;
}
extern "C" {
pub fn Gecko_Atomize(aString: *const ::std::os::raw::c_char, aLength: u32)
-> *mut nsIAtom;
}
extern "C" {
+ pub fn Gecko_Atomize16(aString: *const nsAString) -> *mut nsIAtom;
+}
+extern "C" {
pub fn Gecko_AddRefAtom(aAtom: *mut nsIAtom);
}
extern "C" {
pub fn Gecko_ReleaseAtom(aAtom: *mut nsIAtom);
}
extern "C" {
pub fn Gecko_GetAtomAsUTF16(aAtom: *mut nsIAtom, aLength: *mut u32)
-> *const u16;
@@ -702,16 +705,24 @@ extern "C" {
extern "C" {
pub fn Gecko_FontFamilyList_AppendGeneric(list: *mut FontFamilyList,
familyType: FontFamilyType);
}
extern "C" {
pub fn Gecko_CopyFontFamilyFrom(dst: *mut nsFont, src: *const nsFont);
}
extern "C" {
+ pub fn Gecko_nsFont_InitSystem(dst: *mut nsFont, font_id: i32,
+ font: *const nsStyleFont,
+ pres_context: RawGeckoPresContextBorrowed);
+}
+extern "C" {
+ pub fn Gecko_nsFont_Destroy(dst: *mut nsFont);
+}
+extern "C" {
pub fn Gecko_SetImageOrientation(aVisibility: *mut nsStyleVisibility,
aRadians: f64, aFlip: bool);
}
extern "C" {
pub fn Gecko_SetImageOrientationAsFromImage(aVisibility:
*mut nsStyleVisibility);
}
extern "C" {
--- a/servo/components/style/gecko_string_cache/mod.rs
+++ b/servo/components/style/gecko_string_cache/mod.rs
@@ -3,19 +3,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![allow(unsafe_code)]
//! A drop-in replacement for string_cache, but backed by Gecko `nsIAtom`s.
use gecko_bindings::bindings::Gecko_AddRefAtom;
use gecko_bindings::bindings::Gecko_Atomize;
+use gecko_bindings::bindings::Gecko_Atomize16;
use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::nsIAtom;
use precomputed_hash::PrecomputedHash;
+use nsstring::nsAString;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;
@@ -276,16 +278,27 @@ impl<'a> From<&'a str> for Atom {
unsafe {
Atom(WeakAtom::new(
Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
))
}
}
}
+impl<'a> From<&'a nsAString> for Atom {
+ #[inline]
+ fn from(string: &nsAString) -> Atom {
+ unsafe {
+ Atom(WeakAtom::new(
+ Gecko_Atomize16(string)
+ ))
+ }
+ }
+}
+
impl<'a> From<Cow<'a, str>> for Atom {
#[inline]
fn from(string: Cow<'a, str>) -> Atom {
Atom::from(&*string)
}
}
impl From<String> for Atom {
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -89,25 +89,27 @@ pub struct ComputedValues {
/// from a keyword value or a keyword value on some ancestor with only
/// font-size-relative keywords and regular inheritance in between. The
/// integer stores the final ratio of the chain of font size relative values.
/// and is 1 when there was just a keyword and no relative values.
///
/// When this is Some, we compute font sizes by computing the keyword against
/// the generic font, and then multiplying it by the ratio.
pub font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
+ pub cached_system_font: Option<longhands::system_font::ComputedSystemFont>,
}
impl ComputedValues {
pub fn inherit_from(parent: &Self, default: &Self) -> Arc<Self> {
Arc::new(ComputedValues {
custom_properties: parent.custom_properties.clone(),
writing_mode: parent.writing_mode,
root_font_size: parent.root_font_size,
font_size_keyword: parent.font_size_keyword,
+ cached_system_font: None,
% for style_struct in data.style_structs:
% if style_struct.inherited:
${style_struct.ident}: parent.${style_struct.ident}.clone(),
% else:
${style_struct.ident}: default.${style_struct.ident}.clone(),
% endif
% endfor
})
@@ -120,29 +122,31 @@ impl ComputedValues {
% for style_struct in data.style_structs:
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
% endfor
) -> Self {
ComputedValues {
custom_properties: custom_properties,
writing_mode: writing_mode,
root_font_size: root_font_size,
+ cached_system_font: None,
font_size_keyword: font_size_keyword,
% for style_struct in data.style_structs:
${style_struct.ident}: ${style_struct.ident},
% endfor
}
}
pub fn default_values(pres_context: RawGeckoPresContextBorrowed) -> Arc<Self> {
Arc::new(ComputedValues {
custom_properties: None,
writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious
root_font_size: longhands::font_size::get_initial_value(), // FIXME(bz): Also seems dubious?
font_size_keyword: Some((Default::default(), 1.)),
+ cached_system_font: None,
% for style_struct in data.style_structs:
${style_struct.ident}: style_structs::${style_struct.name}::default(pres_context),
% endfor
})
}
#[inline]
pub fn is_display_contents(&self) -> bool {
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -260,16 +260,21 @@
&value);
}
% if property.logical:
let wm = context.style.writing_mode;
% endif
<% maybe_wm = ", wm" if property.logical else "" %>
match *value {
DeclaredValue::Value(ref specified_value) => {
+ % if property.ident in "font_size font_family".split() and product == "gecko":
+ if let Some(sf) = specified_value.get_system() {
+ longhands::system_font::resolve_system_font(sf, context);
+ }
+ % endif
let computed = specified_value.to_computed_value(context);
% if property.ident == "font_size":
if let longhands::font_size::SpecifiedValue::Keyword(kw, fraction)
= **specified_value {
context.mutate_style().font_size_keyword = Some((kw, fraction));
} else if let Some(ratio) = specified_value.as_font_ratio() {
// In case a font-size-relative value was applied to a keyword
// value, we must preserve this fact in case the generic font family
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -340,25 +340,30 @@ impl AnimationValue {
% endif
}
% endif
% endfor
}
}
/// Construct an AnimationValue from a property declaration
- pub fn from_declaration(decl: &PropertyDeclaration, context: &Context, initial: &ComputedValues) -> Option<Self> {
+ pub fn from_declaration(decl: &PropertyDeclaration, context: &mut Context, initial: &ComputedValues) -> Option<Self> {
use error_reporting::StdoutErrorReporter;
use properties::LonghandId;
use properties::DeclaredValue;
match *decl {
% for prop in data.longhands:
% if prop.animatable:
PropertyDeclaration::${prop.camel_case}(ref val) => {
+ % if prop.ident in "font_size font_family".split() and product == "gecko":
+ if let Some(sf) = val.get_system() {
+ longhands::system_font::resolve_system_font(sf, context);
+ }
+ % endif
Some(AnimationValue::${prop.camel_case}(val.to_computed_value(context)))
},
% endif
% endfor
PropertyDeclaration::CSSWideKeyword(id, keyword) => {
match id {
// We put all the animatable properties first in the hopes
// that it might increase match locality.
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -1,29 +1,40 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
<%namespace name="helpers" file="/helpers.mako.rs" />
-<% from data import Method %>
+<% from data import Method, to_camel_case, to_rust_ident %>
<% 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_type="none" need_index="True"
spec="https://drafts.csswg.org/css-fonts/#propdef-font-family">
+ use properties::longhands::system_font::SystemFont;
use self::computed_value::{FontFamily, FamilyName};
+ use std::fmt;
+ use style_traits::ToCss;
use values::HasViewportPercentage;
use values::computed::ComputedValueAsSpecified;
- pub use self::computed_value::T as SpecifiedValue;
- impl ComputedValueAsSpecified for SpecifiedValue {}
no_viewport_percentage!(SpecifiedValue);
pub mod computed_value {
use cssparser::{CssStringWriter, Parser, serialize_identifier};
+ use properties::longhands::system_font::SystemFont;
use std::fmt::{self, Write};
use Atom;
use style_traits::ToCss;
pub use self::FontFamily as SingleComputedValue;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub enum FontFamily {
@@ -195,19 +206,71 @@
/// <family-name>#
/// <family-name> = <string> | [ <ident>+ ]
/// TODO: <generic-family>
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
SpecifiedValue::parse(input)
}
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+ pub enum SpecifiedValue {
+ Values(Vec<FontFamily>),
+ System(SystemFont),
+ }
+
+ 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.style.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())
+ }
+ }
+
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(input: &mut Parser) -> Result<Self, ()> {
- input.parse_comma_separated(|input| FontFamily::parse(input)).map(SpecifiedValue)
+ input.parse_comma_separated(|input| FontFamily::parse(input)).map(SpecifiedValue::Values)
+ }
+ }
+
+
+ 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(())
+ }
+ _ => Ok(())
+ }
}
}
/// `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(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
match FontFamily::parse(input) {
@@ -413,24 +476,26 @@
<%helpers:longhand name="font-size" need_clone="True" animation_type="normal"
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size">
use app_units::Au;
use std::fmt;
use style_traits::ToCss;
use values::{FONT_MEDIUM_PX, HasViewportPercentage};
use values::specified::{FontRelativeLength, LengthOrPercentage, Length};
use values::specified::{NoCalcLength, Percentage};
+ use properties::longhands::system_font::SystemFont;
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
SpecifiedValue::Length(ref lop) => lop.to_css(dest),
SpecifiedValue::Keyword(kw, _) => kw.to_css(dest),
SpecifiedValue::Smaller => dest.write_str("smaller"),
SpecifiedValue::Larger => dest.write_str("larger"),
+ SpecifiedValue::System(_) => Ok(()),
}
}
}
impl HasViewportPercentage for SpecifiedValue {
fn has_viewport_percentage(&self) -> bool {
match *self {
SpecifiedValue::Length(ref lop) => lop.has_viewport_percentage(),
@@ -447,16 +512,17 @@
/// The ratio in any specified keyword value
/// will be 1, but we cascade keywordness even
/// after font-relative (percent and em) values
/// have been applied, which is where the keyword
/// comes in. See bug 1355707
Keyword(KeywordSize, f32),
Smaller,
Larger,
+ System(SystemFont)
}
impl From<specified::LengthOrPercentage> for SpecifiedValue {
fn from(other: specified::LengthOrPercentage) -> Self {
SpecifiedValue::Length(other)
}
}
@@ -672,16 +738,22 @@
SpecifiedValue::Smaller => {
FontRelativeLength::Em(0.85).to_computed_value(context,
/* use_inherited */ true)
}
SpecifiedValue::Larger => {
FontRelativeLength::Em(1.2).to_computed_value(context,
/* use_inherited */ true)
}
+
+ SpecifiedValue::System(_) => {
+ <%self:nongecko_unreachable>
+ context.style.cached_system_font.as_ref().unwrap().font_size
+ </%self:nongecko_unreachable>
+ }
}
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
SpecifiedValue::Length(LengthOrPercentage::Length(
ToComputedValue::from_computed_value(computed)
))
@@ -698,16 +770,28 @@
}
match_ignore_ascii_case! {&*input.expect_ident()?,
"smaller" => Ok(SpecifiedValue::Smaller),
"larger" => Ok(SpecifiedValue::Larger),
_ => Err(())
}
}
+ 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
+ }
+ }
+ }
</%helpers:longhand>
<%helpers:longhand products="gecko" name="font-size-adjust" animation_type="normal"
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust">
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
@@ -1796,8 +1880,121 @@ macro_rules! exclusive_value {
}
pub fn parse(_context: &ParserContext, _input: &mut Parser) -> Result<SpecifiedValue, ()> {
debug_assert!(false, "Should be set directly by presentation attributes only.");
Err(())
}
</%helpers:longhand>
+
+% if product == "gecko":
+ pub mod system_font {
+ use app_units::Au;
+ use cssparser::Parser;
+ use properties::longhands;
+ use values::computed::{ToComputedValue, Context};
+ <%
+ system_fonts = """caption icon menu message-box small-caption status-bar
+ -moz-window -moz-document -moz-workspace -moz-desktop
+ -moz-info -moz-dialog -moz-button -moz-pull-down-menu
+ -moz-list -moz-field""".split()
+ %>
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+ pub enum SystemFont {
+ % for font in system_fonts:
+ ${to_camel_case(font)},
+ % endfor
+ }
+
+ impl ToComputedValue for SystemFont {
+ type ComputedValue = ComputedSystemFont;
+
+ fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
+ use gecko_bindings::bindings;
+ use gecko_bindings::structs::{LookAndFeel_FontID, nsFont};
+ use std::mem;
+
+ let id = match *self {
+ % for font in system_fonts:
+ SystemFont::${to_camel_case(font)} => {
+ LookAndFeel_FontID::eFont_${to_camel_case(font.replace("-moz-", ""))}
+ }
+ % endfor
+ };
+
+ let mut system: nsFont = unsafe { mem::uninitialized() };
+ unsafe {
+ bindings::Gecko_nsFont_InitSystem(&mut system, id as i32,
+ cx.style.get_font().gecko(),
+ &*cx.device.pres_context)
+ }
+ let family = system.fontlist.mFontlist.iter().map(|font| {
+ use properties::longhands::font_family::computed_value::*;
+ FontFamily::FamilyName(FamilyName {
+ name: (&*font.mName).into(),
+ quoted: true
+ })
+ }).collect::<Vec<_>>();
+ let ret = ComputedSystemFont {
+ font_family: longhands::font_family::computed_value::T(family),
+ font_size: Au(system.size),
+ system_font: *self,
+ };
+ unsafe { bindings::Gecko_nsFont_Destroy(&mut system); }
+ ret
+ }
+
+ fn from_computed_value(_: &ComputedSystemFont) -> Self {
+ unreachable!()
+ }
+ }
+
+ #[inline]
+ /// Compute and cache a system font
+ ///
+ /// Must be called before attempting to compute a system font
+ /// specified value
+ pub fn resolve_system_font(system: SystemFont, context: &mut Context) {
+ if context.style.cached_system_font.is_none() {
+ let computed = system.to_computed_value(context);
+ context.style.cached_system_font = Some(computed);
+ }
+ debug_assert!(system == context.style.cached_system_font.as_ref().unwrap().system_font)
+ }
+
+ #[derive(Clone, Debug, PartialEq, Eq, Hash)]
+ pub struct ComputedSystemFont {
+ pub font_family: longhands::font_family::computed_value::T,
+ pub font_size: longhands::font_size::computed_value::T,
+ pub system_font: SystemFont,
+ }
+
+ impl SystemFont {
+ pub fn parse(input: &mut Parser) -> Result<Self, ()> {
+ Ok(match_ignore_ascii_case! { &*input.expect_ident()?,
+ % for font in system_fonts:
+ "${font}" => SystemFont::${to_camel_case(font)},
+ % endfor
+ _ => return Err(())
+ })
+ }
+ }
+ }
+% else:
+ pub mod system_font {
+ use cssparser::Parser;
+
+ // We don't parse system fonts, but in the interest of not littering
+ // a lot of code with `if product == gecko` conditionals, we have a
+ // dummy system font module that does nothing
+
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ /// void enum for system font, can never exist
+ pub enum SystemFont {}
+ impl SystemFont {
+ pub fn parse(_: &mut Parser) -> Result<Self, ()> {
+ Err(())
+ }
+ }
+ }
+% endif
--- a/servo/components/style/properties/shorthand/font.mako.rs
+++ b/servo/components/style/properties/shorthand/font.mako.rs
@@ -11,18 +11,19 @@
${'font-kerning' if product == 'gecko' or data.testing else ''}
${'font-variant-alternates' if product == 'gecko' or data.testing else ''}
${'font-variant-east-asian' if product == 'gecko' or data.testing else ''}
${'font-variant-ligatures' if product == 'gecko' or data.testing else ''}
${'font-variant-numeric' if product == 'gecko' or data.testing else ''}
${'font-variant-position' if product == 'gecko' or data.testing else ''}
${'font-language-override' if product == 'gecko' or data.testing else ''}"
spec="https://drafts.csswg.org/css-fonts-3/#propdef-font">
- use properties::longhands::{font_style, font_variant_caps, font_weight, font_stretch};
- use properties::longhands::{font_size, line_height};
+ use properties::longhands::{font_family, font_style, font_weight, font_stretch};
+ use properties::longhands::{font_size, line_height, font_variant_caps};
+ use properties::longhands::system_font::SystemFont;
<%
gecko_sub_properties = "kerning language_override size_adjust \
variant_alternates variant_east_asian \
variant_ligatures variant_numeric \
variant_position".split()
%>
% if product == "gecko" or data.testing:
% for prop in gecko_sub_properties:
@@ -33,16 +34,29 @@
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
let mut nb_normals = 0;
let mut style = None;
let mut variant_caps = None;
let mut weight = None;
let mut stretch = None;
let size;
+ % if product == "gecko":
+ if let Ok(sys) = input.try(SystemFont::parse) {
+ return Ok(Longhands {
+ % for name in "family size".split():
+ font_${name}: font_${name}::SpecifiedValue::system_font(sys),
+ % endfor
+ % for name in "style weight stretch variant_caps".split() + gecko_sub_properties:
+ font_${name}: font_${name}::get_initial_specified_value(),
+ % endfor
+ line_height: line_height::get_initial_specified_value(),
+ })
+ }
+ % endif
loop {
// Special-case 'normal' because it is valid in each of
// font-style, font-weight, font-variant and font-stretch.
// Leaves the values to None, 'normal' is the initial value for each of them.
if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
nb_normals += 1;
continue;
}
@@ -83,17 +97,17 @@
}
let line_height = if input.try(|input| input.expect_delim('/')).is_ok() {
Some(try!(line_height::parse(context, input)))
} else {
None
};
let family = FontFamily::parse(input)?;
Ok(Longhands {
- % for name in "style variant_caps weight stretch size".split():
+ % for name in "style weight stretch size variant_caps".split():
font_${name}: unwrap_or_initial!(font_${name}, ${name}),
% endfor
line_height: unwrap_or_initial!(line_height),
font_family: family,
% if product == "gecko" or data.testing:
% for name in gecko_sub_properties:
font_${name}: font_${name}::get_initial_specified_value(),
% endfor
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1904,17 +1904,17 @@ pub extern "C" fn Servo_GetComputedKeyfr
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let style = ComputedValues::as_arc(&style);
let parent_style = parent_style.as_ref().map(|r| &**ComputedValues::as_arc(&r));
let default_values = data.default_computed_values();
let metrics = get_metrics_provider_for_product();
- let context = Context {
+ let mut context = Context {
is_root_element: false,
device: &data.stylist.device,
inherited_style: parent_style.unwrap_or(default_values),
layout_parent_style: parent_style.unwrap_or(default_values),
style: (**style).clone(),
font_metrics_provider: &metrics,
in_media_query: false,
};
@@ -1932,17 +1932,17 @@ pub extern "C" fn Servo_GetComputedKeyfr
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let guard = declarations.read_with(&guard);
let anim_iter = guard.declarations()
.iter()
.filter_map(|&(ref decl, imp)| {
if imp == Importance::Normal {
let property = TransitionProperty::from_declaration(decl);
- let animation = AnimationValue::from_declaration(decl, &context, default_values);
+ let animation = AnimationValue::from_declaration(decl, &mut context, default_values);
debug_assert!(property.is_none() == animation.is_none(),
"The failure condition of TransitionProperty::from_declaration \
and AnimationValue::from_declaration should be the same");
// Skip the property if either ::from_declaration fails.
if property.is_none() || animation.is_none() {
None
} else {
Some((property.unwrap(), animation.unwrap()))