Skip to content

Commit

Permalink
style: Support css use counters for unimplemented properties.
Browse files Browse the repository at this point in the history
For developing properties, we will handle them in an other bug.

Besides, I use an iframe for the test because we create a use counter in
the constructor of Document, which use the prefs to decide what kind of
properties we want to record. So, in the test, we have to reload iframe
to make sure we re-create the document, so does the use counter, to make
sure the prefs work properly.

The two prefs affect the css use counters:
1. layout.css.use-counters.enabled: Allocate use counters, and record
   non-custom properties.
2. layout.css.use-counters-unimplemented.enabled: Record all unimplmented
   properties into the use counters.

If we disable layout.css.use-counters.enblaed, we don't create use counters
object, so layout.css.use-counters-unimplemented.enabled doesn't work,
either.

Differential Revision: https://phabricator.services.mozilla.com/D43860
  • Loading branch information
BorisChiou authored and emilio committed Sep 12, 2019
1 parent f7a87c4 commit c3a3bd4
Show file tree
Hide file tree
Showing 4 changed files with 275 additions and 41 deletions.
128 changes: 128 additions & 0 deletions components/style/properties/counted_unknown_properties.py
@@ -0,0 +1,128 @@
# 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/.

# The following properties are under development, so they are not in this list.
# FIXME: We should handle the developing properties properly by Bug 1577358:
# "backdrop-filter",
# "text-decoration-skip-ink",
# "column-span",
# "offset-distance",
# "offset-path",
# "offset-rotate"
COUNTED_UNKNOWN_PROPERTIES = [
"-webkit-font-smoothing",
"zoom",
"-webkit-tap-highlight-color",
"speak",
"text-size-adjust",
"-webkit-font-feature-settings",
"-webkit-user-drag",
"size",
"-webkit-clip-path",
"orphans",
"widows",
"-webkit-user-modify",
"-webkit-margin-before",
"-webkit-margin-after",
"tab-size",
"-webkit-margin-start",
"-webkit-column-break-inside",
"-webkit-padding-start",
"-webkit-margin-end",
"-webkit-box-reflect",
"-webkit-print-color-adjust",
"-webkit-mask-box-image",
"-webkit-line-break",
"-webkit-text-security",
"alignment-baseline",
"-webkit-writing-mode",
"baseline-shift",
"-webkit-hyphenate-character",
"page",
"text-underline-position",
"-webkit-highlight",
"background-repeat-x",
"-webkit-padding-end",
"background-repeat-y",
"-webkit-text-emphasis-color",
"-webkit-margin-top-collapse",
"-webkit-rtl-ordering",
"-webkit-padding-before",
"-webkit-text-decorations-in-effect",
"-webkit-border-vertical-spacing",
"-webkit-locale",
"-webkit-padding-after",
"-webkit-border-horizontal-spacing",
"color-rendering",
"-webkit-column-break-before",
"-webkit-transform-origin-x",
"-webkit-transform-origin-y",
"-webkit-text-emphasis-position",
"buffered-rendering",
"-webkit-text-orientation",
"-webkit-text-combine",
"-webkit-text-emphasis-style",
"-webkit-text-emphasis",
"d",
"-webkit-mask-box-image-width",
"-webkit-mask-box-image-source",
"-webkit-mask-box-image-outset",
"-webkit-mask-box-image-slice",
"-webkit-mask-box-image-repeat",
"-webkit-margin-after-collapse",
"-webkit-border-before-color",
"-webkit-border-before-width",
"-webkit-perspective-origin-x",
"-webkit-perspective-origin-y",
"-webkit-margin-before-collapse",
"-webkit-border-before-style",
"scroll-snap-stop",
"-webkit-margin-bottom-collapse",
"-webkit-ruby-position",
"-webkit-column-break-after",
"-webkit-margin-collapse",
"offset",
"-webkit-border-before",
"-webkit-border-end",
"-webkit-border-after",
"-webkit-border-start",
"-webkit-min-logical-width",
"-webkit-logical-height",
"-webkit-transform-origin-z",
"-webkit-font-size-delta",
"-webkit-logical-width",
"-webkit-max-logical-width",
"-webkit-min-logical-height",
"-webkit-max-logical-height",
"-webkit-border-end-color",
"-webkit-border-end-width",
"-webkit-border-start-color",
"-webkit-border-start-width",
"-webkit-border-after-color",
"-webkit-border-after-width",
"-webkit-border-end-style",
"-webkit-border-after-style",
"-webkit-border-start-style",
"-webkit-mask-repeat-x",
"-webkit-mask-repeat-y",
"user-zoom",
"min-zoom",
"-webkit-box-decoration-break",
"orientation",
"max-zoom",
"-webkit-app-region",
"-webkit-column-rule",
"-webkit-column-span",
"-webkit-column-gap",
"-webkit-shape-outside",
"-webkit-column-rule-width",
"-webkit-column-count",
"-webkit-opacity",
"-webkit-column-width",
"-webkit-shape-image-threshold",
"-webkit-column-rule-style",
"-webkit-columns",
"-webkit-column-rule-color",
"-webkit-shape-margin",
]
8 changes: 8 additions & 0 deletions components/style/properties/data.py
Expand Up @@ -3,6 +3,7 @@
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

