mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +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.
|
||||
/// 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)]
|
||||
pub struct PropertyDeclarationBlock {
|
||||
#[ignore_heap_size_of = "#7038"]
|
||||
|
@ -263,6 +267,121 @@ pub struct PropertyDeclarationBlock {
|
|||
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>,
|
||||
extra_data: ParserContextExtraData)
|
||||
-> PropertyDeclarationBlock {
|
||||
|
@ -401,6 +520,10 @@ pub enum Shorthand {
|
|||
% endfor
|
||||
}
|
||||
|
||||
use std::borrow::ToOwned;
|
||||
use std::iter::FromIterator;
|
||||
use util::str::str_join;
|
||||
|
||||
impl Shorthand {
|
||||
pub fn from_name(name: &str) -> Option<Shorthand> {
|
||||
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] {
|
||||
% for property in data.shorthands:
|
||||
static ${property.ident.upper()}: &'static [&'static str] = &[
|
||||
|
@ -425,6 +556,29 @@ impl Shorthand {
|
|||
% 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)]
|
||||
|
@ -680,6 +834,38 @@ impl PropertyDeclaration {
|
|||
_ => 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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue