servo: Merge #10774 - Improve properties.mako.rs file structure, take 2 (from perlun:improve-mako-file-structure-v2); r=SimonSapin

This is a new attempt of #10586, after Simon Sapin's great cleanups in #10749 has landed. I have adjusted the changes to the new structure that was introduced, and also only done a few of the longhand ones. Will certainly continue on this as soon as we have a basic agreement that this style is reasonable.

Source-Repo: https://github.com/servo/servo
Source-Revision: 69acd8e1ccba8ff01e8f7fde4305956ba5ab866d
This commit is contained in:
Per Lundberg 2016-04-22 01:50:28 +05:01
Родитель 7840a81291
Коммит 4887f0639b
10 изменённых файлов: 696 добавлений и 648 удалений

Просмотреть файл

@ -10,6 +10,7 @@ BASE = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(BASE, "Mako-0.9.1.zip"))
from mako import exceptions
from mako.lookup import TemplateLookup
from mako.template import Template
import data
@ -43,10 +44,12 @@ def abort(message):
def render(filename, **context):
try:
lookup = TemplateLookup(directories=[BASE])
template = Template(open(filename, "rb").read(),
filename=filename,
input_encoding="utf8",
strict_undefined=True,
filename=filename)
lookup=lookup,
strict_undefined=True)
# Uncomment to debug generated Python code:
# write("/tmp", "mako_%s.py" % os.path.basename(filename), template.code)
return template.render(**context).encode("utf8")

Просмотреть файл