import re
from counted_unknown_properties import COUNTED_UNKNOWN_PROPERTIES

PHYSICAL_SIDES = ["top", "right", "bottom", "left"]
LOGICAL_SIDES = ["block-start", "block-end", "inline-start", "inline-end"]
Expand Down Expand Up @@ -574,6 +575,7 @@ def __init__(self, engine):
self.shorthands = []
self.shorthands_by_name = {}
self.shorthand_aliases = []
self.counted_unknown_properties = [CountedUnknownProperty(p) for p in COUNTED_UNKNOWN_PROPERTIES]

def new_style_struct(self, *args, **kwargs):
style_struct = StyleStruct(*args, **kwargs)
Expand Down Expand Up @@ -794,3 +796,9 @@ def cue(data):
+ PropertyRestrictions.shorthand(data, "background")
+ PropertyRestrictions.shorthand(data, "outline")
+ PropertyRestrictions.shorthand(data, "font"))

class CountedUnknownProperty:
def __init__(self, name):
self.name = name
self.ident = to_rust_ident(name)
self.camel_case = to_camel_case(self.ident)
97 changes: 87 additions & 10 deletions components/style/properties/properties.mako.rs
Expand Up @@ -38,6 +38,7 @@ use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use to_shmem::impl_trivial_to_shmem;
use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
use crate::use_counters::UseCounters;
use crate::values::generics::text::LineHeight;
use crate::values::{computed, resolved};
use crate::values::computed::NonNegativeLength;
Expand Down Expand Up @@ -427,6 +428,9 @@ pub struct NonCustomPropertyId(usize);
pub const NON_CUSTOM_PROPERTY_ID_COUNT: usize =
${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())};

/// The length of all counted unknown properties.
pub const COUNTED_UNKNOWN_PROPERTY_COUNT: usize = ${len(data.counted_unknown_properties)};

% if engine == "gecko":
#[allow(dead_code)]
unsafe fn static_assert_nscsspropertyid() {
Expand Down Expand Up @@ -1788,6 +1792,45 @@ impl ToCss for PropertyId {
}
}

/// The counted unknown property list which is used for css use counters.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum CountedUnknownProperty {
% for prop in data.counted_unknown_properties:
/// ${prop.name}
${prop.camel_case},
% endfor
}

impl CountedUnknownProperty {
/// Parse the counted unknown property.
pub fn parse_for_test(property_name: &str) -> Option<Self> {
ascii_case_insensitive_phf_map! {
unknown_id -> CountedUnknownProperty = {
% for property in data.counted_unknown_properties:
"${property.name}" => CountedUnknownProperty::${property.camel_case},
% endfor
}
}
unknown_id(property_name).cloned()
}

/// Returns the underlying index, used for use counter.
pub fn bit(self) -> usize {
self as usize
}
}

