зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #17551 - stylo: implement indexed and count getters for custom properties (from ferjm:bug1375555.stylevariables); r=emilio
From https://bugzilla.mozilla.org/show_bug.cgi?id=1375555 Source-Repo: https://github.com/servo/servo Source-Revision: b3e2b26a238f2e6683156f3aca880c44fc23a424 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : fee6205b019fe709a92d8b19b0ce577554a96dab
This commit is contained in:
Родитель
5a78a77b68
Коммит
7ef05c141f
|
@ -13,7 +13,7 @@ use properties::{CSSWideKeyword, DeclaredValue};
|
|||
use selectors::parser::SelectorParseError;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::{HashMap, hash_map, HashSet};
|
||||
use std::fmt;
|
||||
use style_traits::{HasViewportPercentage, ToCss, StyleParseError, ParseError};
|
||||
use stylearc::Arc;
|
||||
|
@ -92,7 +92,65 @@ impl ToCss for ComputedValue {
|
|||
|
||||
/// A map from CSS variable names to CSS variable computed values, used for
|
||||
/// resolving.
|
||||
pub type ComputedValuesMap = HashMap<Name, ComputedValue>;
|
||||
///
|
||||
/// A consistent ordering is required for CSSDeclaration objects in the
|
||||
/// DOM. CSSDeclarations expose property names as indexed properties, which
|
||||
/// need to be stable. So we keep an array of property names which order is
|
||||
/// determined on the order that they are added to the name-value map.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CustomPropertiesMap {
|
||||
/// Custom property name index.
|
||||
index: Vec<Name>,
|
||||
/// Computed values indexed by custom property name.
|
||||
values: HashMap<Name, ComputedValue>,
|
||||
}
|
||||
|
||||
impl CustomPropertiesMap {
|
||||
/// Creates a new custom properties map.
|
||||
pub fn new() -> Self {
|
||||
CustomPropertiesMap {
|
||||
index: Vec::new(),
|
||||
values: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a computed value if it has not previously been inserted.
|
||||
pub fn insert(&mut self, name: &Name, value: ComputedValue) {
|
||||
debug_assert!(!self.index.contains(name));
|
||||
self.index.push(name.clone());
|
||||
self.values.insert(name.clone(), value);
|
||||
}
|
||||
|
||||
/// Custom property computed value getter by name.
|
||||
pub fn get_computed_value(&self, name: &Name) -> Option<&ComputedValue> {
|
||||
let value = self.values.get(name);
|
||||
debug_assert_eq!(value.is_some(), self.index.contains(name));
|
||||
value
|
||||
}
|
||||
|
||||
/// Get the name of a custom property given its list index.
|
||||
pub fn get_name_at(&self, index: u32) -> Option<&Name> {
|
||||
self.index.get(index as usize)
|
||||
}
|
||||
|
||||
/// Get an iterator for custom properties computed values.
|
||||
pub fn iter(&self) -> hash_map::Iter<Name, ComputedValue> {
|
||||
self.values.iter()
|
||||
}
|
||||
|
||||
/// Get the count of custom properties computed values.
|
||||
pub fn len(&self) -> usize {
|
||||
debug_assert_eq!(self.values.len(), self.index.len());
|
||||
self.values.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for CustomPropertiesMap {}
|
||||
impl PartialEq for CustomPropertiesMap {
|
||||
fn eq(&self, other: &CustomPropertiesMap) -> bool {
|
||||
self.values == other.values && self.index == other.index
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputedValue {
|
||||
fn empty() -> ComputedValue {
|
||||
|
@ -335,7 +393,7 @@ fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>,
|
|||
/// Add one custom property declaration to a map, unless another with the same
|
||||
/// name was already there.
|
||||
pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedSpecifiedValue<'a>>>,
|
||||
inherited: &'a Option<Arc<HashMap<Name, ComputedValue>>>,
|
||||
inherited: &'a Option<Arc<CustomPropertiesMap>>,
|
||||
seen: &mut HashSet<&'a Name>,
|
||||
name: &'a Name,
|
||||
specified_value: DeclaredValue<'a, Box<SpecifiedValue>>) {
|
||||
|
@ -388,8 +446,8 @@ pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedSpec
|
|||
///
|
||||
/// Otherwise, just use the inherited custom properties map.
|
||||
pub fn finish_cascade(specified_values_map: Option<HashMap<&Name, BorrowedSpecifiedValue>>,
|
||||
inherited: &Option<Arc<HashMap<Name, ComputedValue>>>)
|
||||
-> Option<Arc<HashMap<Name, ComputedValue>>> {
|
||||
inherited: &Option<Arc<CustomPropertiesMap>>)
|
||||
-> Option<Arc<CustomPropertiesMap>> {
|
||||
if let Some(mut map) = specified_values_map {
|
||||
remove_cycles(&mut map);
|
||||
Some(Arc::new(substitute_all(map, inherited)))
|
||||
|
@ -445,18 +503,19 @@ fn remove_cycles(map: &mut HashMap<&Name, BorrowedSpecifiedValue>) {
|
|||
|
||||
/// Replace `var()` functions for all custom properties.
|
||||
fn substitute_all(specified_values_map: HashMap<&Name, BorrowedSpecifiedValue>,
|
||||
inherited: &Option<Arc<HashMap<Name, ComputedValue>>>)
|
||||
-> HashMap<Name, ComputedValue> {
|
||||
let mut computed_values_map = HashMap::new();
|
||||
inherited: &Option<Arc<CustomPropertiesMap>>)
|
||||
-> CustomPropertiesMap {
|
||||
let mut custom_properties_map = CustomPropertiesMap::new();
|
||||
let mut invalid = HashSet::new();
|
||||
for (&name, value) in &specified_values_map {
|
||||
// If this value is invalid at computed-time it won’t be inserted in computed_values_map.
|
||||
// Nothing else to do.
|
||||
let _ = substitute_one(
|
||||
name, value, &specified_values_map, inherited, None,
|
||||
&mut computed_values_map, &mut invalid);
|
||||
&mut custom_properties_map, &mut invalid);
|
||||
}
|
||||
computed_values_map
|
||||
|
||||
custom_properties_map
|
||||
}
|
||||
|
||||
/// Replace `var()` functions for one custom property.
|
||||
|
@ -466,12 +525,12 @@ fn substitute_all(specified_values_map: HashMap<&Name, BorrowedSpecifiedValue>,
|
|||
fn substitute_one(name: &Name,
|
||||
specified_value: &BorrowedSpecifiedValue,
|
||||
specified_values_map: &HashMap<&Name, BorrowedSpecifiedValue>,
|
||||
inherited: &Option<Arc<HashMap<Name, ComputedValue>>>,
|
||||
inherited: &Option<Arc<CustomPropertiesMap>>,
|
||||
partial_computed_value: Option<&mut ComputedValue>,
|
||||
computed_values_map: &mut HashMap<Name, ComputedValue>,
|
||||
custom_properties_map: &mut CustomPropertiesMap,
|
||||
invalid: &mut HashSet<Name>)
|
||||
-> Result<TokenSerializationType, ()> {
|
||||
if let Some(computed_value) = computed_values_map.get(name) {
|
||||
if let Some(computed_value) = custom_properties_map.get_computed_value(&name) {
|
||||
if let Some(partial_computed_value) = partial_computed_value {
|
||||
partial_computed_value.push_variable(computed_value)
|
||||
}
|
||||
|
@ -491,7 +550,7 @@ fn substitute_one(name: &Name,
|
|||
&mut |name, partial_computed_value| {
|
||||
if let Some(other_specified_value) = specified_values_map.get(name) {
|
||||
substitute_one(name, other_specified_value, specified_values_map, inherited,
|
||||
Some(partial_computed_value), computed_values_map, invalid)
|
||||
Some(partial_computed_value), custom_properties_map, invalid)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
|
@ -502,7 +561,7 @@ fn substitute_one(name: &Name,
|
|||
partial_computed_value
|
||||
} else {
|
||||
// Invalid at computed-value time. Use the inherited value.
|
||||
if let Some(inherited_value) = inherited.as_ref().and_then(|i| i.get(name)) {
|
||||
if let Some(inherited_value) = inherited.as_ref().and_then(|i| i.values.get(name)) {
|
||||
inherited_value.clone()
|
||||
} else {
|
||||
invalid.insert(name.clone());
|
||||
|
@ -521,7 +580,7 @@ fn substitute_one(name: &Name,
|
|||
partial_computed_value.push_variable(&computed_value)
|
||||
}
|
||||
let last_token_type = computed_value.last_token_type;
|
||||
computed_values_map.insert(name.clone(), computed_value);
|
||||
custom_properties_map.insert(name, computed_value);
|
||||
Ok(last_token_type)
|
||||
}
|
||||
|
||||
|
@ -616,7 +675,7 @@ fn substitute_block<'i, 't, F>(input: &mut Parser<'i, 't>,
|
|||
/// Replace `var()` functions for a non-custom property.
|
||||
/// Return `Err(())` for invalid at computed time.
|
||||
pub fn substitute<'i>(input: &'i str, first_token_type: TokenSerializationType,
|
||||
computed_values_map: &Option<Arc<HashMap<Name, ComputedValue>>>)
|
||||
computed_values_map: &Option<Arc<CustomPropertiesMap>>)
|
||||
-> Result<String, ParseError<'i>> {
|
||||
let mut substituted = ComputedValue::empty();
|
||||
let mut input = ParserInput::new(input);
|
||||
|
@ -624,7 +683,7 @@ pub fn substitute<'i>(input: &'i str, first_token_type: TokenSerializationType,
|
|||
let mut position = (input.position(), first_token_type);
|
||||
let last_token_type = substitute_block(
|
||||
&mut input, &mut position, &mut substituted, &mut |name, substituted| {
|
||||
if let Some(value) = computed_values_map.as_ref().and_then(|map| map.get(name)) {
|
||||
if let Some(value) = computed_values_map.as_ref().and_then(|map| map.get_computed_value(name)) {
|
||||
substituted.push_variable(value);
|
||||
Ok(value.last_token_type)
|
||||
} else {
|
||||
|
|
|
@ -2709,6 +2709,22 @@ extern "C" {
|
|||
RawServoDeclarationBlockBorrowed,
|
||||
buffer: *mut nsAString);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_GetCustomPropertyValue(computed_values:
|
||||
ServoComputedValuesBorrowed,
|
||||
name: *const nsAString,
|
||||
value: *mut nsAString) -> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_GetCustomPropertiesCount(computed_values:
|
||||
ServoComputedValuesBorrowed)
|
||||
-> u32;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_GetCustomPropertyNameAt(arg1: ServoComputedValuesBorrowed,
|
||||
index: u32, name: *mut nsAString)
|
||||
-> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_GetStyleFont(computed_values:
|
||||
ServoComputedValuesBorrowedOrNull)
|
||||
|
|
|
@ -375,7 +375,7 @@ impl PropertyDeclarationIdSet {
|
|||
% else:
|
||||
value: &DeclaredValue<longhands::${property.ident}::SpecifiedValue>,
|
||||
% endif
|
||||
custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||
custom_properties: &Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
f: &mut F,
|
||||
error_reporter: &ParseErrorReporter,
|
||||
quirks_mode: QuirksMode)
|
||||
|
@ -406,7 +406,7 @@ impl PropertyDeclarationIdSet {
|
|||
first_token_type: TokenSerializationType,
|
||||
url_data: &UrlExtraData,
|
||||
from_shorthand: Option<ShorthandId>,
|
||||
custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||
custom_properties: &Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
f: &mut F,
|
||||
error_reporter: &ParseErrorReporter,
|
||||
quirks_mode: QuirksMode)
|
||||
|
@ -1816,7 +1816,7 @@ pub struct ComputedValues {
|
|||
% for style_struct in data.active_style_structs():
|
||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
||||
% endfor
|
||||
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||
custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
/// The writing mode of this computed values struct.
|
||||
pub writing_mode: WritingMode,
|
||||
/// The keyword behind the current font-size property, if any
|
||||
|
@ -1839,7 +1839,7 @@ pub struct ComputedValues {
|
|||
impl ComputedValues {
|
||||
/// Construct a `ComputedValues` instance.
|
||||
pub fn new(
|
||||
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||
custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
writing_mode: WritingMode,
|
||||
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
|
||||
flags: ComputedValueFlags,
|
||||
|
@ -1937,7 +1937,7 @@ impl ComputedValues {
|
|||
// Aah! The << in the return type below is not valid syntax, but we must
|
||||
// escape < that way for Mako.
|
||||
/// Gets a reference to the custom properties map (if one exists).
|
||||
pub fn get_custom_properties(&self) -> Option<<&::custom_properties::ComputedValuesMap> {
|
||||
pub fn get_custom_properties(&self) -> Option<<&::custom_properties::CustomPropertiesMap> {
|
||||
self.custom_properties.as_ref().map(|x| &**x)
|
||||
}
|
||||
|
||||
|
@ -1945,7 +1945,7 @@ impl ComputedValues {
|
|||
///
|
||||
/// Cloning the Arc here is fine because it only happens in the case where
|
||||
/// we have custom properties, and those are both rare and expensive.
|
||||
pub fn custom_properties(&self) -> Option<Arc<::custom_properties::ComputedValuesMap>> {
|
||||
pub fn custom_properties(&self) -> Option<Arc<::custom_properties::CustomPropertiesMap>> {
|
||||
self.custom_properties.clone()
|
||||
}
|
||||
|
||||
|
@ -2241,7 +2241,7 @@ impl ComputedValues {
|
|||
PropertyDeclarationId::Custom(name) => {
|
||||
self.custom_properties
|
||||
.as_ref()
|
||||
.and_then(|map| map.get(name))
|
||||
.and_then(|map| map.get_computed_value(name))
|
||||
.map(|value| value.to_css_string())
|
||||
.unwrap_or(String::new())
|
||||
}
|
||||
|
@ -2401,7 +2401,7 @@ pub struct StyleBuilder<'a> {
|
|||
/// The rule node representing the ordered list of rules matched for this
|
||||
/// node.
|
||||
rules: Option<StrongRuleNode>,
|
||||
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||
custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
/// The writing mode flags.
|
||||
///
|
||||
/// TODO(emilio): Make private.
|
||||
|
@ -2423,7 +2423,7 @@ impl<'a> StyleBuilder<'a> {
|
|||
inherited_style: &'a ComputedValues,
|
||||
reset_style: &'a ComputedValues,
|
||||
rules: Option<StrongRuleNode>,
|
||||
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||
custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
writing_mode: WritingMode,
|
||||
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
|
||||
visited_style: Option<Arc<ComputedValues>>,
|
||||
|
@ -2544,7 +2544,7 @@ impl<'a> StyleBuilder<'a> {
|
|||
///
|
||||
/// Cloning the Arc here is fine because it only happens in the case where
|
||||
/// we have custom properties, and those are both rare and expensive.
|
||||
fn custom_properties(&self) -> Option<Arc<::custom_properties::ComputedValuesMap>> {
|
||||
fn custom_properties(&self) -> Option<Arc<::custom_properties::CustomPropertiesMap>> {
|
||||
self.custom_properties.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3224,15 +3224,16 @@ pub extern "C" fn Servo_StyleSet_HasStateDependency(
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_GetCustomProperty(computed_values: ServoComputedValuesBorrowed,
|
||||
name: *const nsAString, value: *mut nsAString) -> bool {
|
||||
pub extern "C" fn Servo_GetCustomPropertyValue(computed_values: ServoComputedValuesBorrowed,
|
||||
name: *const nsAString,
|
||||
value: *mut nsAString) -> bool {
|
||||
let custom_properties = match ComputedValues::as_arc(&computed_values).custom_properties() {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let name = unsafe { Atom::from((&*name)) };
|
||||
let computed_value = match custom_properties.get(&name) {
|
||||
let computed_value = match custom_properties.get_computed_value(&name) {
|
||||
Some(v) => v,
|
||||
None => return false,
|
||||
};
|
||||
|
@ -3240,3 +3241,31 @@ pub extern "C" fn Servo_GetCustomProperty(computed_values: ServoComputedValuesBo
|
|||
computed_value.to_css(unsafe { value.as_mut().unwrap() }).unwrap();
|
||||
true
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: ServoComputedValuesBorrowed) -> u32 {
|
||||
match ComputedValues::as_arc(&computed_values).custom_properties() {
|
||||
Some(p) => p.len() as u32,
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_GetCustomPropertyNameAt(computed_values: ServoComputedValuesBorrowed,
|
||||
index: u32,
|
||||
name: *mut nsAString) -> bool {
|
||||
let custom_properties = match ComputedValues::as_arc(&computed_values).custom_properties() {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let property_name = match custom_properties.get_name_at(index) {
|
||||
Some(n) => n,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let name = unsafe { name.as_mut().unwrap() };
|
||||
name.assign(&*property_name.as_slice());
|
||||
|
||||
true
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче