Auto merge of #17058 - Manishearth:stylo-randomprops, r=emilio

stylo: Support remaning longhands

r=xidorn https://bugzilla.mozilla.org/show_bug.cgi?id=1367275

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17058)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-05-27 13:37:59 -05:00 committed by GitHub
commit 369d5cf124
14 changed files with 425 additions and 166 deletions

View file

@ -1486,27 +1486,28 @@ 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
-moz-min-font-size-ratio"""
%>
<%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;
}
}
};
@ -1526,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)
@ -1595,7 +1630,6 @@ fn static_assert() {
// actual computed size, and the other of which (mFont.size) is the 'display
// size' which takes font zooming into account. We don't handle font zooming yet.
pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) {
self.gecko.mFont.size = v.0;
self.gecko.mSize = v.0;
self.gecko.mScriptUnconstrainedSize = v.0;
}
@ -1603,21 +1637,27 @@ fn static_assert() {
/// Set font size, taking into account scriptminsize and scriptlevel
/// Returns Some(size) if we have to recompute the script unconstrained size
pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T,
parent: &Self) -> Option<Au> {
parent: &Self,
device: &Device) -> Option<Au> {
let (adjusted_size, adjusted_unconstrained_size)
= self.calculate_script_level_size(parent);
// In this case, we have been unaffected by scriptminsize, ignore it
if parent.gecko.mSize == parent.gecko.mScriptUnconstrainedSize &&
adjusted_size == adjusted_unconstrained_size {
self.set_font_size(v);
self.fixup_font_min_size(device);
None
} else {
self.gecko.mFont.size = v.0;
self.gecko.mSize = v.0;
self.fixup_font_min_size(device);
Some(Au(parent.gecko.mScriptUnconstrainedSize))
}
}
pub fn fixup_font_min_size(&mut self, device: &Device) {
unsafe { bindings::Gecko_nsStyleFont_FixupMinFontSize(&mut self.gecko, &*device.pres_context) }
}
pub fn apply_unconstrained_font_size(&mut self, v: Au) {
self.gecko.mScriptUnconstrainedSize = v.0;
}
@ -1726,7 +1766,8 @@ fn static_assert() {
///
/// Returns true if the inherited keyword size was actually used
pub fn inherit_font_size_from(&mut self, parent: &Self,
kw_inherited_size: Option<Au>) -> bool {
kw_inherited_size: Option<Au>,
device: &Device) -> bool {
let (adjusted_size, adjusted_unconstrained_size)
= self.calculate_script_level_size(parent);
if adjusted_size.0 != parent.gecko.mSize ||
@ -1745,23 +1786,23 @@ fn static_assert() {
// In the case that MathML has given us an adjusted size, apply it.
// Keep track of the unconstrained adjusted size.
self.gecko.mFont.size = adjusted_size.0;
self.gecko.mSize = adjusted_size.0;
self.gecko.mScriptUnconstrainedSize = adjusted_unconstrained_size.0;
self.fixup_font_min_size(device);
false
} else if let Some(size) = kw_inherited_size {
// Parent element was a keyword-derived size.
self.gecko.mFont.size = size.0;
self.gecko.mSize = size.0;
// MathML constraints didn't apply here, so we can ignore this.
self.gecko.mScriptUnconstrainedSize = size.0;
self.fixup_font_min_size(device);
true
} else {
// MathML isn't affecting us, and our parent element does not
// have a keyword-derived size. Set things normally.
self.gecko.mFont.size = parent.gecko.mFont.size;
self.gecko.mSize = parent.gecko.mSize;
self.gecko.mScriptUnconstrainedSize = parent.gecko.mScriptUnconstrainedSize;
self.fixup_font_min_size(device);
false
}
}
@ -1864,6 +1905,21 @@ fn static_assert() {
}
${impl_simple_copy('font_variant_numeric', 'mFont.variantNumeric')}
#[allow(non_snake_case)]
pub fn set__moz_min_font_size_ratio(&mut self, v: longhands::_moz_min_font_size_ratio::computed_value::T) {
let percentage = if v.0 > 255. {
255.
} else if v.0 < 0. {
0.
} else {
v.0
};
self.gecko.mMinFontSizeRatio = percentage as u8;
}
${impl_simple_copy('_moz_min_font_size_ratio', 'mMinFontSizeRatio')}
</%self:impl_trait>
<%def name="impl_copy_animation_or_transition_value(type, ident, gecko_ffi_name)">
@ -4003,7 +4059,7 @@ clip-path
</%self:impl_trait>
<%self:impl_trait style_struct_name="InheritedSVG"
skip_longhands="paint-order stroke-dasharray stroke-dashoffset stroke-width"
skip_longhands="paint-order stroke-dasharray stroke-dashoffset stroke-width -moz-context-properties"
skip_additionals="*">
pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) {
use self::longhands::paint_order;
@ -4111,6 +4167,34 @@ clip-path
_ => unreachable!(),
}
}
#[allow(non_snake_case)]
pub fn set__moz_context_properties<I>(&mut self, v: I)
where I: IntoIterator<Item = longhands::_moz_context_properties::computed_value::single_value::T>,
I::IntoIter: ExactSizeIterator
{
let v = v.into_iter();
unsafe {
bindings::Gecko_nsStyleSVG_SetContextPropertiesLength(&mut self.gecko, v.len() as u32);
}
self.gecko.mContextPropsBits = 0;
for (mut gecko, servo) in self.gecko.mContextProps.iter_mut().zip(v) {
if servo.0 == atom!("fill") {
self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL as u8;
} else if servo.0 == atom!("stroke") {
self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE as u8;
}
unsafe { gecko.set_raw_from_addrefed::<structs::nsIAtom>(servo.0.into_addrefed()) }
}
}
#[allow(non_snake_case)]
pub fn copy__moz_context_properties_from(&mut self, other: &Self) {
unsafe {
bindings::Gecko_nsStyleSVG_CopyContextProperties(&mut self.gecko, &other.gecko);
}
}
</%self:impl_trait>
<%self:impl_trait style_struct_name="Color"

View file

@ -54,9 +54,8 @@ ${helpers.predefined_type("column-rule-color", "CSSColor",
complex_color=True, need_clone=True,
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-color")}
// It's not implemented in servo or gecko yet.
${helpers.single_keyword("column-span", "none all",
products="none", animation_value_type="none",
products="gecko", animation_value_type="none",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-span")}
${helpers.single_keyword("column-rule-style",

View file

@ -925,10 +925,12 @@ ${helpers.single_keyword_system("font-variant-caps",
}
% endif
let parent_unconstrained = context.mutate_style()
.mutate_font()
.apply_font_size(computed,
parent);
let parent_unconstrained = {
let (style, device) = context.mutate_style_with_device();
style.mutate_font().apply_font_size(computed, parent, device)
};
if let Some(parent) = parent_unconstrained {
let new_unconstrained = specified_value
@ -946,13 +948,14 @@ ${helpers.single_keyword_system("font-variant-caps",
let kw_inherited_size = context.style().font_size_keyword.map(|(kw, ratio)| {
SpecifiedValue::Keyword(kw, ratio).to_computed_value(context)
});
let used_kw = context.mutate_style().mutate_font()
.inherit_font_size_from(parent, kw_inherited_size);
let parent_kw = context.inherited_style.font_computation_data.font_size_keyword;
let (style, device) = context.mutate_style_with_device();
let used_kw = style.mutate_font()
.inherit_font_size_from(parent, kw_inherited_size, device);
if used_kw {
context.mutate_style().font_size_keyword =
context.inherited_style.font_computation_data.font_size_keyword;
style.font_size_keyword = parent_kw;
} else {
context.mutate_style().font_size_keyword = None;
style.font_size_keyword = None;
}
}
@ -961,9 +964,12 @@ ${helpers.single_keyword_system("font-variant-caps",
// compute to the same value and depends on the font
let computed = longhands::font_size::get_initial_specified_value()
.to_computed_value(context);
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
.set_font_size(computed);
context.mutate_style().font_size_keyword = Some((Default::default(), 1.));
let (style, _device) = context.mutate_style_with_device();
style.mutate_font().set_font_size(computed);
% if product == "gecko":
style.mutate_font().fixup_font_min_size(_device);
% endif
style.font_size_keyword = Some((Default::default(), 1.));
}
</%helpers:longhand>
@ -1774,6 +1780,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 +1792,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 +1812,40 @@ ${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"
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">
@ -2453,3 +2392,11 @@ ${helpers.single_keyword("-moz-osx-font-smoothing",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth)",
animation_value_type="none",
need_clone=True)}
${helpers.predefined_type("-moz-min-font-size-ratio",
"Percentage",
"computed::Percentage::hundred()",
animation_value_type="none",
products="gecko",
internal=True,
spec="Nonstandard (Internal-only)")}

View file

@ -268,3 +268,28 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
impl ComputedValueAsSpecified for SpecifiedValue { }
</%helpers:longhand>
<%helpers:vector_longhand name="-moz-context-properties"
animation_value_type="none"
products="gecko"
spec="Nonstandard (Internal-only)"
internal="True"
allow_empty="True">
use values::CustomIdent;
use values::computed::ComputedValueAsSpecified;
no_viewport_percentage!(SpecifiedValue);
impl ComputedValueAsSpecified for SpecifiedValue { }
pub type SpecifiedValue = CustomIdent;
pub mod computed_value {
pub type T = super::SpecifiedValue;
}
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
let i = input.expect_ident()?;
CustomIdent::from_ident(i, &["all", "none", "auto"])
}
</%helpers:vector_longhand>

View file

@ -31,6 +31,13 @@ ${helpers.single_keyword("-moz-window-dragging", "default drag no-drag", product
animation_value_type="none",
spec="None (Nonstandard Firefox-only property)")}
${helpers.single_keyword("-moz-window-shadow", "none default menu tooltip sheet", products="gecko",
gecko_ffi_name="mWindowShadow",
gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW",
animation_value_type="none",
internal=True,
spec="None (Nonstandard internal property)")}
<%helpers:longhand name="-moz-force-broken-image-icon"
products="gecko"
animation_value_type="none"

View file

@ -607,6 +607,7 @@ impl LonghandId {
LonghandId::TransitionProperty |
LonghandId::XLang |
LonghandId::MozScriptLevel |
LonghandId::MozMinFontSizeRatio |
% endif
LonghandId::FontSize |
LonghandId::FontFamily |
@ -1524,6 +1525,7 @@ pub mod style_structs {
use super::longhands;
use std::hash::{Hash, Hasher};
use logical_geometry::WritingMode;
use media_queries::Device;
% for style_struct in data.active_style_structs():
% if style_struct.name == "Font":
@ -1634,14 +1636,15 @@ pub mod style_structs {
/// (Servo does not handle MathML, so this just calls copy_font_size_from)
pub fn inherit_font_size_from(&mut self, parent: &Self,
_: Option<Au>) -> bool {
_: Option<Au>, _: &Device) -> bool {
self.copy_font_size_from(parent);
false
}
/// (Servo does not handle MathML, so this just calls set_font_size)
pub fn apply_font_size(&mut self,
v: longhands::font_size::computed_value::T,
_: &Self) -> Option<Au> {
_: &Self,
_: &Device) -> Option<Au> {
self.set_font_size(v);
None
}
@ -2628,17 +2631,6 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
continue
}
// The computed value of some properties depends on the
// (sometimes computed) value of *other* properties.
//
// So we classify properties into "early" and "other", such that
// the only dependencies can be from "other" to "early".
//
// We iterate applicable_declarations twice, first cascading
// "early" properties then "other".
//
// Unfortunately, its not easy to check that this
// classification is correct.
if
% if category_to_cascade_now == "early":
!
@ -2718,6 +2710,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
// scriptlevel changes.
} else if seen.contains(LonghandId::XLang) ||
seen.contains(LonghandId::MozScriptLevel) ||
seen.contains(LonghandId::MozMinFontSizeRatio) ||
font_family.is_some() {
let discriminant = LonghandId::FontSize as usize;
let size = PropertyDeclaration::CSSWideKeyword(