#[cfg(feature = "gecko")]
fn is_counted_unknown_use_counters_enabled() -> bool {
static_prefs::pref!("layout.css.use-counters-unimplemented.enabled")
}

#[cfg(feature = "servo")]
fn is_counted_unknown_use_counters_enabled() -> bool {
false
}

impl PropertyId {
/// Return the longhand id that this property id represents.
#[inline]
Expand All @@ -1801,28 +1844,62 @@ impl PropertyId {

/// Returns a given property from the string `s`.
///
/// Returns Err(()) for unknown non-custom properties.
fn parse_unchecked(property_name: &str) -> Result<Self, ()> {
/// Returns Err(()) for unknown properties.
fn parse_unchecked(
property_name: &str,
use_counters: Option< &UseCounters>,
) -> Result<Self, ()> {
// A special id for css use counters.
// ShorthandAlias is not used in the Servo build.
// That's why we need to allow dead_code.
#[allow(dead_code)]
pub enum StaticId {
Longhand(LonghandId),
Shorthand(ShorthandId),
LonghandAlias(LonghandId, AliasId),
ShorthandAlias(ShorthandId, AliasId),
CountedUnknown(CountedUnknownProperty),
}
ascii_case_insensitive_phf_map! {
property_id -> PropertyId = {
static_id -> StaticId = {
% for (kind, properties) in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]:
% for property in properties:
"${property.name}" => PropertyId::${kind}(${kind}Id::${property.camel_case}),
"${property.name}" => StaticId::${kind}(${kind}Id::${property.camel_case}),
% for alias in property.alias:
"${alias.name}" => {
PropertyId::${kind}Alias(
StaticId::${kind}Alias(
${kind}Id::${property.camel_case},
AliasId::${alias.camel_case},
)
},
% endfor
% endfor
% endfor
% for property in data.counted_unknown_properties:
"${property.name}" => {
StaticId::CountedUnknown(CountedUnknownProperty::${property.camel_case})
},
% endfor
}
}

if let Some(id) = property_id(property_name) {
return Ok(id.clone())
if let Some(id) = static_id(property_name) {
return Ok(match *id {
StaticId::Longhand(id) => PropertyId::Longhand(id),
StaticId::Shorthand(id) => PropertyId::Shorthand(id),
StaticId::LonghandAlias(id, alias) => PropertyId::LonghandAlias(id, alias),
StaticId::ShorthandAlias(id, alias) => PropertyId::ShorthandAlias(id, alias),
StaticId::CountedUnknown(unknown_prop) => {
if is_counted_unknown_use_counters_enabled() {
if let Some(counters) = use_counters {
counters.counted_unknown_properties.record(unknown_prop);
}
}

// Always return Err(()) because these aren't valid custom property names.
return Err(());
}
});
}

let name = crate::custom_properties::parse_name(property_name)?;
Expand All @@ -1833,7 +1910,7 @@ impl PropertyId {
/// enabled for all content.
#[inline]
pub fn parse_enabled_for_all_content(name: &str) -> Result<Self, ()> {
let id = Self::parse_unchecked(name)?;
let id = Self::parse_unchecked(name, None)?;

if !id.enabled_for_all_content() {
return Err(());
Expand All @@ -1847,7 +1924,7 @@ impl PropertyId {
/// allowed in this context.
#[inline]
pub fn parse(name: &str, context: &ParserContext) -> Result<Self, ()> {
let id = Self::parse_unchecked(name)?;
let id = Self::parse_unchecked(name, context.use_counters)?;

if !id.allowed_in(context) {
return Err(());
Expand All @@ -1865,7 +1942,7 @@ impl PropertyId {
name: &str,
context: &ParserContext,
) -> Result<Self, ()> {
let id = Self::parse_unchecked(name)?;
let id = Self::parse_unchecked(name, None)?;

if !id.allowed_in_ignoring_rule_type(context) {
return Err(());
Expand Down

0 comments on commit c3a3bd4

Please sign in to comment.