@ -0,0 +1,191 @@
/* 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/. */
<%! from data import Keyword, to_rust_ident %>
<%def name="longhand(name, **kwargs)">
<%call expr="raw_longhand(name, **kwargs)">
${caller.body()}
% if not data.longhands_by_name[name].derived_from:
pub fn parse_specified(context: &ParserContext, input: &mut Parser)
-> Result<DeclaredValue<SpecifiedValue>, ()> {
parse(context, input).map(DeclaredValue::Value)
}
% endif
</%call>
</%def>
<%def name="predefined_type(name, type, initial_value, parse_method='parse', products='gecko servo')">
<%self:longhand name="${name}" products="${products}">
#[allow(unused_imports)]
use app_units::Au;
pub type SpecifiedValue = specified::${type};
pub mod computed_value {
pub use values::computed::${type} as T;
}
#[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
#[inline] pub fn parse(_context: &ParserContext, input: &mut Parser)
-> Result<SpecifiedValue, ()> {
specified::${type}::${parse_method}(input)
}
</%self:longhand>
</%def>
<%def name="raw_longhand(*args, **kwargs)">
<%
property = data.declare_longhand(*args, **kwargs)
if property is None:
return ""
%>
pub mod ${property.ident} {
#![allow(unused_imports)]
% if not property.derived_from:
use cssparser::Parser;
use parser::ParserContext;
use properties::{CSSWideKeyword, DeclaredValue, Shorthand};
% endif
use error_reporting::ParseErrorReporter;
use properties::longhands;
use properties::property_bit_field::PropertyBitField;
use properties::{ComputedValues, ServoComputedValues, PropertyDeclaration};
use properties::style_struct_traits::${data.current_style_struct.trait_name};
use properties::style_structs;
use std::boxed::Box as StdBox;
use std::collections::HashMap;
use std::sync::Arc;
use values::computed::{TContext, ToComputedValue};
use values::{computed, specified};
use string_cache::Atom;
${caller.body()}
#[allow(unused_variables)]
pub fn cascade_property<C: ComputedValues>(
declaration: &PropertyDeclaration,
inherited_style: &C,
context: &mut computed::Context<C>,
seen: &mut PropertyBitField,
cacheable: &mut bool,
error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
let declared_value = match *declaration {
PropertyDeclaration::${property.camel_case}(ref declared_value) => {
declared_value
}
_ => panic!("entered the wrong cascade_property() implementation"),
};
% if not property.derived_from:
if seen.get_${property.ident}() {
return
}
seen.set_${property.ident}();
{
let custom_props = context.style().custom_properties();
::properties::substitute_variables_${property.ident}(
declared_value, &custom_props, |value| match *value {
DeclaredValue::Value(ref specified_value) => {
let computed = specified_value.to_computed_value(context);
context.mutate_style().mutate_${data.current_style_struct.trait_name_lower}()
.set_${property.ident}(computed);
}
DeclaredValue::WithVariables { .. } => unreachable!(),
DeclaredValue::Initial => {
// We assume that it's faster to use copy_*_from rather than
// set_*(get_initial_value());
let initial_struct = C::initial_values()
.get_${data.current_style_struct.trait_name_lower}();
context.mutate_style().mutate_${data.current_style_struct.trait_name_lower}()
.copy_${property.ident}_from(initial_struct);
},
DeclaredValue::Inherit => {
// This is a bit slow, but this is rare so it shouldn't
// matter.
//
// FIXME: is it still?
*cacheable = false;
let inherited_struct =
inherited_style.get_${data.current_style_struct.trait_name_lower}();
context.mutate_style().mutate_${data.current_style_struct.trait_name_lower}()
.copy_${property.ident}_from(inherited_struct);
}
}, error_reporter
);
}
% if property.custom_cascade:
cascade_property_custom(declaration,
inherited_style,
context,
seen,
cacheable,
error_reporter);
% endif
% else:
// Do not allow stylesheets to set derived properties.
% endif
}
% if not property.derived_from:
pub fn parse_declared(context: &ParserContext, input: &mut Parser)
-> Result<DeclaredValue<SpecifiedValue>, ()> {
match input.try(CSSWideKeyword::parse) {
Ok(CSSWideKeyword::InheritKeyword) => Ok(DeclaredValue::Inherit),
Ok(CSSWideKeyword::InitialKeyword) => Ok(DeclaredValue::Initial),
Ok(CSSWideKeyword::UnsetKeyword) => Ok(DeclaredValue::${
"Inherit" if data.current_style_struct.inherited else "Initial"}),
Err(()) => {
input.look_for_var_functions();
let start = input.position();
let specified = parse_specified(context, input);
if specified.is_err() {
while let Ok(_) = input.next() {} // Look for var() after the error.
}
let var = input.seen_var_functions();
if specified.is_err() && var {
input.reset(start);
let (first_token_type, css) = try!(
::custom_properties::parse_non_custom_with_var(input));
return Ok(DeclaredValue::WithVariables {
css: css.into_owned(),
first_token_type: first_token_type,
base_url: context.base_url.clone(),
from_shorthand: None,
})
}
specified
}
}
}
% endif
}
</%def>
<%def name="single_keyword(name, values, **kwargs)">
<%call expr="single_keyword_computed(name, values, **kwargs)">
use values::computed::ComputedValueAsSpecified;
impl ComputedValueAsSpecified for SpecifiedValue {}
</%call>
</%def>
<%def name="single_keyword_computed(name, values, **kwargs)">
<%
keyword_kwargs = {a: kwargs.pop(a, None) for a in [
'gecko_constant_prefix', 'extra_gecko_values', 'extra_servo_values'
]}
%>
<%call expr="longhand(name, keyword=Keyword(name, values.split(), **keyword_kwargs), **kwargs)">
pub use self::computed_value::T as SpecifiedValue;
${caller.body()}
pub mod computed_value {
define_css_keyword_enum! { T:
% for value in data.longhands_by_name[name].keyword.values_for(product):
"${value}" => ${to_rust_ident(value)},
% endfor
}
}
#[inline] pub fn get_initial_value() -> computed_value::T {
computed_value::T::${to_rust_ident(values.split()[0])}
}
pub fn parse(_context: &ParserContext, input: &mut Parser)
-> Result<SpecifiedValue, ()> {
computed_value::T::parse(input)
}
</%call>
</%def>

Просмотреть файл

