Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 */
/* atom list for CSS pseudo-elements */
#ifndef nsCSSPseudoElements_h___
#define nsCSSPseudoElements_h___
#include "nsGkAtoms.h"
#include "mozilla/CSSEnabledState.h"
#include "mozilla/PseudoStyleType.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_layout.h"
// Is this pseudo-element a CSS2 pseudo-element that can be specified
// with the single colon syntax (in addition to the double-colon syntax,
// which can be used for all pseudo-elements)?
// Note: We also rely on this for IsEagerlyCascadedInServo.
#define CSS_PSEUDO_ELEMENT_IS_CSS2 (1 << 0)
// Is this pseudo-element a pseudo-element that can contain other
// elements?
// (Currently pseudo-elements are either leaves of the tree (relative to
// real elements) or they contain other elements in a non-tree-like
// manner (i.e., like incorrectly-nested start and end tags). It's
// possible that in the future there might be container pseudo-elements
// that form a properly nested tree structure. If that happens, we
// should probably split this flag into two.)
// Flag to add the ability to take into account style attribute set for the
// pseudo element (by default it's ignored).
// Flag that indicate the pseudo-element supports a user action pseudo-class
// following it, such as :active or :hover. This would normally correspond
// to whether the pseudo-element is tree-like, but we don't support these
// pseudo-classes on ::before and ::after generated content yet. See
// Should this pseudo-element be enabled only for UA sheets?
// Should this pseudo-element be enabled only for UA sheets and chrome
// stylesheets?
// Can we use the ChromeOnly document.createElement(..., { pseudo: "::foo" })
// API for creating pseudo-implementing native anonymous content in JS with this
// pseudo-element?
// Does this pseudo-element act like an item for containers (such as flex and
// grid containers) and thus needs parent display-based style fixup?
class nsCSSPseudoElements {
typedef mozilla::PseudoStyleType Type;
typedef mozilla::CSSEnabledState EnabledState;
static bool IsEagerlyCascadedInServo(const Type aType) {
return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_IS_CSS2);
#ifdef DEBUG
static void AssertAtoms();
// Alias nsCSSPseudoElements::foo() to nsGkAtoms::foo.
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
static nsCSSPseudoElementStaticAtom* name_() { \
return const_cast<nsCSSPseudoElementStaticAtom*>( \
static_cast<const nsCSSPseudoElementStaticAtom*>( \
nsGkAtoms::PseudoElement_##name_)); \
#include "nsCSSPseudoElementList.h"
// Returns an empty tuple for a syntactically invalid pseudo-element, and
// NotPseudo for the empty / null string.
// The second element of the tuple (functional pseudo parameter) is currently
// only used for `::highlight()` pseudos and is `nullptr` otherwise.
static std::tuple<mozilla::Maybe<Type>, RefPtr<nsAtom>> ParsePseudoElement(
const nsAString& aPseudoElement,
EnabledState = EnabledState::ForAllContent);
// Returns Nothing() for a syntactically invalid pseudo-element, and NotPseudo
// for the empty / null string.
static mozilla::Maybe<Type> GetPseudoType(
const nsAString& aPseudoElement,
EnabledState = EnabledState::ForAllContent);
// Get the atom for a given Type. aType must be <
// PseudoType::CSSPseudoElementsEnd.
// This only ever returns static atoms, so it's fine to return a raw pointer.
static nsAtom* GetPseudoAtom(Type aType);
// Get the atom for a given pseudo-element string (e.g. "::before"). This can
// return dynamic atoms, for unrecognized pseudo-elements.
static already_AddRefed<nsAtom> GetPseudoAtom(
const nsAString& aPseudoElement);
static bool PseudoElementContainsElements(const Type aType) {
return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS);
static bool PseudoElementSupportsStyleAttribute(const Type aType) {
MOZ_ASSERT(aType < Type::CSSPseudoElementsEnd);
return PseudoElementHasFlags(aType,
static bool PseudoElementSupportsUserActionState(const Type aType);
static bool PseudoElementIsJSCreatedNAC(Type aType) {
return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC);
static bool PseudoElementIsFlexOrGridItem(const Type aType) {
return PseudoElementHasFlags(aType,
static bool EnabledInContent(Type aType) {
switch (aType) {
case Type::highlight:
return mozilla::StaticPrefs::dom_customHighlightAPI_enabled();
case Type::targetText:
return mozilla::StaticPrefs::dom_text_fragments_enabled();
case Type::sliderTrack:
case Type::sliderThumb:
case Type::sliderFill:
return mozilla::StaticPrefs::layout_css_modern_range_pseudos_enabled();
return !PseudoElementHasAnyFlag(
static bool IsEnabled(Type aType, EnabledState aEnabledState) {
if (EnabledInContent(aType)) {
return true;
if ((aEnabledState & EnabledState::InUASheets) &&
return true;
if ((aEnabledState & EnabledState::InChrome) &&
return true;
return false;
static nsString PseudoTypeAsString(Type aPseudoType);
// Does the given pseudo-element have all of the flags given?
static bool PseudoElementHasFlags(const Type aType, uint32_t aFlags) {
MOZ_ASSERT(aType < Type::CSSPseudoElementsEnd);
return (kPseudoElementFlags[size_t(aType)] & aFlags) == aFlags;
static bool PseudoElementHasAnyFlag(const Type aType, uint32_t aFlags) {
MOZ_ASSERT(aType < Type::CSSPseudoElementsEnd);
return (kPseudoElementFlags[size_t(aType)] & aFlags) != 0;
static nsStaticAtom* GetAtomBase();
static const uint32_t kPseudoElementFlags[size_t(Type::CSSPseudoElementsEnd)];
#endif /* nsCSSPseudoElements_h___ */