blob: d48e97a23b40f3583ac1bdb1c8d6405b0922af39 [file]
/*
* Copyright (C) 2019-2023 Apple Inc. All rights reserved.
* Copyright (C) 2025 Samuel Weinig <sam@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "CSSToLengthConversionData.h"
#include "Document.h"
#include "FontTaggedSettings.h"
#include "PropertyCascade.h"
#include "RuleSet.h"
#include "SelectorChecker.h"
#include "StyleComputedStyle.h"
#include "StyleForVisitedLink.h"
#include "StyleSubstitutionContext.h"
#include "TextFlags.h"
#include "TreeResolutionState.h"
#include <wtf/BitSet.h>
namespace WebCore {
class FontCascadeDescription;
class FontSelectionValue;
class StyleResolver;
struct CSSRegisteredCustomProperty;
namespace CSSCalc {
struct RandomCachingKey;
}
namespace Style {
class BuilderStatePropertyScope;
class BuilderState;
class Builder;
class CustomPropertyRegistry;
class Image;
class LocalPropertyRegistry;
class Scope;
struct Color;
struct FontFamilies;
struct FontFeatureSettings;
struct FontPalette;
struct FontSizeAdjust;
struct FontStyle;
struct FontVariantAlternates;
struct FontVariantEastAsian;
struct FontVariantLigatures;
struct FontVariantNumeric;
struct FontVariationSettings;
struct FontWeight;
struct FontWidth;
struct TextAutospace;
struct TextSpacingTrim;
struct WebkitLocale;
struct Zoom;
enum class PositionTryFallbackTactic : uint8_t;
void maybeUpdateFontForLetterSpacingOrWordSpacing(BuilderState&, CSSValue&);
enum class ApplyValueType : uint8_t { Value, Initial, Inherit };
struct BuilderPositionTryFallback {
RefPtr<const StyleProperties> properties;
Vector<PositionTryFallbackTactic> tactics;
};
struct RegisteredSubstitutionAttribute {
AtomString name;
WeakPtr<const Scope> targetScope;
};
struct BuilderContext {
const Ref<const Document> document;
const Style::ComputedStyle* parentStyle { };
// For highlight pseudo-elements: the corresponding highlight pseudo-element style of the
// originating element's parent, if any. https://drafts.csswg.org/css-pseudo-4/#highlight-cascade
const Style::ComputedStyle* parentHighlightStyle { };
const Style::ComputedStyle* rootElementStyle { };
RefPtr<const Element> element { };
CheckedPtr<TreeResolutionState> treeResolutionState { };
std::optional<BuilderPositionTryFallback> positionTryFallback { };
const LocalPropertyRegistry* localPropertyRegistry { nullptr };
// For a custom function's hypothetical element: the builder of the calling context, used to
// resolve inherited custom properties on demand. https://drafts.csswg.org/css-mixins/#evaluating-custom-functions
Builder* callingContextBuilder { nullptr };
};
class BuilderState : public CanMakeCheckedPtr<BuilderState> {
WTF_MAKE_TZONE_ALLOCATED(BuilderState);
WTF_MAKE_NONCOPYABLE(BuilderState);
WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(BuilderState);
public:
template<typename T, class... Args> friend WTF::UniqueRef<T> WTF::makeUniqueRefWithoutFastMallocCheck(Args&&...);
static UniqueRef<BuilderState> create(ComputedStyle& style, BuilderContext&& builderContext)
{
return makeUniqueRefWithoutRefCountedCheck<BuilderState>(style, WTF::move(builderContext));
}
ComputedStyle& style() LIFETIME_BOUND { return m_style; }
const ComputedStyle& style() const LIFETIME_BOUND { return m_style; }
const ComputedStyle& parentStyle() const LIFETIME_BOUND { return *m_context.parentStyle; }
// The highlight pseudo-element style this one inherits from. Null for the highlight
// pseudo-element of the root element, and for anything that isn't a highlight pseudo-element.
// https://drafts.csswg.org/css-pseudo-4/#highlight-cascade
const ComputedStyle* parentHighlightStyle() const LIFETIME_BOUND { return m_context.parentHighlightStyle; }
// True for any highlight pseudo-element style, including one with nothing to inherit from.
inline bool isBuildingHighlightStyle() const;
Builder* callingContextBuilder() const { return m_context.callingContextBuilder; }
const Style::ComputedStyle* rootElementStyle() const LIFETIME_BOUND { return m_context.rootElementStyle; }
const Document& document() const { return m_context.document; }
const Element* element() const { return m_context.element.get(); }
const CSSRegisteredCustomProperty* registeredProperty(const AtomString&) const;
// The registrations of the custom function being evaluated, if any. These shadow the document's.
const LocalPropertyRegistry* localPropertyRegistry() const { return m_context.localPropertyRegistry; }
inline void setZoom(Zoom);
inline void setUsedZoom(float);
inline void setWritingMode(StyleWritingMode);
inline void setTextOrientation(TextOrientation);
bool fontDirty() const { return m_fontDirty; }
void setFontDirty() { m_fontDirty = true; }
inline const FontCascadeDescription& fontDescription() LIFETIME_BOUND;
inline const FontCascadeDescription& parentFontDescription() LIFETIME_BOUND;
bool applyPropertyToRegularStyle() const { return m_linkMatch != SelectorChecker::MatchVisited; }
bool applyPropertyToVisitedLinkStyle() const { return m_linkMatch != SelectorChecker::MatchLink; }
float NODELETE zoomWithTextZoomFactor();
bool NODELETE useSVGZoomRules() const;
bool NODELETE useSVGZoomRulesForLength() const;
// Defaults to Element when called outside property cascade application (e.g. attr() resolution
// during container-query evaluation), where there is no current property in flight.
ScopeOrdinal styleScopeOrdinal() const { return m_currentProperty ? m_currentProperty->styleScopeOrdinal : ScopeOrdinal::Element; }
RefPtr<Image> createStyleImage(const CSSValue&) const;
const Vector<RegisteredSubstitutionAttribute>& registeredSubstitutionAttributes() const LIFETIME_BOUND { return m_registeredSubstitutionAttributes; }
void registerSubstitutionAttribute(const AtomString& attributeLocalName, const Scope* targetScope = nullptr);
const CSSToLengthConversionData& cssToLengthConversionData() const LIFETIME_BOUND { return m_cssToLengthConversionData; }
GuardedSubstitutionContexts::Guard guardSubstitutionContext(SubstitutionContext&& context) { return m_guardedSubstitutionContexts.guard(WTF::move(context)); }
void addGuardedFunctionContexts(const BuilderState& other) { m_guardedSubstitutionContexts.addFunctionContextsFrom(other.m_guardedSubstitutionContexts); }
void setIsBuildingKeyframeStyle() { m_isBuildingKeyframeStyle = true; }
bool hasRevertRuleOrLayerInKeyframeStyle() const { return m_hasRevertRuleOrLayerInKeyframeStyle; }
void setIsResolvingContainerQueries() { m_isResolvingContainerQueries = true; }
bool isResolvingContainerQueries() const { return m_isResolvingContainerQueries; }
bool isAuthorOrigin() const
{
return m_currentProperty && m_currentProperty->origin == PropertyCascade::Origin::Author;
}
CSSPropertyID NODELETE cssPropertyID() const;
AtomString NODELETE customPropertyName() const;
bool NODELETE isCurrentPropertyInvalidAtComputedValueTime() const;
void NODELETE setCurrentPropertyInvalidAtComputedValueTime();
void NODELETE setUsesViewportUnits();
void NODELETE setIsContainerDependent();
double lookupCSSRandomBaseValue(const CSSCalc::RandomCachingKey&, std::optional<CSS::Keyword::ElementScoped>) const;
// Accessors for sibling information used by the sibling-count() and sibling-index() CSS functions.
unsigned NODELETE siblingCount();
unsigned NODELETE siblingIndex();
AnchorPositionedStates* anchorPositionedStates() LIFETIME_BOUND { return m_context.treeResolutionState ? &m_context.treeResolutionState->anchorPositionedStates : nullptr; }
const std::optional<BuilderPositionTryFallback>& positionTryFallback() const LIFETIME_BOUND { return m_context.positionTryFallback; }
// FIXME: Copying a FontCascadeDescription is really inefficient. Migrate all callers to
// setFontDescriptionXXX() variants below, then remove these functions.
inline void setFontDescription(FontCascadeDescription&&);
void setFontSize(FontCascadeDescription&, float size);
void setFontDescriptionKeywordSizeFromIdentifier(CSSValueID);
void setFontDescriptionIsAbsoluteSize(bool);
void setFontDescriptionFontSize(float);
void setFontDescriptionFamilies(FontFamilies&&);
void setFontDescriptionFeatureSettings(FontFeatureSettings&&);
void setFontDescriptionFontPalette(FontPalette&&);
void setFontDescriptionFontSizeAdjust(FontSizeAdjust);
void setFontDescriptionFontSmoothing(FontSmoothingMode);
void setFontDescriptionFontStyle(FontStyle);
void setFontDescriptionFontSynthesisSmallCaps(FontSynthesisLonghandValue);
void setFontDescriptionFontSynthesisStyle(FontSynthesisStyleLonghandValue);
void setFontDescriptionFontSynthesisWeight(FontSynthesisLonghandValue);
void setFontDescriptionKerning(Kerning);
void setFontDescriptionOpticalSizing(FontOpticalSizing);
void setFontDescriptionSpecifiedLocale(WebkitLocale&&);
void setFontDescriptionTextAutospace(TextAutospace);
void setFontDescriptionTextRenderingMode(TextRenderingMode);
void setFontDescriptionTextSpacingTrim(TextSpacingTrim);
void setFontDescriptionVariantCaps(FontVariantCaps);
void setFontDescriptionVariantEmoji(FontVariantEmoji);
void setFontDescriptionVariantPosition(FontVariantPosition);
void setFontDescriptionVariationSettings(FontVariationSettings&&);
void setFontDescriptionWeight(FontWeight);
void setFontDescriptionWidth(FontWidth);
void setFontDescriptionVariantAlternates(FontVariantAlternates&&);
void setFontDescriptionVariantEastAsian(FontVariantEastAsian);
void setFontDescriptionVariantEastAsianVariant(FontVariantEastAsianVariant);
void setFontDescriptionVariantEastAsianWidth(FontVariantEastAsianWidth);
void setFontDescriptionVariantEastAsianRuby(FontVariantEastAsianRuby);
void setFontDescriptionKeywordSize(unsigned);
void setFontDescriptionVariantLigatures(FontVariantLigatures);
void setFontDescriptionVariantCommonLigatures(WebCore::FontVariantLigatures);
void setFontDescriptionVariantDiscretionaryLigatures(WebCore::FontVariantLigatures);
void setFontDescriptionVariantHistoricalLigatures(WebCore::FontVariantLigatures);
void setFontDescriptionVariantContextualAlternates(WebCore::FontVariantLigatures);
void setFontDescriptionVariantNumeric(FontVariantNumeric);
void setFontDescriptionVariantNumericFigure(FontVariantNumericFigure);
void setFontDescriptionVariantNumericSpacing(FontVariantNumericSpacing);
void setFontDescriptionVariantNumericFraction(FontVariantNumericFraction);
void setFontDescriptionVariantNumericOrdinal(FontVariantNumericOrdinal);
void setFontDescriptionVariantNumericSlashedZero(FontVariantNumericSlashedZero);
void disableNativeAppearanceIfNeeded(CSSPropertyID, PropertyCascade::Origin);
private:
// See the comment in maybeUpdateFontForLetterSpacingOrWordSpacing() about why this needs to be a friend.
friend void maybeUpdateFontForLetterSpacingOrWordSpacing(BuilderState&, CSSValue&);
friend class BuilderStatePropertyScope;
friend class Builder;
friend class SubstitutionResolver;
BuilderState(ComputedStyle&, BuilderContext&&);
void NODELETE adjustStyleForInterCharacterRuby();
void updateFont();
void updateFontForTextSizeAdjust();
void updateFontForZoomChange();
void updateFontForGenericFamilyChange();
void updateFontForOrientationChange();
void updateFontForSizeChange();
void setCurrentProperty(const PropertyCascade::Property* property)
{
if (property) {
m_currentProperty = property;
m_cssToLengthConversionData.m_property = m_currentProperty->id;
} else {
m_currentProperty = nullptr;
m_cssToLengthConversionData.m_property = CSSPropertyInvalid;
}
}
Style::ComputedStyle& m_style;
BuilderContext m_context;
CSSToLengthConversionData m_cssToLengthConversionData;
HashSet<AtomString> m_appliedCustomProperties;
GuardedSubstitutionContexts m_guardedSubstitutionContexts;
WTF::BitSet<cssPropertyIDEnumValueCount> m_inProgressProperties;
WTF::BitSet<cssPropertyIDEnumValueCount> m_invalidAtComputedValueTimeProperties;
const PropertyCascade::Property* m_currentProperty { nullptr };
SelectorChecker::LinkMatchMask m_linkMatch { };
const PropertyCascade* m_currentRollbackCascade { nullptr };
bool m_fontDirty { false };
Vector<RegisteredSubstitutionAttribute> m_registeredSubstitutionAttributes;
bool m_isBuildingKeyframeStyle { false };
bool m_hasRevertRuleOrLayerInKeyframeStyle { false };
bool m_isResolvingContainerQueries { false };
};
class BuilderStatePropertyScope {
public:
BuilderStatePropertyScope(BuilderState& state, const PropertyCascade::Property* newProperty)
: m_state { state }
, m_propertyToRestore { m_state.m_currentProperty }
{
m_state.setCurrentProperty(newProperty);
}
~BuilderStatePropertyScope()
{
m_state.setCurrentProperty(m_propertyToRestore);
}
private:
BuilderState& m_state;
const PropertyCascade::Property* m_propertyToRestore;
};
} // namespace Style
} // namespace WebCore