@ -0,0 +1,64 @@
/* 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 %>
<% data.new_style_struct("Border", inherited=False, gecko_ffi_name="nsStyleBorder",
additional_methods=[Method("border_" + side + "_is_none_or_hidden_and_has_nonzero_width",
"bool") for side in ["top", "right", "bottom", "left"]]) %>
% for side in ["top", "right", "bottom", "left"]:
${helpers.predefined_type("border-%s-color" % side, "CSSColor", "::cssparser::Color::CurrentColor")}
% endfor
% for side in ["top", "right", "bottom", "left"]:
${helpers.predefined_type("border-%s-style" % side, "BorderStyle", "specified::BorderStyle::none")}
% endfor
% for side in ["top", "right", "bottom", "left"]:
<%helpers:longhand name="border-${side}-width">
use app_units::Au;
use cssparser::ToCss;
use std::fmt;
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.0.to_css(dest)
}
}
#[inline]
pub fn parse(_context: &ParserContext, input: &mut Parser)
-> Result<SpecifiedValue, ()> {
specified::parse_border_width(input).map(SpecifiedValue)
}
#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
pub struct SpecifiedValue(pub specified::Length);
pub mod computed_value {
use app_units::Au;
pub type T = Au;
}
#[inline] pub fn get_initial_value() -> computed_value::T {
Au::from_px(3) // medium
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value<Cx: TContext>(&self, context: &Cx) -> computed_value::T {
self.0.to_computed_value(context)
}
}
</%helpers:longhand>
% endfor
// FIXME(#4126): when gfx supports painting it, make this Size2D<LengthOrPercentage>
% for corner in ["top-left", "top-right", "bottom-right", "bottom-left"]:
${helpers.predefined_type("border-" + corner + "-radius", "BorderRadiusSize",
"computed::BorderRadiusSize::zero()",
"parse")}
% endfor

Просмотреть файл

@ -0,0 +1,129 @@
/* 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, to_rust_ident %>
<% data.new_style_struct("Box",
inherited=False,
gecko_ffi_name="nsStyleDisplay",
additional_methods=[Method("clone_display", "longhands::display::computed_value::T"),
Method("clone_position", "longhands::position::computed_value::T"),
Method("is_floated", "bool"),
Method("overflow_x_is_visible", "bool"),
Method("overflow_y_is_visible", "bool"),
Method("transition_count", "usize")]) %>
// TODO(SimonSapin): don't parse `inline-table`, since we don't support it
<%helpers:longhand name="display" custom_cascade="${product == 'servo'}">
<%
values = """inline block inline-block
table inline-table table-row-group table-header-group table-footer-group
table-row table-column-group table-column table-cell table-caption
list-item flex
none
""".split()
experimental_values = set("flex".split())
%>
pub use self::computed_value::T as SpecifiedValue;
use values::computed::{Context, ComputedValueAsSpecified};
pub mod computed_value {
#[allow(non_camel_case_types)]
#[derive(Clone, Eq, PartialEq, Copy, Hash, RustcEncodable, Debug, HeapSizeOf)]
#[derive(Deserialize, Serialize)]
pub enum T {
% for value in values:
${to_rust_ident(value)},
% endfor
}
impl ::cssparser::ToCss for T {
fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result
where W: ::std::fmt::Write {
match *self {
% for value in values:
T::${to_rust_ident(value)} => dest.write_str("${value}"),
% endfor
}
}
}
}
#[inline] pub fn get_initial_value() -> computed_value::T {
computed_value::T::${to_rust_ident(values[0])}
}
pub fn parse(_context: &ParserContext, input: &mut Parser)
-> Result<SpecifiedValue, ()> {
match_ignore_ascii_case! { try!(input.expect_ident()),
% for value in values:
"${value}" => {
% if value in experimental_values:
if !::util::prefs::get_pref("layout.${value}.enabled")
.as_boolean().unwrap_or(false) {
return Err(())
}
% endif
Ok(computed_value::T::${to_rust_ident(value)})
},
% endfor
_ => Err(())
}
}
impl ComputedValueAsSpecified for SpecifiedValue {}
% if product == "servo":
fn cascade_property_custom<C: ComputedValues>(
_declaration: &PropertyDeclaration,
_inherited_style: &C,
context: &mut computed::Context<C>,
_seen: &mut PropertyBitField,
_cacheable: &mut bool,
_error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
longhands::_servo_display_for_hypothetical_box::derive_from_display(context);
longhands::_servo_text_decorations_in_effect::derive_from_display(context);
}
% endif
</%helpers:longhand>
${helpers.single_keyword("position", "static absolute relative fixed", extra_gecko_values="sticky")}
<%helpers:single_keyword_computed name="float" values="none left right" gecko_ffi_name="mFloats">
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value<Cx: TContext>(&self, context: &Cx) -> computed_value::T {
let positioned = matches!(context.style().get_box().clone_position(),
longhands::position::SpecifiedValue::absolute |
longhands::position::SpecifiedValue::fixed);
if positioned {
SpecifiedValue::none
} else {
*self
}
}
}
</%helpers:single_keyword_computed>
${helpers.single_keyword("clear", "none left right both", gecko_ffi_name="mBreakType")}
<%helpers:longhand name="-servo-display-for-hypothetical-box" derived_from="display" products="servo">
pub use super::display::{SpecifiedValue, get_initial_value};
pub use super::display::{parse};
pub mod computed_value {
pub type T = super::SpecifiedValue;
}
#[inline]
pub fn derive_from_display<Cx: TContext>(context: &mut Cx) {
let d = context.style().get_box().clone_display();
context.mutate_style().mutate_box().set__servo_display_for_hypothetical_box(d);
}
</%helpers:longhand>

Просмотреть файл

@ -0,0 +1,12 @@
/* 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" />
<% data.new_style_struct("Margin", inherited=False, gecko_ffi_name="nsStyleMargin") %>
% for side in ["top", "right", "bottom", "left"]:
${helpers.predefined_type("margin-" + side, "LengthOrPercentageOrAuto",
"computed::LengthOrPercentageOrAuto::Length(Au(0))")}
% endfor

Просмотреть файл

@ -0,0 +1,63 @@
/* 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 %>
<% data.new_style_struct("Outline",
inherited=False,
gecko_ffi_name="nsStyleOutline",
additional_methods=[Method("outline_is_none_or_hidden_and_has_nonzero_width", "bool")]) %>
// TODO(pcwalton): `invert`
${helpers.predefined_type("outline-color", "CSSColor", "::cssparser::Color::CurrentColor")}
<%helpers:longhand name="outline-style">
pub use values::specified::BorderStyle as SpecifiedValue;
pub fn get_initial_value() -> SpecifiedValue { SpecifiedValue::none }
pub mod computed_value {
pub use values::specified::BorderStyle as T;
}
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
match SpecifiedValue::parse(input) {
Ok(SpecifiedValue::hidden) => Err(()),
result => result
}
}
</%helpers:longhand>
<%helpers:longhand name="outline-width">
use app_units::Au;
use cssparser::ToCss;
use std::fmt;
use values::AuExtensionMethods;
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.0.to_css(dest)
}
}
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
specified::parse_border_width(input).map(SpecifiedValue)
}
#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
pub struct SpecifiedValue(pub specified::Length);
pub mod computed_value {
use app_units::Au;
pub type T = Au;
}
pub use super::border_top_width::get_initial_value;
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value<Cx: TContext>(&self, context: &Cx) -> computed_value::T {
self.0.to_computed_value(context)
}
}
</%helpers:longhand>
${helpers.predefined_type("outline-offset", "Length", "Au(0)")}

Просмотреть файл

@ -0,0 +1,13 @@
/* 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" />
<% data.new_style_struct("Padding", inherited=False, gecko_ffi_name="nsStylePadding") %>
% for side in ["top", "right", "bottom", "left"]:
${helpers.predefined_type("padding-" + side, "LengthOrPercentage",
"computed::LengthOrPercentage::Length(Au(0))",
"parse_non_negative")}
% endfor

Просмотреть файл

@ -0,0 +1,58 @@
/* 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" />
<% data.new_style_struct("Position", inherited=False, gecko_ffi_name="nsStylePosition") %>
% for side in ["top", "right", "bottom", "left"]:
${helpers.predefined_type(side, "LengthOrPercentageOrAuto",
"computed::LengthOrPercentageOrAuto::Auto")}
% endfor
<%helpers:longhand name="z-index">
use values::computed::ComputedValueAsSpecified;
impl ComputedValueAsSpecified for SpecifiedValue {}
pub type SpecifiedValue = computed_value::T;
pub mod computed_value {
use cssparser::ToCss;
use std::fmt;
#[derive(PartialEq, Clone, Eq, Copy, Debug, HeapSizeOf)]
pub enum T {
Auto,
Number(i32),
}
impl ToCss for T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
T::Auto => dest.write_str("auto"),
T::Number(number) => write!(dest, "{}", number),
}
}
}
impl T {
pub fn number_or_zero(self) -> i32 {
match self {
T::Auto => 0,
T::Number(value) => value,
}
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T::Auto
}
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
Ok(computed_value::T::Auto)
} else {
specified::parse_integer(input).map(computed_value::T::Number)
}
}
</%helpers:longhand>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -277,7 +277,7 @@ def check_toml(file_name, lines):
def check_rust(file_name, lines):
if not file_name.endswith(".rs") or \
file_name.endswith("properties.mako.rs") or \
file_name.endswith(".mako.rs") or \
file_name.endswith(os.path.join("style", "build.rs")) or \
file_name.endswith(os.path.join("geckolib", "build.rs")) or \
file_name.endswith(os.path.join("unit", "style", "stylesheets.rs")):