mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15: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 traversal;
|
||||
pub mod traversal_flags;
|
||||
pub mod use_counters;
|
||||
#[macro_use]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub mod values;
|
||||
|
|
|
@ -9,6 +9,7 @@ use cssparser::{Parser, SourceLocation, UnicodeRange};
|
|||
use error_reporting::{ContextualParseError, ParseErrorReporter};
|
||||
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
|
||||
use stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData};
|
||||
use use_counters::UseCounters;
|
||||
|
||||
/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -53,6 +54,8 @@ pub struct ParserContext<'a> {
|
|||
error_reporter: Option<&'a ParseErrorReporter>,
|
||||
/// The currently active 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> {
|
||||
|
@ -66,7 +69,7 @@ impl<'a> ParserContext<'a> {
|
|||
quirks_mode: QuirksMode,
|
||||
error_reporter: Option<&'a ParseErrorReporter>,
|
||||
) -> Self {
|
||||
ParserContext {
|
||||
Self {
|
||||
stylesheet_origin,
|
||||
url_data,
|
||||
rule_type,
|
||||
|
@ -74,6 +77,7 @@ impl<'a> ParserContext<'a> {
|
|||
quirks_mode,
|
||||
error_reporter,
|
||||
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]
|
||||
pub fn new_with_rule_type(
|
||||
context: &'a ParserContext,
|
||||
rule_type: CssRuleType,
|
||||
namespaces: &'a Namespaces,
|
||||
) -> ParserContext<'a> {
|
||||
ParserContext {
|
||||
Self {
|
||||
stylesheet_origin: context.stylesheet_origin,
|
||||
url_data: context.url_data,
|
||||
rule_type: Some(rule_type),
|
||||
|
@ -111,6 +116,7 @@ impl<'a> ParserContext<'a> {
|
|||
quirks_mode: context.quirks_mode,
|
||||
namespaces: Some(namespaces),
|
||||
error_reporter: context.error_reporter,
|
||||
use_counters: context.use_counters,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -425,6 +425,10 @@ pub mod animated_properties {
|
|||
#[derive(Clone, Copy, Debug)]
|
||||
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":
|
||||
#[allow(dead_code)]
|
||||
unsafe fn static_assert_nscsspropertyid() {
|
||||
|
@ -435,6 +439,11 @@ unsafe fn static_assert_nscsspropertyid() {
|
|||
% endif
|
||||
|
||||
impl NonCustomPropertyId {
|
||||
/// Returns the underlying index, used for use counter.
|
||||
pub fn bit(self) -> usize {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
#[inline]
|
||||
fn to_nscsspropertyid(self) -> nsCSSPropertyID {
|
||||
|
@ -450,7 +459,7 @@ impl NonCustomPropertyId {
|
|||
if prop < 0 {
|
||||
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(());
|
||||
}
|
||||
// unsafe: guaranteed by static_assert_nscsspropertyid above.
|
||||
|
@ -460,7 +469,7 @@ impl NonCustomPropertyId {
|
|||
/// Get the property name.
|
||||
#[inline]
|
||||
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():
|
||||
"${property.name}",
|
||||
% endfor
|
||||
|
@ -635,7 +644,7 @@ impl NonCustomPropertyId {
|
|||
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 {
|
||||
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
|
||||
#[derive(Clone, PartialEq)]
|
||||
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 {
|
||||
|
@ -2198,7 +2207,7 @@ impl PropertyDeclaration {
|
|||
// FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774
|
||||
// before adding skip_whitespace here.
|
||||
// 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),
|
||||
Err(()) => match ::custom_properties::SpecifiedValue::parse(input) {
|
||||
Ok(value) => DeclaredValueOwned::Value(value),
|
||||
|
@ -2212,12 +2221,12 @@ impl PropertyDeclaration {
|
|||
name: property_name,
|
||||
value,
|
||||
}));
|
||||
Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
PropertyId::LonghandAlias(id, _) |
|
||||
PropertyId::Longhand(id) => {
|
||||
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(
|
||||
WideKeywordDeclaration { id, keyword },
|
||||
)
|
||||
|
@ -2253,12 +2262,12 @@ impl PropertyDeclaration {
|
|||
})
|
||||
}).map(|declaration| {
|
||||
declarations.push(declaration)
|
||||
})
|
||||
})?;
|
||||
}
|
||||
PropertyId::ShorthandAlias(id, _) |
|
||||
PropertyId::Shorthand(id) => {
|
||||
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 {
|
||||
declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword)
|
||||
} else {
|
||||
|
@ -2271,51 +2280,55 @@ impl PropertyDeclaration {
|
|||
))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
input.look_for_var_functions();
|
||||
// Not using parse_entirely here: each ${shorthand.ident}::parse_into function
|
||||
// needs to do so *before* pushing to `declarations`.
|
||||
id.parse_into(declarations, context, input).or_else(|err| {
|
||||
while let Ok(_) = input.next() {} // Look for var() after the error.
|
||||
if input.seen_var_functions() {
|
||||
input.reset(&start);
|
||||
let (first_token_type, css) =
|
||||
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
|
||||
StyleParseErrorKind::new_invalid(
|
||||
non_custom_id.unwrap().name(),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
let unparsed = Arc::new(UnparsedValue {
|
||||
css: css.into_owned(),
|
||||
first_token_type: first_token_type,
|
||||
url_data: context.url_data.clone(),
|
||||
from_shorthand: Some(id),
|
||||
});
|
||||
if id == ShorthandId::All {
|
||||
declarations.all_shorthand = AllShorthand::WithVariables(unparsed)
|
||||
} else {
|
||||
for id in id.longhands() {
|
||||
declarations.push(
|
||||
PropertyDeclaration::WithVariables(VariableDeclaration {
|
||||
id,
|
||||
value: unparsed.clone(),
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(StyleParseErrorKind::new_invalid(
|
||||
if !input.seen_var_functions() {
|
||||
return Err(StyleParseErrorKind::new_invalid(
|
||||
non_custom_id.unwrap().name(),
|
||||
err,
|
||||
))
|
||||
));
|
||||
}
|
||||
})
|
||||
|
||||
input.reset(&start);
|
||||
let (first_token_type, css) =
|
||||
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
|
||||
StyleParseErrorKind::new_invalid(
|
||||
non_custom_id.unwrap().name(),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
let unparsed = Arc::new(UnparsedValue {
|
||||
css: css.into_owned(),
|
||||
first_token_type: first_token_type,
|
||||
url_data: context.url_data.clone(),
|
||||
from_shorthand: Some(id),
|
||||
});
|
||||
if id == ShorthandId::All {
|
||||
declarations.all_shorthand = AllShorthand::WithVariables(unparsed)
|
||||
} else {
|
||||
for id in id.longhands() {
|
||||
declarations.push(
|
||||
PropertyDeclaration::WithVariables(VariableDeclaration {
|
||||
id,
|
||||
value: unparsed.clone(),
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
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