stylo: Support font-variation-settings

This commit is contained in:
Manish Goregaokar 2017-05-23 18:15:47 -07:00 committed by Manish Goregaokar
parent dd1cc6bb45
commit 9ed5a7a05e
6 changed files with 259 additions and 117 deletions

View file

@ -1487,27 +1487,27 @@ fn static_assert() {
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) },
FontSettings::Normal => (), // do nothing, length is already 0
T::Tag(feature_settings) => {
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;
}
}
};
@ -1527,6 +1527,40 @@ fn static_assert() {
}
}
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)

View file

@ -1774,6 +1774,7 @@ ${helpers.single_keyword_system("font-variant-position",
use properties::longhands::system_font::SystemFont;
use std::fmt;
use style_traits::ToCss;
use values::generics::FontSettings;
#[derive(Debug, Clone, PartialEq)]
pub enum SpecifiedValue {
@ -1785,120 +1786,18 @@ ${helpers.single_keyword_system("font-variant-position",
<%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>#
@ -1907,6 +1806,41 @@ ${helpers.single_keyword_system("font-variant-position",
}
</%helpers:longhand>
<%
# This spec link is too long to fit elsewhere
variation_spec = """\
https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-the-font-variation-settings-property\
"""
%>
<%helpers:longhand name="font-variation-settings" products="gecko" animation_value_type="none"
boxed="True"
spec="${variation_spec}">
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">