mirror of
https://github.com/servo/servo.git
synced 2025-07-25 08:10:21 +01:00
For Shorthand impl, added to_name method and copied serialize_shorthand
from cssstyledeclaration.rs file For PropertyDeclaration impl, added shorthands method to get the shorthands associated with the current longhand For PropertyDeclarationBlock impl, added serialize algorithm
This commit is contained in:
parent
220bdfec2e
commit
feff32c4ab
1 changed files with 186 additions and 0 deletions
|
@ -255,6 +255,10 @@ mod property_bit_field {
|
||||||
|
|
||||||
/// Declarations are stored in reverse order.
|
/// Declarations are stored in reverse order.
|
||||||
/// Overridden declarations are skipped.
|
/// Overridden declarations are skipped.
|
||||||
|
// TODO: Because normal & important are stored in seperate lists, it is impossible to know their
|
||||||
|
// exact declaration order. They should be changed into one list, adding an important/normal
|
||||||
|
// flag to PropertyDeclaration
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, HeapSizeOf)]
|
#[derive(Debug, PartialEq, HeapSizeOf)]
|
||||||
pub struct PropertyDeclarationBlock {
|
pub struct PropertyDeclarationBlock {
|
||||||
#[ignore_heap_size_of = "#7038"]
|
#[ignore_heap_size_of = "#7038"]
|
||||||
|
@ -263,6 +267,121 @@ pub struct PropertyDeclarationBlock {
|
||||||
pub normal: Arc<Vec<PropertyDeclaration>>,
|
pub normal: Arc<Vec<PropertyDeclaration>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PropertyDeclarationBlock {
|
||||||
|
// https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
|
||||||
|
pub fn serialize(&self) -> String {
|
||||||
|
// Step 1
|
||||||
|
let mut result_list = String::new();
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
let mut already_serialized = HashSet::new();
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
// restore order of declarations since PropertyDeclarationBlock is stored in reverse order
|
||||||
|
let declarations = self.normal.iter().rev().chain(self.important.iter().rev()).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
|
||||||
|
for declaration in &declarations {
|
||||||
|
// Step 3.1
|
||||||
|
let property = declaration.name().to_string();
|
||||||
|
|
||||||
|
// Step 3.2
|
||||||
|
if already_serialized.contains(&property) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3.3
|
||||||
|
let mut shorthands = Vec::from(declaration.shorthands());
|
||||||
|
if shorthands.len() > 0 {
|
||||||
|
shorthands.sort_by(|a,b| a.longhands().len().cmp(&b.longhands().len()));
|
||||||
|
|
||||||
|
// Step 3.3.1
|
||||||
|
let mut longhands = declarations.iter().cloned()
|
||||||
|
.filter(|d| !already_serialized.contains(&d.name().to_string()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Step 3.3.2
|
||||||
|
for shorthand in shorthands {
|
||||||
|
let properties = shorthand.longhands();
|
||||||
|
|
||||||
|
// Substep 2 & 3
|
||||||
|
let mut current_longhands = Vec::new();
|
||||||
|
let mut missing_properties: HashSet<_> = HashSet::from_iter(
|
||||||
|
properties.iter().map(|&s| s.to_owned())
|
||||||
|
);
|
||||||
|
|
||||||
|
for longhand in longhands.iter().cloned() {
|
||||||
|
let longhand_string = longhand.name().to_string();
|
||||||
|
if !properties.contains(&&*longhand_string) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
missing_properties.remove(&longhand_string);
|
||||||
|
current_longhands.push(longhand);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Substep 1
|
||||||
|
if current_longhands.len() == 0 || missing_properties.len() > 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Substep 4
|
||||||
|
let important_count = current_longhands.iter()
|
||||||
|
.filter(|l| self.important.contains(l))
|
||||||
|
.count();
|
||||||
|
|
||||||
|
let is_important = important_count > 0;
|
||||||
|
if is_important && important_count != current_longhands.len() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: serialize shorthand does not take is_important into account currently
|
||||||
|
// Substep 5
|
||||||
|
let value = shorthand.serialize_shorthand(¤t_longhands[..]);
|
||||||
|
|
||||||
|
// Substep 6
|
||||||
|
if value.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Substep 7 & 8
|
||||||
|
result_list.push_str(&format!("{}: {}; ", &shorthand.to_name(), value));
|
||||||
|
|
||||||
|
for current_longhand in current_longhands {
|
||||||
|
// Substep 9
|
||||||
|
already_serialized.insert(current_longhand.name().to_string());
|
||||||
|
let index_to_remove = longhands.iter().position(|l| l == ¤t_longhand);
|
||||||
|
if let Some(index) = index_to_remove {
|
||||||
|
// Substep 10
|
||||||
|
longhands.remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3.3.4
|
||||||
|
if already_serialized.contains(&property) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3.3.5
|
||||||
|
let mut value = declaration.value();
|
||||||
|
if self.important.contains(declaration) {
|
||||||
|
value.push_str(" ! important");
|
||||||
|
}
|
||||||
|
// Steps 3.3.6 & 3.3.7
|
||||||
|
result_list.push_str(&format!("{}: {}; ", &property, value));
|
||||||
|
|
||||||
|
// Step 3.3.8
|
||||||
|
already_serialized.insert(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
result_list.pop(); // remove trailling whitespace
|
||||||
|
// Step 4
|
||||||
|
result_list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_style_attribute(input: &str, base_url: &Url, error_reporter: StdBox<ParseErrorReporter + Send>,
|
pub fn parse_style_attribute(input: &str, base_url: &Url, error_reporter: StdBox<ParseErrorReporter + Send>,
|
||||||
extra_data: ParserContextExtraData)
|
extra_data: ParserContextExtraData)
|
||||||
-> PropertyDeclarationBlock {
|
-> PropertyDeclarationBlock {
|
||||||
|
@ -401,6 +520,10 @@ pub enum Shorthand {
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::borrow::ToOwned;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
use util::str::str_join;
|
||||||
|
|
||||||
impl Shorthand {
|
impl Shorthand {
|
||||||
pub fn from_name(name: &str) -> Option<Shorthand> {
|
pub fn from_name(name: &str) -> Option<Shorthand> {
|
||||||
match_ignore_ascii_case! { name,
|
match_ignore_ascii_case! { name,
|
||||||
|
@ -411,6 +534,14 @@ impl Shorthand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_name(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
% for property in SHORTHANDS:
|
||||||
|
Shorthand::${property.camel_case} => "${property.name}",
|
||||||
|
% endfor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn longhands(&self) -> &'static [&'static str] {
|
pub fn longhands(&self) -> &'static [&'static str] {
|
||||||
% for property in data.shorthands:
|
% for property in data.shorthands:
|
||||||
static ${property.ident.upper()}: &'static [&'static str] = &[
|
static ${property.ident.upper()}: &'static [&'static str] = &[
|
||||||
|
@ -425,6 +556,29 @@ impl Shorthand {
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serialize_shorthand(self, declarations: &[&PropertyDeclaration]) -> String {
|
||||||
|
// https://drafts.csswg.org/css-variables/#variables-in-shorthands
|
||||||
|
if let Some(css) = declarations[0].with_variables_from_shorthand(self) {
|
||||||
|
if declarations[1..]
|
||||||
|
.iter()
|
||||||
|
.all(|d| d.with_variables_from_shorthand(self) == Some(css)) {
|
||||||
|
css.to_owned()
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if declarations.iter().any(|d| d.with_variables()) {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
let str_iter = declarations.iter().map(|d| d.value());
|
||||||
|
// FIXME: this needs property-specific code, which probably should be in style/
|
||||||
|
// "as appropriate according to the grammar of shorthand "
|
||||||
|
// https://drafts.csswg.org/cssom/#serialize-a-css-value
|
||||||
|
str_join(str_iter, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, HeapSizeOf)]
|
#[derive(Clone, PartialEq, Eq, Debug, HeapSizeOf)]
|
||||||
|
@ -680,6 +834,38 @@ impl PropertyDeclaration {
|
||||||
_ => PropertyDeclarationParseResult::UnknownProperty
|
_ => PropertyDeclarationParseResult::UnknownProperty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn shorthands(&self) -> &[Shorthand] {
|
||||||
|
// first generate longhand to shorthands lookup map
|
||||||
|
<%
|
||||||
|
longhand_to_shorthand_map = {}
|
||||||
|
for shorthand in SHORTHANDS:
|
||||||
|
for sub_property in shorthand.sub_properties:
|
||||||
|
if sub_property.ident not in longhand_to_shorthand_map:
|
||||||
|
longhand_to_shorthand_map[sub_property.ident] = []
|
||||||
|
|
||||||
|
longhand_to_shorthand_map[sub_property.ident].append(shorthand.camel_case)
|
||||||
|
|
||||||
|
for shorthand_list in longhand_to_shorthand_map.itervalues():
|
||||||
|
shorthand_list.sort()
|
||||||
|
%>
|
||||||
|
|
||||||
|
// based on lookup results for each longhand, create result arrays
|
||||||
|
% for property in LONGHANDS:
|
||||||
|
static ${property.ident.upper()}: &'static [Shorthand] = &[
|
||||||
|
% for shorthand in longhand_to_shorthand_map.get(property.ident, []):
|
||||||
|
Shorthand::${shorthand},
|
||||||
|
% endfor
|
||||||
|
];
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
% for property in LONGHANDS:
|
||||||
|
PropertyDeclaration::${property.camel_case}(_) => ${property.ident.upper()},
|
||||||
|
% endfor
|
||||||
|
_ => &[] // include outlet for Custom enum value
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod style_struct_traits {
|
pub mod style_struct_traits {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue