mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
style: Add a very simple use counter implementation.
As simple as I could make it, for now. We can improve on this. Differential Revision: https://phabricator.services.mozilla.com/D3827
This commit is contained in:
parent
c3a4b27441
commit
c8e5b7f1b0
4 changed files with 105 additions and 45 deletions
|
@ -157,6 +157,7 @@ pub mod thread_state;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod traversal;
|
pub mod traversal;
|
||||||
pub mod traversal_flags;
|
pub mod traversal_flags;
|
||||||
|
pub mod use_counters;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub mod values;
|
pub mod values;
|
||||||
|
|
|
@ -9,6 +9,7 @@ use cssparser::{Parser, SourceLocation, UnicodeRange};
|
||||||
use error_reporting::{ContextualParseError, ParseErrorReporter};
|
use error_reporting::{ContextualParseError, ParseErrorReporter};
|
||||||
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
|
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
|
||||||
use stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData};
|
use stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData};
|
||||||
|
use use_counters::UseCounters;
|
||||||
|
|
||||||
/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
|
/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -53,6 +54,8 @@ pub struct ParserContext<'a> {
|
||||||
error_reporter: Option<&'a ParseErrorReporter>,
|
error_reporter: Option<&'a ParseErrorReporter>,
|
||||||
/// The currently active namespaces.
|
/// The currently active namespaces.
|
||||||
pub namespaces: Option<&'a Namespaces>,
|
pub namespaces: Option<&'a Namespaces>,
|
||||||
|
/// The use counters we want to record while parsing style rules, if any.
|
||||||
|
pub use_counters: Option<&'a UseCounters>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ParserContext<'a> {
|
impl<'a> ParserContext<'a> {
|
||||||
|
@ -66,7 +69,7 @@ impl<'a> ParserContext<'a> {
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
error_reporter: Option<&'a ParseErrorReporter>,
|
error_reporter: Option<&'a ParseErrorReporter>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ParserContext {
|
Self {
|
||||||
stylesheet_origin,
|
stylesheet_origin,
|
||||||
url_data,
|
url_data,
|
||||||
rule_type,
|
rule_type,
|
||||||
|
@ -74,6 +77,7 @@ impl<'a> ParserContext<'a> {
|
||||||
quirks_mode,
|
quirks_mode,
|
||||||
error_reporter,
|
error_reporter,
|
||||||
namespaces: None,
|
namespaces: None,
|
||||||
|
use_counters: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,14 +100,15 @@ impl<'a> ParserContext<'a> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a parser context based on a previous context, but with a modified rule type.
|
/// Create a parser context based on a previous context, but with a modified
|
||||||
|
/// rule type.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_with_rule_type(
|
pub fn new_with_rule_type(
|
||||||
context: &'a ParserContext,
|
context: &'a ParserContext,
|
||||||
rule_type: CssRuleType,
|
rule_type: CssRuleType,
|
||||||
namespaces: &'a Namespaces,
|
namespaces: &'a Namespaces,
|
||||||
) -> ParserContext<'a> {
|
) -> ParserContext<'a> {
|
||||||
ParserContext {
|
Self {
|
||||||
stylesheet_origin: context.stylesheet_origin,
|
stylesheet_origin: context.stylesheet_origin,
|
||||||
url_data: context.url_data,
|
url_data: context.url_data,
|
||||||
rule_type: Some(rule_type),
|
rule_type: Some(rule_type),
|
||||||
|
@ -111,6 +116,7 @@ impl<'a> ParserContext<'a> {
|
||||||
quirks_mode: context.quirks_mode,
|
quirks_mode: context.quirks_mode,
|
||||||
namespaces: Some(namespaces),
|
namespaces: Some(namespaces),
|
||||||
error_reporter: context.error_reporter,
|
error_reporter: context.error_reporter,
|
||||||
|
use_counters: context.use_counters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -425,6 +425,10 @@ pub mod animated_properties {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct NonCustomPropertyId(usize);
|
pub struct NonCustomPropertyId(usize);
|
||||||
|
|
||||||
|
/// The length of all the non-custom properties.
|
||||||
|
pub const NON_CUSTOM_PROPERTY_ID_COUNT: usize =
|
||||||
|
${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())};
|
||||||
|
|
||||||
% if product == "gecko":
|
% if product == "gecko":
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
unsafe fn static_assert_nscsspropertyid() {
|
unsafe fn static_assert_nscsspropertyid() {
|
||||||
|
@ -435,6 +439,11 @@ unsafe fn static_assert_nscsspropertyid() {
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
impl NonCustomPropertyId {
|
impl NonCustomPropertyId {
|
||||||
|
/// Returns the underlying index, used for use counter.
|
||||||
|
pub fn bit(self) -> usize {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_nscsspropertyid(self) -> nsCSSPropertyID {
|
fn to_nscsspropertyid(self) -> nsCSSPropertyID {
|
||||||
|
@ -450,7 +459,7 @@ impl NonCustomPropertyId {
|
||||||
if prop < 0 {
|
if prop < 0 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
if prop >= ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} {
|
if prop >= NON_CUSTOM_PROPERTY_ID_COUNT as i32 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
// unsafe: guaranteed by static_assert_nscsspropertyid above.
|
// unsafe: guaranteed by static_assert_nscsspropertyid above.
|
||||||
|
@ -460,7 +469,7 @@ impl NonCustomPropertyId {
|
||||||
/// Get the property name.
|
/// Get the property name.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn name(self) -> &'static str {
|
pub fn name(self) -> &'static str {
|
||||||
static MAP: [&'static str; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
|
static MAP: [&'static str; NON_CUSTOM_PROPERTY_ID_COUNT] = [
|
||||||
% for property in data.longhands + data.shorthands + data.all_aliases():
|
% for property in data.longhands + data.shorthands + data.all_aliases():
|
||||||
"${property.name}",
|
"${property.name}",
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -635,7 +644,7 @@ impl NonCustomPropertyId {
|
||||||
PropertyId::Shorthand(transmute((self.0 - ${len(data.longhands)}) as u16))
|
PropertyId::Shorthand(transmute((self.0 - ${len(data.longhands)}) as u16))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(self.0 < ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())});
|
assert!(self.0 < NON_CUSTOM_PROPERTY_ID_COUNT);
|
||||||
let alias_id: AliasId = unsafe {
|
let alias_id: AliasId = unsafe {
|
||||||
transmute((self.0 - ${len(data.longhands) + len(data.shorthands)}) as u16)
|
transmute((self.0 - ${len(data.longhands) + len(data.shorthands)}) as u16)
|
||||||
};
|
};
|
||||||
|
@ -671,7 +680,7 @@ impl From<AliasId> for NonCustomPropertyId {
|
||||||
/// A set of all properties
|
/// A set of all properties
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct NonCustomPropertyIdSet {
|
pub struct NonCustomPropertyIdSet {
|
||||||
storage: [u32; (${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} - 1 + 32) / 32]
|
storage: [u32; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + 32) / 32]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonCustomPropertyIdSet {
|
impl NonCustomPropertyIdSet {
|
||||||
|
@ -2198,7 +2207,7 @@ impl PropertyDeclaration {
|
||||||
// FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774
|
// FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774
|
||||||
// before adding skip_whitespace here.
|
// before adding skip_whitespace here.
|
||||||
// This probably affects some test results.
|
// This probably affects some test results.
|
||||||
let value = match input.try(|i| CSSWideKeyword::parse(i)) {
|
let value = match input.try(CSSWideKeyword::parse) {
|
||||||
Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword),
|
Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword),
|
||||||
Err(()) => match ::custom_properties::SpecifiedValue::parse(input) {
|
Err(()) => match ::custom_properties::SpecifiedValue::parse(input) {
|
||||||
Ok(value) => DeclaredValueOwned::Value(value),
|
Ok(value) => DeclaredValueOwned::Value(value),
|
||||||
|
@ -2212,12 +2221,12 @@ impl PropertyDeclaration {
|
||||||
name: property_name,
|
name: property_name,
|
||||||
value,
|
value,
|
||||||
}));
|
}));
|
||||||
Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
PropertyId::LonghandAlias(id, _) |
|
PropertyId::LonghandAlias(id, _) |
|
||||||
PropertyId::Longhand(id) => {
|
PropertyId::Longhand(id) => {
|
||||||
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
|
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
|
||||||
input.try(|i| CSSWideKeyword::parse(i)).map(|keyword| {
|
input.try(CSSWideKeyword::parse).map(|keyword| {
|
||||||
PropertyDeclaration::CSSWideKeyword(
|
PropertyDeclaration::CSSWideKeyword(
|
||||||
WideKeywordDeclaration { id, keyword },
|
WideKeywordDeclaration { id, keyword },
|
||||||
)
|
)
|
||||||
|
@ -2253,12 +2262,12 @@ impl PropertyDeclaration {
|
||||||
})
|
})
|
||||||
}).map(|declaration| {
|
}).map(|declaration| {
|
||||||
declarations.push(declaration)
|
declarations.push(declaration)
|
||||||
})
|
})?;
|
||||||
}
|
}
|
||||||
PropertyId::ShorthandAlias(id, _) |
|
PropertyId::ShorthandAlias(id, _) |
|
||||||
PropertyId::Shorthand(id) => {
|
PropertyId::Shorthand(id) => {
|
||||||
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
|
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
|
||||||
if let Ok(keyword) = input.try(|i| CSSWideKeyword::parse(i)) {
|
if let Ok(keyword) = input.try(CSSWideKeyword::parse) {
|
||||||
if id == ShorthandId::All {
|
if id == ShorthandId::All {
|
||||||
declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword)
|
declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword)
|
||||||
} else {
|
} else {
|
||||||
|
@ -2271,14 +2280,19 @@ impl PropertyDeclaration {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
input.look_for_var_functions();
|
input.look_for_var_functions();
|
||||||
// Not using parse_entirely here: each ${shorthand.ident}::parse_into function
|
// Not using parse_entirely here: each ${shorthand.ident}::parse_into function
|
||||||
// needs to do so *before* pushing to `declarations`.
|
// needs to do so *before* pushing to `declarations`.
|
||||||
id.parse_into(declarations, context, input).or_else(|err| {
|
id.parse_into(declarations, context, input).or_else(|err| {
|
||||||
while let Ok(_) = input.next() {} // Look for var() after the error.
|
while let Ok(_) = input.next() {} // Look for var() after the error.
|
||||||
if input.seen_var_functions() {
|
if !input.seen_var_functions() {
|
||||||
|
return Err(StyleParseErrorKind::new_invalid(
|
||||||
|
non_custom_id.unwrap().name(),
|
||||||
|
err,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
input.reset(&start);
|
input.reset(&start);
|
||||||
let (first_token_type, css) =
|
let (first_token_type, css) =
|
||||||
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
|
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
|
||||||
|
@ -2306,16 +2320,15 @@ impl PropertyDeclaration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
})?;
|
||||||
Err(StyleParseErrorKind::new_invalid(
|
|
||||||
non_custom_id.unwrap().name(),
|
|
||||||
err,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
debug_assert!(non_custom_id.is_some(), "Custom properties should've returned earlier");
|
||||||
|
if let Some(use_counters) = context.use_counters {
|
||||||
|
use_counters.non_custom_properties.record(non_custom_id.unwrap());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
40
components/style/use_counters/mod.rs
Normal file
40
components/style/use_counters/mod.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
//! Various stuff for CSS property use counters.
|
||||||
|
|
||||||
|
use properties::{NonCustomPropertyId, NON_CUSTOM_PROPERTY_ID_COUNT};
|
||||||
|
// FIXME(emilio): We need AtomicU32 on stable ASAP...
|
||||||
|
use std::sync::atomic::AtomicUsize;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
const BITS_PER_ENTRY: usize = 64;
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
const BITS_PER_ENTRY: usize = 32;
|
||||||
|
|
||||||
|
/// One bit per each non-custom CSS property.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct NonCustomPropertyUseCounters {
|
||||||
|
storage: [AtomicUsize; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + BITS_PER_ENTRY) / BITS_PER_ENTRY],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NonCustomPropertyUseCounters {
|
||||||
|
/// Record that a given non-custom property ID has been parsed.
|
||||||
|
#[inline]
|
||||||
|
pub fn record(&self, id: NonCustomPropertyId) {
|
||||||
|
let bit = id.bit();
|
||||||
|
let bucket = bit / BITS_PER_ENTRY;
|
||||||
|
let bit_in_bucket = bit % BITS_PER_ENTRY;
|
||||||
|
self.storage[bucket].fetch_or(1 << bit_in_bucket, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The use-counter data related to a given document we want to store.
|
||||||
|
pub struct UseCounters {
|
||||||
|
/// The counters for non-custom properties that have been parsed in the
|
||||||
|
/// document's stylesheets.
|
||||||
|
pub non_custom_properties: NonCustomPropertyUseCounters,
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue