--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -123,16 +123,17 @@ whitelist-types = [
"mozilla::HalfCorner",
"mozilla::PropertyStyleAnimationValuePair",
"mozilla::TraversalRestyleBehavior",
"mozilla::TraversalRootBehavior",
"mozilla::StyleShapeRadius",
"mozilla::StyleGrid.*",
"mozilla::UpdateAnimationsTasks",
"mozilla::LookAndFeel",
+ "mozilla::gfx::FontVariation",
".*ThreadSafe.*Holder",
"AnonymousContent",
"AudioContext",
"CapturingContentInfo",
"DefaultDelete",
"DOMIntersectionObserverEntry",
"Element",
"FontFamilyList",
@@ -252,17 +253,18 @@ whitelist-types = [
"mozilla::InheritTarget",
"mozilla::StyleRuleInclusion",
]
opaque-types = [
"std::pair__PCCP",
"std::namespace::atomic___base", "std::atomic__My_base",
"std::atomic",
"std::atomic___base",
- "mozilla::gfx::.*",
+ # We want everything but FontVariation to be opaque but we don't have negative regexes ;_;
+ "mozilla::gfx::(.{0,12}|.{14,}|([^F][^o][^n][^t][^V][^a][^r][^i][^a][^t][^i][^o][^n]))",
"FallibleTArray",
"mozilla::dom::Sequence",
"mozilla::dom::Optional",
"mozilla::dom::Nullable",
"RefPtr_Proxy",
"RefPtr_Proxy_member_function",
"nsAutoPtr_Proxy",
"nsAutoPtr_Proxy_member_function",
--- a/servo/components/style/gecko/generated/structs_debug.rs
+++ b/servo/components/style/gecko/generated/structs_debug.rs
@@ -2383,27 +2383,39 @@ pub mod root {
}
pub type IntRectTyped_Super = u8;
pub type IntRectTyped_Self = u8;
pub type IntRectTyped_ToInt = u32;
pub type IntRect = [u32; 4usize];
#[repr(C)]
#[derive(Debug, Copy)]
pub struct FontVariation {
- pub _bindgen_opaque_blob: [u32; 2usize],
+ pub mTag: u32,
+ pub mValue: f32,
}
#[test]
fn bindgen_test_layout_FontVariation() {
assert_eq!(::std::mem::size_of::<FontVariation>() , 8usize ,
concat ! (
"Size of: " , stringify ! ( FontVariation ) ));
assert_eq! (::std::mem::align_of::<FontVariation>() , 4usize ,
concat ! (
"Alignment of " , stringify ! ( FontVariation )
));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const FontVariation ) ) . mTag as *
+ const _ as usize } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! (
+ FontVariation ) , "::" , stringify ! ( mTag ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const FontVariation ) ) . mValue as
+ * const _ as usize } , 4usize , concat ! (
+ "Alignment of field: " , stringify ! (
+ FontVariation ) , "::" , stringify ! ( mValue )
+ ));
}
impl Clone for FontVariation {
fn clone(&self) -> Self { *self }
}
pub type Matrix4x4 = [u32; 16usize];
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ScaleFactor {
--- a/servo/components/style/gecko/generated/structs_release.rs
+++ b/servo/components/style/gecko/generated/structs_release.rs
@@ -2293,27 +2293,39 @@ pub mod root {
}
pub type IntRectTyped_Super = u8;
pub type IntRectTyped_Self = u8;
pub type IntRectTyped_ToInt = u32;
pub type IntRect = [u32; 4usize];
#[repr(C)]
#[derive(Debug, Copy)]
pub struct FontVariation {
- pub _bindgen_opaque_blob: [u32; 2usize],
+ pub mTag: u32,
+ pub mValue: f32,
}
#[test]
fn bindgen_test_layout_FontVariation() {
assert_eq!(::std::mem::size_of::<FontVariation>() , 8usize ,
concat ! (
"Size of: " , stringify ! ( FontVariation ) ));
assert_eq! (::std::mem::align_of::<FontVariation>() , 4usize ,
concat ! (
"Alignment of " , stringify ! ( FontVariation )
));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const FontVariation ) ) . mTag as *
+ const _ as usize } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! (
+ FontVariation ) , "::" , stringify ! ( mTag ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const FontVariation ) ) . mValue as
+ * const _ as usize } , 4usize , concat ! (
+ "Alignment of field: " , stringify ! (
+ FontVariation ) , "::" , stringify ! ( mValue )
+ ));
}
impl Clone for FontVariation {
fn clone(&self) -> Self { *self }
}
pub type Matrix4x4 = [u32; 16usize];
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ScaleFactor {
--- a/servo/components/style/gecko/rules.rs
+++ b/servo/components/style/gecko/rules.rs
@@ -11,16 +11,17 @@ use counter_style;
use cssparser::UnicodeRange;
use font_face::{FontFaceRuleData, Source, FontDisplay};
use gecko_bindings::bindings;
use gecko_bindings::structs::{self, nsCSSFontFaceRule, nsCSSValue};
use gecko_bindings::structs::{nsCSSCounterDesc, nsCSSCounterStyleRule};
use gecko_bindings::sugar::ns_css_value::ToNsCssValue;
use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr};
use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard};
+use values::generics::FontSettings;
use std::{fmt, str};
/// A @font-face rule
pub type FontFaceRule = RefPtr<nsCSSFontFaceRule>;
impl ToNsCssValue for FamilyName {
fn convert(self, nscssvalue: &mut nsCSSValue) {
nscssvalue.set_string_from_atom(&self.name)
@@ -31,26 +32,26 @@ impl ToNsCssValue for font_weight::T {
fn convert(self, nscssvalue: &mut nsCSSValue) {
nscssvalue.set_integer(self as i32)
}
}
impl ToNsCssValue for font_feature_settings::T {
fn convert(self, nscssvalue: &mut nsCSSValue) {
match self {
- font_feature_settings::T::Normal => nscssvalue.set_normal(),
- font_feature_settings::T::Tag(tags) => {
+ FontSettings::Normal => nscssvalue.set_normal(),
+ FontSettings::Tag(tags) => {
nscssvalue.set_pair_list(tags.into_iter().map(|entry| {
let mut feature = nsCSSValue::null();
let mut raw = [0u8; 4];
(&mut raw[..]).write_u32::<BigEndian>(entry.tag).unwrap();
feature.set_string(str::from_utf8(&raw).unwrap());
let mut index = nsCSSValue::null();
- index.set_integer(entry.value as i32);
+ index.set_integer(entry.value.0 as i32);
(feature, index)
}))
}
}
}
}
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1501,37 +1501,37 @@ fn static_assert() {
}
</%self:impl_trait>
<%
skip_font_longhands = """font-family font-size font-size-adjust font-weight
font-synthesis -x-lang font-variant-alternates
font-variant-east-asian font-variant-ligatures
font-variant-numeric font-language-override
- font-feature-settings"""
+ font-feature-settings font-variation-settings"""
%>
<%self:impl_trait style_struct_name="Font"
skip_longhands="${skip_font_longhands}"
skip_additionals="*">
pub fn set_font_feature_settings(&mut self, v: longhands::font_feature_settings::computed_value::T) {
- use properties::longhands::font_feature_settings::computed_value::T;
+ use values::generics::FontSettings;
let current_settings = &mut self.gecko.mFont.fontFeatureSettings;
current_settings.clear_pod();
match v {
- T::Normal => unsafe { current_settings.set_len_pod(0) },
-
- T::Tag(feature_settings) => {
+ FontSettings::Normal => (), // do nothing, length is already 0
+
+ FontSettings::Tag(feature_settings) => {
unsafe { current_settings.set_len_pod(feature_settings.len() as u32) };
for (current, feature) in current_settings.iter_mut().zip(feature_settings) {
current.mTag = feature.tag;
- current.mValue = feature.value;
+ current.mValue = feature.value.0;
}
}
};
}
pub fn copy_font_feature_settings_from(&mut self, other: &Self ) {
let current_settings = &mut self.gecko.mFont.fontFeatureSettings;
let feature_settings = &other.gecko.mFont.fontFeatureSettings;
@@ -1541,16 +1541,50 @@ fn static_assert() {
unsafe { current_settings.set_len_pod(settings_length) };
for (current, feature) in current_settings.iter_mut().zip(feature_settings.iter()) {
current.mTag = feature.mTag;
current.mValue = feature.mValue;
}
}
+ pub fn set_font_variation_settings(&mut self, v: longhands::font_variation_settings::computed_value::T) {
+ use values::generics::FontSettings;
+
+ let current_settings = &mut self.gecko.mFont.fontVariationSettings;
+ current_settings.clear_pod();
+
+ match v {
+ FontSettings::Normal => (), // do nothing, length is already 0
+
+ FontSettings::Tag(feature_settings) => {
+ unsafe { current_settings.set_len_pod(feature_settings.len() as u32) };
+
+ for (current, feature) in current_settings.iter_mut().zip(feature_settings) {
+ current.mTag = feature.tag;
+ current.mValue = feature.value.0;
+ }
+ }
+ };
+ }
+
+ pub fn copy_font_variation_settings_from(&mut self, other: &Self ) {
+ let current_settings = &mut self.gecko.mFont.fontVariationSettings;
+ let feature_settings = &other.gecko.mFont.fontVariationSettings;
+ let settings_length = feature_settings.len() as u32;
+
+ current_settings.clear_pod();
+ unsafe { current_settings.set_len_pod(settings_length) };
+
+ for (current, feature) in current_settings.iter_mut().zip(feature_settings.iter()) {
+ current.mTag = feature.mTag;
+ current.mValue = feature.mValue;
+ }
+ }
+
pub fn fixup_none_generic(&mut self, device: &Device) {
unsafe {
bindings::Gecko_nsStyleFont_FixupNoneGeneric(&mut self.gecko, &*device.pres_context)
}
}
pub fn set_font_family(&mut self, v: longhands::font_family::computed_value::T) {
use properties::longhands::font_family::computed_value::FontFamily;
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -1769,149 +1769,77 @@ macro_rules! exclusive_value {
animation_value_type="none")}
<%helpers:longhand name="font-feature-settings" products="gecko" animation_value_type="none"
extra_prefixes="moz" boxed="True"
spec="https://drafts.csswg.org/css-fonts/#propdef-font-feature-settings">
use properties::longhands::system_font::SystemFont;
use std::fmt;
use style_traits::ToCss;
+ use values::generics::FontSettings;
#[derive(Debug, Clone, PartialEq)]
pub enum SpecifiedValue {
Value(computed_value::T),
System(SystemFont)
}
no_viewport_percentage!(SpecifiedValue);
<%self:simple_system_boilerplate name="font_feature_settings"></%self:simple_system_boilerplate>
pub mod computed_value {
- use cssparser::Parser;
- use parser::{Parse, ParserContext};
- use std::fmt;
- use style_traits::ToCss;
-
- #[derive(Clone, Debug, Eq, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub enum T {
- Normal,
- Tag(Vec<FeatureTagValue>)
- }
-
- #[derive(Clone, Debug, Eq, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct FeatureTagValue {
- pub tag: u32,
- pub value: u32
- }
-
- impl ToCss for T {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- T::Normal => dest.write_str("normal"),
- T::Tag(ref ftvs) => {
- let mut iter = ftvs.iter();
- // handle head element
- try!(iter.next().unwrap().to_css(dest));
- // handle tail, precede each with a delimiter
- for ftv in iter {
- try!(dest.write_str(", "));
- try!(ftv.to_css(dest));
- }
- Ok(())
- }
- }
- }
- }
-
- impl Parse for T {
- /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
- fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
- if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
- return Ok(T::Normal);
- }
- input.parse_comma_separated(|i| FeatureTagValue::parse(context, i)).map(T::Tag)
- }
- }
-
- impl ToCss for FeatureTagValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- use std::str;
- use byteorder::{WriteBytesExt, BigEndian};
- use cssparser::serialize_string;
-
- let mut raw: Vec<u8> = vec!();
- raw.write_u32::<BigEndian>(self.tag).unwrap();
- serialize_string(str::from_utf8(&raw).unwrap_or_default(), dest)?;
-
- match self.value {
- 1 => Ok(()),
- 0 => dest.write_str(" off"),
- x => write!(dest, " {}", x)
- }
- }
- }
-
- impl Parse for FeatureTagValue {
- /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
- /// <string> [ on | off | <integer> ]
- fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
- use std::io::Cursor;
- use byteorder::{ReadBytesExt, BigEndian};
-
- let tag = try!(input.expect_string());
-
- // allowed strings of length 4 containing chars: <U+20, U+7E>
- if tag.len() != 4 ||
- tag.chars().any(|c| c < ' ' || c > '~')
- {
- return Err(())
- }
-
- let mut raw = Cursor::new(tag.as_bytes());
- let u_tag = raw.read_u32::<BigEndian>().unwrap();
-
- if let Ok(value) = input.try(|input| input.expect_integer()) {
- // handle integer, throw if it is negative
- if value >= 0 {
- Ok(FeatureTagValue { tag: u_tag, value: value as u32 })
- } else {
- Err(())
- }
- } else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) {
- // on is an alias for '1'
- Ok(FeatureTagValue { tag: u_tag, value: 1 })
- } else if let Ok(_) = input.try(|input| input.expect_ident_matching("off")) {
- // off is an alias for '0'
- Ok(FeatureTagValue { tag: u_tag, value: 0 })
- } else {
- // empty value is an alias for '1'
- Ok(FeatureTagValue { tag: u_tag, value: 1 })
- }
- }
- }
+ use values::generics::{FontSettings, FontSettingTagInt};
+ pub type T = FontSettings<FontSettingTagInt>;
}
#[inline]
pub fn get_initial_value() -> computed_value::T {
- computed_value::T::Normal
+ FontSettings::Normal
}
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
- SpecifiedValue::Value(computed_value::T::Normal)
+ SpecifiedValue::Value(FontSettings::Normal)
}
/// normal | <feature-tag-value>#
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
computed_value::T::parse(context, input).map(SpecifiedValue::Value)
}
</%helpers:longhand>
+<%helpers:longhand name="font-variation-settings" products="gecko" animation_value_type="none"
+ boxed="True"
+ spec="https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-the-font-variation-settings-property">
+ use values::computed::ComputedValueAsSpecified;
+ use values::generics::FontSettings;
+
+ impl ComputedValueAsSpecified for SpecifiedValue {}
+
+ pub type SpecifiedValue = computed_value::T;
+
+ no_viewport_percentage!(SpecifiedValue);
+
+
+ pub mod computed_value {
+ use values::generics::{FontSettings, FontSettingTagFloat};
+ pub type T = FontSettings<FontSettingTagFloat>;
+ }
+
+ #[inline]
+ pub fn get_initial_value() -> computed_value::T {
+ FontSettings::Normal
+ }
+
+ /// normal | <feature-tag-value>#
+ pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+ computed_value::T::parse(context, input)
+ }
+</%helpers:longhand>
+
<%helpers:longhand name="font-language-override" products="gecko" animation_value_type="none"
extra_prefixes="moz" boxed="True"
spec="https://drafts.csswg.org/css-fonts-3/#propdef-font-language-override">
use properties::longhands::system_font::SystemFont;
use std::fmt;
use style_traits::ToCss;
use byteorder::{BigEndian, ByteOrder};
no_viewport_percentage!(SpecifiedValue);
--- a/servo/components/style/values/generics/mod.rs
+++ b/servo/components/style/values/generics/mod.rs
@@ -5,17 +5,17 @@
//! Generic types that share their serialization implementations
//! for both specified and computed values.
use counter_style::parse_counter_style_name;
use cssparser::Parser;
use euclid::size::Size2D;
use parser::{Parse, ParserContext};
use std::fmt;
-use style_traits::{HasViewportPercentage, ToCss};
+use style_traits::{HasViewportPercentage, OneOrMoreCommaSeparated, ToCss};
use super::CustomIdent;
pub use self::basic_shape::serialize_radius_values;
pub mod basic_shape;
pub mod border;
pub mod grid;
pub mod image;
@@ -103,8 +103,154 @@ impl ToCss for CounterStyleOrNone {
#[inline]
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self {
&CounterStyleOrNone::None_ => dest.write_str("none"),
&CounterStyleOrNone::Name(ref name) => name.to_css(dest),
}
}
}
+
+/// A settings tag, defined by a four-character tag and a setting value
+///
+/// For font-feature-settings, this is a tag and an integer,
+/// for font-variation-settings this is a tag and a float
+#[derive(Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct FontSettingTag<T> {
+ /// A four-character tag, packed into a u32 (one byte per character)
+ pub tag: u32,
+ /// The value
+ pub value: T,
+}
+
+impl<T> OneOrMoreCommaSeparated for FontSettingTag<T> {}
+
+impl<T: ToCss> ToCss for FontSettingTag<T> {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ use std::str;
+ use byteorder::{WriteBytesExt, BigEndian};
+ use cssparser::serialize_string;
+
+ let mut raw: Vec<u8> = vec!();
+ raw.write_u32::<BigEndian>(self.tag).unwrap();
+ serialize_string(str::from_utf8(&raw).unwrap_or_default(), dest)?;
+
+ self.value.to_css(dest)
+ }
+}
+
+impl<T: Parse> Parse for FontSettingTag<T> {
+ /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
+ /// https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-the-font-variation-settings-property
+ /// <string> [ on | off | <integer> ]
+ /// <string> <number>
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ use std::io::Cursor;
+ use byteorder::{ReadBytesExt, BigEndian};
+
+ let tag = try!(input.expect_string());
+
+ // allowed strings of length 4 containing chars: <U+20, U+7E>
+ if tag.len() != 4 ||
+ tag.chars().any(|c| c < ' ' || c > '~')
+ {
+ return Err(())
+ }
+
+ let mut raw = Cursor::new(tag.as_bytes());
+ let u_tag = raw.read_u32::<BigEndian>().unwrap();
+
+ Ok(FontSettingTag { tag: u_tag, value: T::parse(context, input)? })
+ }
+}
+
+
+/// A font settings value for font-variation-settings or font-feature-settings
+#[derive(Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum FontSettings<T> {
+ /// No settings (default)
+ Normal,
+ /// Set of settings
+ Tag(Vec<FontSettingTag<T>>)
+}
+
+impl<T: ToCss> ToCss for FontSettings<T> {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ FontSettings::Normal => dest.write_str("normal"),
+ FontSettings::Tag(ref ftvs) => ftvs.to_css(dest)
+ }
+ }
+}
+
+impl<T: Parse> Parse for FontSettings<T> {
+ /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
+ return Ok(FontSettings::Normal);
+ }
+ Vec::parse(context, input).map(FontSettings::Tag)
+ }
+}
+
+/// An integer that can also parse "on" and "off",
+/// for font-feature-settings
+///
+/// Do not use this type anywhere except within FontSettings
+/// because it serializes with the preceding space
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub struct FontSettingTagInt(pub u32);
+/// A number value to be used for font-variation-settings
+///
+/// Do not use this type anywhere except within FontSettings
+/// because it serializes with the preceding space
+#[derive(Clone, Debug, PartialEq)]
+pub struct FontSettingTagFloat(pub f32);
+
+impl ToCss for FontSettingTagInt {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match self.0 {
+ 1 => Ok(()),
+ 0 => dest.write_str(" off"),
+ x => write!(dest, " {}", x)
+ }
+ }
+}
+
+impl Parse for FontSettingTagInt {
+ fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ if let Ok(value) = input.try(|input| input.expect_integer()) {
+ // handle integer, throw if it is negative
+ if value >= 0 {
+ Ok(FontSettingTagInt(value as u32))
+ } else {
+ Err(())
+ }
+ } else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) {
+ // on is an alias for '1'
+ Ok(FontSettingTagInt(1))
+ } else if let Ok(_) = input.try(|input| input.expect_ident_matching("off")) {
+ // off is an alias for '0'
+ Ok(FontSettingTagInt(0))
+ } else {
+ // empty value is an alias for '1'
+ Ok(FontSettingTagInt(1))
+ }
+ }
+}
+
+
+impl Parse for FontSettingTagFloat {
+ fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ input.expect_number().map(FontSettingTagFloat)
+ }
+}
+
+impl ToCss for FontSettingTagFloat {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ dest.write_str(" ")?;
+ self.0.to_css(dest)
+ }
+}
+
+