Bug 1447367 - Remove files that are not built when MOZ_OLD_STYLE is not defined. r=emilio

MozReview-Commit-ID: D9bEPfTSw61
This commit is contained in:
Jonathan Watt 2018-03-07 18:08:41 +00:00
Родитель d838e97ff8
Коммит f3e6656403
49 изменённых файлов: 3 добавлений и 54910 удалений

Просмотреть файл

@ -1,117 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
#include "AnimValuesStyleRule.h"
#include "mozilla/GeckoStyleContext.h"
#include "nsRuleData.h"
namespace mozilla {
NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule)
void
AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
{
GeckoStyleContext* contextParent = aRuleData->mStyleContext->GetParent();
if (contextParent && contextParent->HasPseudoElementData()) {
// Don't apply transitions or animations to things inside of
// pseudo-elements.
// FIXME (Bug 522599): Add tests for this.
// Prevent structs from being cached on the rule node since we're inside
// a pseudo-element, as we could determine cacheability differently
// when walking the rule tree for a style context that is not inside
// a pseudo-element. Note that nsRuleNode::GetStyle##name_ and GetStyleData
// will never look at cached structs when we're animating things inside
// a pseduo-element, so that we don't incorrectly return a struct that
// is only appropriate for non-pseudo-elements.
aRuleData->mConditions.SetUncacheable();
return;
}
for (auto iter = mAnimationValues.ConstIter(); !iter.Done(); iter.Next()) {
nsCSSPropertyID property = static_cast<nsCSSPropertyID>(iter.Key());
if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(
nsCSSProps::kSIDTable[property])) {
nsCSSValue *prop = aRuleData->ValueFor(property);
if (prop->GetUnit() == eCSSUnit_Null) {
DebugOnly<bool> ok =
StyleAnimationValue::UncomputeValue(property, iter.Data(),
*prop);
MOZ_ASSERT(ok, "could not store computed value");
}
}
}
}
bool
AnimValuesStyleRule::MightMapInheritedStyleData()
{
return mStyleBits & NS_STYLE_INHERITED_STRUCT_MASK;
}
bool
AnimValuesStyleRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
nsCSSValue* aValue)
{
MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
return false;
}
void
AnimValuesStyleRule::AddValue(nsCSSPropertyID aProperty,
const StyleAnimationValue &aValue)
{
MOZ_ASSERT(aProperty != eCSSProperty_UNKNOWN,
"Unexpected css property");
mAnimationValues.Put(aProperty, aValue);
mStyleBits |=
nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]);
}
void
AnimValuesStyleRule::AddValue(nsCSSPropertyID aProperty,
StyleAnimationValue&& aValue)
{
MOZ_ASSERT(aProperty != eCSSProperty_UNKNOWN,
"Unexpected css property");
mAnimationValues.Put(aProperty, Move(aValue));
mStyleBits |=
nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]);
}
bool
AnimValuesStyleRule::GetValue(nsCSSPropertyID aProperty,
StyleAnimationValue& aValue) const
{
return mAnimationValues.Get(aProperty, &aValue);
}
#ifdef DEBUG
void
AnimValuesStyleRule::List(FILE* out, int32_t aIndent) const
{
nsAutoCString str;
for (int32_t index = aIndent; --index >= 0; ) {
str.AppendLiteral(" ");
}
str.AppendLiteral("[anim values] { ");
for (auto iter = mAnimationValues.ConstIter(); !iter.Done(); iter.Next()) {
nsCSSPropertyID property = static_cast<nsCSSPropertyID>(iter.Key());
str.Append(nsCSSProps::GetStringValue(property));
str.AppendLiteral(": ");
nsAutoString value;
Unused <<
StyleAnimationValue::UncomputeValue(property, iter.Data(), value);
AppendUTF16toUTF8(value, str);
str.AppendLiteral("; ");
}
str.AppendLiteral("}\n");
fprintf_stderr(out, "%s", str.get());
}
#endif
} // namespace mozilla

Просмотреть файл

@ -1,63 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_AnimValuesStyleRule_h
#define mozilla_AnimValuesStyleRule_h
#include "mozilla/StyleAnimationValue.h"
#include "nsCSSPropertyID.h"
#include "nsCSSPropertyIDSet.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h" // For nsUint32HashKey
#include "nsIStyleRule.h"
#include "nsISupportsImpl.h" // For NS_DECL_ISUPPORTS
#include "nsRuleNode.h" // For nsCachedStyleData
#include "nsTArray.h" // For nsTArray
namespace mozilla {
/**
* A style rule that maps property-StyleAnimationValue pairs.
*/
class AnimValuesStyleRule final : public nsIStyleRule
{
public:
AnimValuesStyleRule()
: mStyleBits(0) {}
// nsISupports implementation
NS_DECL_ISUPPORTS
// nsIStyleRule implementation
void MapRuleInfoInto(nsRuleData* aRuleData) override;
bool MightMapInheritedStyleData() override;
bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
nsCSSValue* aValue) override;
#ifdef DEBUG
void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
// For the following functions, it there is already a value for |aProperty| it
// will be replaced with |aValue|.
void AddValue(nsCSSPropertyID aProperty, const StyleAnimationValue &aValue);
void AddValue(nsCSSPropertyID aProperty, StyleAnimationValue&& aValue);
bool HasValue(nsCSSPropertyID aProperty) const {
return mAnimationValues.Contains(aProperty);
}
bool GetValue(nsCSSPropertyID aProperty, StyleAnimationValue& aValue) const;
private:
~AnimValuesStyleRule() {}
nsDataHashtable<nsUint32HashKey, StyleAnimationValue> mAnimationValues;
uint32_t mStyleBits;
};
} // namespace mozilla
#endif // mozilla_AnimValuesStyleRule_h

Просмотреть файл

@ -21,7 +21,6 @@
class nsCSSPropertyIDSet;
class nsAtom;
class nsIFrame;
class nsIStyleRule;
class nsPresContext;
class nsStyleContext;
struct RawServoAnimationValueMap;

Просмотреть файл

@ -41,11 +41,6 @@ EXPORTS.mozilla += [
'TimingParams.h',
]
if CONFIG['MOZ_OLD_STYLE']:
EXPORTS.mozilla += [
'AnimValuesStyleRule.h',
]
UNIFIED_SOURCES += [
'Animation.cpp',
'AnimationEffectReadOnly.cpp',
@ -67,11 +62,6 @@ UNIFIED_SOURCES += [
'TimingParams.cpp',
]
if CONFIG['MOZ_OLD_STYLE']:
UNIFIED_SOURCES += [
'AnimValuesStyleRule.cpp',
]
LOCAL_INCLUDES += [
'/dom/base',
'/layout/base',

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,770 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/**
* Code responsible for managing style changes: tracking what style
* changes need to happen, scheduling them, and doing them.
*/
#ifndef mozilla_GeckoRestyleManager_h
#define mozilla_GeckoRestyleManager_h
#include "mozilla/RestyleLogging.h"
#include "mozilla/RestyleManager.h"
#include "nsISupportsImpl.h"
#include "nsChangeHint.h"
#include "RestyleTracker.h"
#include "nsPresContext.h"
#include "nsRefreshDriver.h"
#include "nsRefPtrHashtable.h"
#include "nsTransitionManager.h"
class nsIFrame;
class nsStyleChangeList;
struct TreeMatchContext;
namespace mozilla {
enum class CSSPseudoElementType : uint8_t;
class EventStates;
struct UndisplayedNode;
namespace dom {
class Element;
} // namespace dom
class GeckoRestyleManager final : public RestyleManager
{
public:
typedef RestyleManager base_type;
friend class RestyleTracker;
friend class ElementRestyler;
explicit GeckoRestyleManager(nsPresContext* aPresContext);
protected:
~GeckoRestyleManager() override
{
MOZ_ASSERT(!mReframingStyleContexts,
"temporary member should be nulled out before destruction");
}
public:
// Forwarded nsIDocumentObserver method, to handle restyling (and
// passing the notification to the frame).
void ContentStateChanged(nsIContent* aContent,
EventStates aStateMask);
// Forwarded nsIMutationObserver method, to handle restyling.
void AttributeWillChange(Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aNewValue);
// Forwarded nsIMutationObserver method, to handle restyling (and
// passing the notification to the frame).
void AttributeChanged(Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aOldValue);
// Whether rule matching should skip styles associated with animation
bool SkipAnimationRules() const { return mSkipAnimationRules; }
void SetSkipAnimationRules(bool aSkipAnimationRules) {
mSkipAnimationRules = aSkipAnimationRules;
}
/**
* Reparent the style contexts of this frame subtree. The parent frame of
* aFrame must be changed to the new parent before this function is called;
* the new parent style context will be automatically computed based on the
* new position in the frame tree.
*
* @param aFrame the root of the subtree to reparent. Must not be null.
*/
nsresult ReparentStyleContext(nsIFrame* aFrame);
private:
/**
* Reparent the descendants of aFrame. This is used by ReparentStyleContext
* and shouldn't be called by anyone else. aProviderChild, if non-null, is a
* child that was the style parent for aFrame and hence shouldn't be
* reparented.
*/
void ReparentFrameDescendants(nsIFrame* aFrame, nsIFrame* aProviderChild);
public:
void ClearSelectors() {
mPendingRestyles.ClearSelectors();
}
void PostRestyleEventForLazyConstruction() { PostRestyleEventInternal(); }
private:
void PostRestyleEventInternal();
// Used when restyling an element with a frame.
void ComputeAndProcessStyleChange(nsIFrame* aFrame,
nsChangeHint aMinChange,
RestyleTracker& aRestyleTracker,
nsRestyleHint aRestyleHint,
const RestyleHintData& aRestyleHintData);
// Used when restyling a display:contents element.
void ComputeAndProcessStyleChange(GeckoStyleContext* aNewContext,
Element* aElement,
nsChangeHint aMinChange,
RestyleTracker& aRestyleTracker,
nsRestyleHint aRestyleHint,
const RestyleHintData& aRestyleHintData);
public:
/**
* In order to start CSS transitions on elements that are being
* reframed, we need to stash their style contexts somewhere during
* the reframing process.
*
* In all cases, the content node in the hash table is the real
* content node, not the anonymous content node we create for ::before
* or ::after. The content node passed to the Get and Put methods is,
* however, the content node to be associate with the frame's style
* context.
*/
typedef nsRefPtrHashtable<nsRefPtrHashKey<nsIContent>, GeckoStyleContext>
ReframingStyleContextTable;
class MOZ_STACK_CLASS ReframingStyleContexts final {
public:
/**
* Construct a ReframingStyleContexts object. The caller must
* ensure that aRestyleManager lives at least as long as the
* object. (This is generally easy since the caller is typically a
* method of RestyleManager.)
*/
explicit ReframingStyleContexts(GeckoRestyleManager* aRestyleManager);
~ReframingStyleContexts();
void Put(nsIContent* aContent, GeckoStyleContext* aStyleContext) {
MOZ_ASSERT(aContent);
CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
if (pseudoType == CSSPseudoElementType::NotPseudo) {
mElementContexts.Put(aContent, aStyleContext);
} else if (pseudoType == CSSPseudoElementType::before) {
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore);
mBeforePseudoContexts.Put(aContent->GetParent(), aStyleContext);
} else if (pseudoType == CSSPseudoElementType::after) {
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter);
mAfterPseudoContexts.Put(aContent->GetParent(), aStyleContext);
}
}
GeckoStyleContext* Get(nsIContent* aContent,
CSSPseudoElementType aPseudoType) {
MOZ_ASSERT(aContent);
if (aPseudoType == CSSPseudoElementType::NotPseudo) {
return mElementContexts.GetWeak(aContent);
}
if (aPseudoType == CSSPseudoElementType::before) {
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore);
return mBeforePseudoContexts.GetWeak(aContent->GetParent());
}
if (aPseudoType == CSSPseudoElementType::after) {
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter);
return mAfterPseudoContexts.GetWeak(aContent->GetParent());
}
MOZ_ASSERT(false, "unexpected aPseudoType");
return nullptr;
}
private:
GeckoRestyleManager* mRestyleManager;
AutoRestore<ReframingStyleContexts*> mRestorePointer;
ReframingStyleContextTable mElementContexts;
ReframingStyleContextTable mBeforePseudoContexts;
ReframingStyleContextTable mAfterPseudoContexts;
};
/**
* Return the current ReframingStyleContexts struct, or null if we're
* not currently in a restyling operation.
*/
ReframingStyleContexts* GetReframingStyleContexts() {
return mReframingStyleContexts;
}
/**
* Try initiating a transition for an element or a ::before or ::after
* pseudo-element, given an old and new style context. This may
* change the new style context if a transition is started. Returns
* true if it does change aNewStyleContext.
*
* For the pseudo-elements, aContent must be the anonymous content
* that we're creating for that pseudo-element, not the real element.
*/
static bool
TryInitiatingTransition(nsPresContext* aPresContext, nsIContent* aContent,
GeckoStyleContext* aOldStyleContext,
RefPtr<GeckoStyleContext>* aNewStyleContext /* inout */);
public:
// Process any pending restyles. This should be called after
// CreateNeededFrames.
// Note: It's the caller's responsibility to make sure to wrap a
// ProcessPendingRestyles call in a view update batch and a script blocker.
// This function does not call ProcessAttachedQueue() on the binding manager.
// If the caller wants that to happen synchronously, it needs to handle that
// itself.
void ProcessPendingRestyles();
private:
// ProcessPendingRestyles calls into one of our RestyleTracker
// objects. It then calls back to these functions at the beginning
// and end of its work.
void BeginProcessingRestyles(RestyleTracker& aRestyleTracker);
void EndProcessingRestyles();
public:
// Update styles for animations that are running on the compositor and
// whose updating is suppressed on the main thread (to save
// unnecessary work), while leaving all other aspects of style
// out-of-date.
//
// Performs an animation-only style flush to make styles from
// throttled transitions up-to-date prior to processing an unrelated
// style change, so that any transitions triggered by that style
// change produce correct results.
//
// In more detail: when we're able to run animations on the
// compositor, we sometimes "throttle" these animations by skipping
// updating style data on the main thread. However, whenever we
// process a normal (non-animation) style change, any changes in
// computed style on elements that have transition-* properties set
// may need to trigger new transitions; this process requires knowing
// both the old and new values of the property. To do this correctly,
// we need to have an up-to-date *old* value of the property on the
// primary frame. So the purpose of the mini-flush is to update the
// style for all throttled transitions and animations to the current
// animation state without making any other updates, so that when we
// process the queued style updates we'll have correct old data to
// compare against. When we do this, we don't bother touching frames
// other than primary frames.
void UpdateOnlyAnimationStyles();
// Rebuilds all style data by throwing out the old rule tree and
// building a new one, and additionally applying aExtraHint (which
// must not contain nsChangeHint_ReconstructFrame) to the root frame.
//
// aRestyleHint says which restyle hint to use for the computation;
// the only sensible values to use are eRestyle_Subtree (which says
// that the rebuild must run selector matching) and nsRestyleHint(0)
// (which says that rerunning selector matching is not required. (The
// method adds eRestyle_ForceDescendants internally, and including it
// in the restyle hint is harmless; some callers (e.g.,
// nsPresContext::MediaFeatureValuesChanged) might do this for their
// own reasons.)
void RebuildAllStyleData(nsChangeHint aExtraHint,
nsRestyleHint aRestyleHint);
/**
* Notify the frame constructor that an element needs to have its
* style recomputed.
* @param aElement: The element to be restyled.
* @param aRestyleHint: Which nodes need to have selector matching run
* on them.
* @param aMinChangeHint: A minimum change hint for aContent and its
* descendants.
* @param aRestyleHintData: Additional data to go with aRestyleHint.
*/
void PostRestyleEvent(Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint,
const RestyleHintData* aRestyleHintData = nullptr);
public:
/**
* Asynchronously clear style data from the root frame downwards and ensure
* it will all be rebuilt. This is safe to call anytime; it will schedule
* a restyle and take effect next time style changes are flushed.
* This method is used to recompute the style data when some change happens
* outside of any style rules, like a color preference change or a change
* in a system font size, or to fix things up when an optimization in the
* style data has become invalid. We assume that the root frame will not
* need to be reframed.
*
* For parameters, see RebuildAllStyleData.
*/
void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
nsRestyleHint aRestyleHint);
#ifdef DEBUG
bool InRebuildAllStyleData() const { return mInRebuildAllStyleData; }
#endif
#ifdef RESTYLE_LOGGING
/**
* Returns whether a restyle event currently being processed by this
* GeckoRestyleManager should be logged.
*/
bool ShouldLogRestyle() {
return ShouldLogRestyle(PresContext());
}
/**
* Returns whether a restyle event currently being processed for the
* document with the specified nsPresContext should be logged.
*/
static bool ShouldLogRestyle(nsPresContext* aPresContext) {
return aPresContext->RestyleLoggingEnabled() &&
(!aPresContext->TransitionManager()->
InAnimationOnlyStyleUpdate() ||
AnimationRestyleLoggingEnabled());
}
static bool RestyleLoggingInitiallyEnabled() {
static bool enabled = getenv("MOZ_DEBUG_RESTYLE") != 0;
return enabled;
}
static bool AnimationRestyleLoggingEnabled() {
static bool animations = getenv("MOZ_DEBUG_RESTYLE_ANIMATIONS") != 0;
return animations;
}
// Set MOZ_DEBUG_RESTYLE_STRUCTS to a comma-separated string of
// style struct names -- such as "Font,SVGReset" -- to log the style context
// tree and those cached struct pointers before each restyle. This
// function returns a bitfield of the structs named in the
// environment variable.
static uint32_t StructsToLog();
static nsCString StructNamesToString(uint32_t aSIDs);
int32_t& LoggingDepth() { return mLoggingDepth; }
#endif
bool IsProcessingRestyles() { return mIsProcessingRestyles; }
bool HasPendingRestyles() const;
private:
inline nsStyleSet* StyleSet() const {
MOZ_ASSERT(PresContext()->StyleSet()->IsGecko(),
"GeckoRestyleManager should only be used with a Gecko-flavored "
"style backend");
return PresContext()->StyleSet()->AsGecko();
}
/* aMinHint is the minimal change that should be made to the element */
// XXXbz do we really need the aPrimaryFrame argument here?
void RestyleElement(Element* aElement,
nsIFrame* aPrimaryFrame,
nsChangeHint aMinHint,
RestyleTracker& aRestyleTracker,
nsRestyleHint aRestyleHint,
const RestyleHintData& aRestyleHintData);
void StartRebuildAllStyleData(RestyleTracker& aRestyleTracker);
void FinishRebuildAllStyleData();
bool ShouldStartRebuildAllFor(RestyleTracker& aRestyleTracker) {
// When we process our primary restyle tracker and we have a pending
// rebuild-all, we need to process it.
return mDoRebuildAllStyleData &&
&aRestyleTracker == &mPendingRestyles;
}
void ProcessRestyles(RestyleTracker& aRestyleTracker) {
// Fast-path the common case (esp. for the animation restyle
// tracker) of not having anything to do.
if (aRestyleTracker.Count() || ShouldStartRebuildAllFor(aRestyleTracker)) {
IncrementRestyleGeneration();
aRestyleTracker.DoProcessRestyles();
}
}
private:
// True if we need to reconstruct the rule tree the next time we
// process restyles.
bool mDoRebuildAllStyleData : 1;
// True if we're currently in the process of reconstructing the rule tree.
bool mInRebuildAllStyleData : 1;
// Whether rule matching should skip styles associated with animation
bool mSkipAnimationRules : 1;
bool mHavePendingNonAnimationRestyles : 1;
nsChangeHint mRebuildAllExtraHint;
nsRestyleHint mRebuildAllRestyleHint;
ReframingStyleContexts* mReframingStyleContexts;
RestyleTracker mPendingRestyles;
// Are we currently in the middle of a call to ProcessRestyles?
// This flag is used both as a debugging aid to assert that we are not
// performing nested calls to ProcessPendingRestyles, as well as to ignore
// redundant calls to IncrementAnimationGeneration.
bool mIsProcessingRestyles;
#ifdef RESTYLE_LOGGING
int32_t mLoggingDepth;
#endif
};
/**
* An ElementRestyler is created for *each* element in a subtree that we
* recompute styles for.
*/
class ElementRestyler final
{
public:
typedef mozilla::dom::Element Element;
struct ContextToClear {
RefPtr<GeckoStyleContext> mStyleContext;
uint32_t mStructs;
};
// Construct for the root of the subtree that we're restyling.
ElementRestyler(nsPresContext* aPresContext,
nsIFrame* aFrame,
nsStyleChangeList* aChangeList,
nsChangeHint aHintsHandledByAncestors,
RestyleTracker& aRestyleTracker,
nsTArray<nsCSSSelector*>& aSelectorsForDescendants,
TreeMatchContext& aTreeMatchContext,
nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement,
nsTArray<ContextToClear>& aContextsToClear,
nsTArray<RefPtr<GeckoStyleContext>>& aSwappedStructOwners);
// Construct for an element whose parent is being restyled.
enum ConstructorFlags {
FOR_OUT_OF_FLOW_CHILD = 1<<0
};
ElementRestyler(const ElementRestyler& aParentRestyler,
nsIFrame* aFrame,
uint32_t aConstructorFlags);
// Construct for a frame whose parent is being restyled, but whose
// style context is the parent style context for its parent frame.
// (This is only used for table frames, whose style contexts are used
// as the parent style context for their table wrapper frame. We should
// probably try to get rid of this exception and have the inheritance go
// the other way.)
enum ParentContextFromChildFrame { PARENT_CONTEXT_FROM_CHILD_FRAME };
ElementRestyler(ParentContextFromChildFrame,
const ElementRestyler& aParentFrameRestyler,
nsIFrame* aFrame);
// For restyling undisplayed content only (mFrame==null).
ElementRestyler(nsPresContext* aPresContext,
nsIContent* aContent,
nsStyleChangeList* aChangeList,
nsChangeHint aHintsHandledByAncestors,
RestyleTracker& aRestyleTracker,
nsTArray<nsCSSSelector*>& aSelectorsForDescendants,
TreeMatchContext& aTreeMatchContext,
nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement,
nsTArray<ContextToClear>& aContextsToClear,
nsTArray<RefPtr<GeckoStyleContext>>& aSwappedStructOwners);
/**
* Restyle our frame's element and its subtree.
*
* Use eRestyle_Self for the aRestyleHint argument to mean
* "reresolve our style context but not kids", use eRestyle_Subtree
* to mean "reresolve our style context and kids", and use
* nsRestyleHint(0) to mean recompute a new style context for our
* current parent and existing rulenode, and the same for kids.
*/
void Restyle(nsRestyleHint aRestyleHint);
/**
* mHintsHandledBySelf changes over time; it starts off as nsChangeHint(0),
* and by the end of Restyle it represents the hints that have been handled
* for this frame. This method is intended to be called after Restyle, to
* find out what hints have been handled for this frame.
*/
nsChangeHint HintsHandledForFrame() { return mHintsHandledBySelf; }
/**
* Called from GeckoRestyleManager::ComputeAndProcessStyleChange to restyle
* children of a display:contents element.
*/
void RestyleChildrenOfDisplayContentsElement(nsIFrame* aParentFrame,
GeckoStyleContext* aNewContext,
nsChangeHint aMinHint,
RestyleTracker& aRestyleTracker,
nsRestyleHint aRestyleHint,
const RestyleHintData&
aRestyleHintData);
/**
* Re-resolve the style contexts for a frame tree, building aChangeList
* based on the resulting style changes, plus aMinChange applied to aFrame.
*/
static void ComputeStyleChangeFor(nsIFrame* aFrame,
nsStyleChangeList* aChangeList,
nsChangeHint aMinChange,
RestyleTracker& aRestyleTracker,
nsRestyleHint aRestyleHint,
const RestyleHintData& aRestyleHintData,
nsTArray<ContextToClear>& aContextsToClear,
nsTArray<RefPtr<GeckoStyleContext>>&
aSwappedStructOwners);
#ifdef RESTYLE_LOGGING
bool ShouldLogRestyle() {
return GeckoRestyleManager::ShouldLogRestyle(mPresContext);
}
#endif
private:
inline nsStyleSet* StyleSet() const;
// Enum class for the result of RestyleSelf, which indicates whether the
// restyle procedure should continue to the children, and how.
//
// These values must be ordered so that later values imply that all
// the work of the earlier values is also done.
enum class RestyleResult : uint8_t {
// default initial value
eNone,
// we left the old style context on the frame; do not restyle children
eStop,
// we got a new style context on this frame, but we know that children
// do not depend on the changed values; do not restyle children
eStopWithStyleChange,
// continue restyling children
eContinue,
// continue restyling children with eRestyle_ForceDescendants set
eContinueAndForceDescendants
};
struct SwapInstruction
{
RefPtr<GeckoStyleContext> mOldContext;
RefPtr<GeckoStyleContext> mNewContext;
uint32_t mStructsToSwap;
};
/**
* First half of Restyle().
*/
RestyleResult RestyleSelf(nsIFrame* aSelf,
nsRestyleHint aRestyleHint,
uint32_t* aSwappedStructs,
nsTArray<SwapInstruction>& aSwaps);
/**
* Restyle the children of this frame (and, in turn, their children).
*
* Second half of Restyle().
*/
void RestyleChildren(nsRestyleHint aChildRestyleHint);
/**
* Returns true iff a selector in mSelectorsForDescendants matches aElement.
* This is called when processing a eRestyle_SomeDescendants restyle hint.
*/
bool SelectorMatchesForRestyle(Element* aElement);
/**
* Returns true iff aRestyleHint indicates that we should be restyling.
* Specifically, this will return true when eRestyle_Self or
* eRestyle_Subtree is present, or if eRestyle_SomeDescendants is
* present and the specified element matches one of the selectors in
* mSelectorsForDescendants.
*/
bool MustRestyleSelf(nsRestyleHint aRestyleHint, Element* aElement);
/**
* Returns true iff aRestyleHint indicates that we can call
* ReparentStyleContext rather than any other restyling method of
* nsStyleSet that looks up a new rule node, and if we are
* not in the process of reconstructing the whole rule tree.
* This is used to check whether it is appropriate to call
* ReparentStyleContext.
*/
bool CanReparentStyleContext(nsRestyleHint aRestyleHint);
/**
* Helpers for Restyle().
*/
bool MoveStyleContextsForContentChildren(nsIFrame* aParent,
GeckoStyleContext* aOldContext,
nsTArray<GeckoStyleContext*>& aContextsToMove);
bool MoveStyleContextsForChildren(GeckoStyleContext* aOldContext);
/**
* Helpers for RestyleSelf().
*/
void CaptureChange(GeckoStyleContext* aOldContext,
GeckoStyleContext* aNewContext,
nsChangeHint aChangeToAssume,
uint32_t* aEqualStructs,
uint32_t* aSamePointerStructs);
void ComputeRestyleResultFromFrame(nsIFrame* aSelf,
RestyleResult& aRestyleResult,
bool& aCanStopWithStyleChange);
void ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
GeckoStyleContext* aNewContext,
RestyleResult& aRestyleResult,
bool& aCanStopWithStyleChange);
// Helpers for RestyleChildren().
void RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint);
bool MustCheckUndisplayedContent(nsIFrame* aFrame,
nsIContent*& aUndisplayedParent);
/**
* In the following two methods, aParentStyleContext is either
* mFrame->StyleContext() if we have a frame, or a display:contents
* style context if we don't.
*/
void DoRestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint,
nsIContent* aParent,
GeckoStyleContext* aParentStyleContext);
void RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint,
UndisplayedNode* aUndisplayed,
nsIContent* aUndisplayedParent,
GeckoStyleContext* aParentStyleContext,
const StyleDisplay aDisplay);
void MaybeReframeForBeforePseudo();
void MaybeReframeForAfterPseudo(nsIFrame* aFrame);
void MaybeReframeForPseudo(CSSPseudoElementType aPseudoType,
nsIFrame* aGenConParentFrame,
nsIFrame* aFrame,
nsIContent* aContent,
GeckoStyleContext* aStyleContext);
#ifdef DEBUG
bool MustReframeForBeforePseudo();
bool MustReframeForAfterPseudo(nsIFrame* aFrame);
#endif
bool MustReframeForPseudo(CSSPseudoElementType aPseudoType,
nsIFrame* aGenConParentFrame,
nsIFrame* aFrame,
nsIContent* aContent,
GeckoStyleContext* aStyleContext);
void RestyleContentChildren(nsIFrame* aParent,
nsRestyleHint aChildRestyleHint);
void InitializeAccessibilityNotifications(nsStyleContext* aNewContext);
void SendAccessibilityNotifications();
enum DesiredA11yNotifications {
eSkipNotifications,
eSendAllNotifications,
eNotifyIfShown
};
enum A11yNotificationType {
eDontNotify,
eNotifyShown,
eNotifyHidden
};
// These methods handle the eRestyle_SomeDescendants hint by traversing
// down the frame tree (and then when reaching undisplayed content,
// the flattened content tree) find elements that match a selector
// in mSelectorsForDescendants and call AddPendingRestyle for them.
void ConditionallyRestyleChildren();
void ConditionallyRestyleChildren(nsIFrame* aFrame,
Element* aRestyleRoot);
void ConditionallyRestyleContentChildren(nsIFrame* aFrame,
Element* aRestyleRoot);
void ConditionallyRestyleUndisplayedDescendants(nsIFrame* aFrame,
Element* aRestyleRoot);
void DoConditionallyRestyleUndisplayedDescendants(nsIContent* aParent,
Element* aRestyleRoot);
void ConditionallyRestyleUndisplayedNodes(UndisplayedNode* aUndisplayed,
nsIContent* aUndisplayedParent,
const StyleDisplay aDisplay,
Element* aRestyleRoot);
void ConditionallyRestyleContentDescendants(Element* aElement,
Element* aRestyleRoot);
bool ConditionallyRestyle(nsIFrame* aFrame, Element* aRestyleRoot);
bool ConditionallyRestyle(Element* aElement, Element* aRestyleRoot);
#ifdef RESTYLE_LOGGING
int32_t& LoggingDepth() { return mLoggingDepth; }
#endif
#ifdef DEBUG
static nsCString RestyleResultToString(RestyleResult aRestyleResult);
#endif
private:
nsPresContext* const mPresContext;
nsIFrame* const mFrame;
nsIContent* const mParentContent;
// |mContent| is the node that we used for rule matching of
// normal elements (not pseudo-elements) and for which we generate
// framechange hints if we need them.
nsIContent* const mContent;
nsStyleChangeList* const mChangeList;
// Hints that we computed on an ancestor (and which we already have
// generated a change list entry for). When we traverse to children
// after restyling an element, this field accumulates the hints
// generated for that element.
const nsChangeHint mHintsHandledByAncestors;
// Hints that we have computed so far the current node. This is
// initially zero, and accumulates hints for each same-style continuation
// and {ib} split sibling we restyle for the node.
nsChangeHint mHintsHandledBySelf;
RestyleTracker& mRestyleTracker;
nsTArray<nsCSSSelector*>& mSelectorsForDescendants;
TreeMatchContext& mTreeMatchContext;
nsIFrame* mResolvedChild; // child that provides our parent style context
// Array of style context subtrees in which we need to clear out cached
// structs at the end of the restyle (after change hints have been
// processed).
nsTArray<ContextToClear>& mContextsToClear;
// Style contexts that had old structs swapped into it and which should
// stay alive until the end of the restyle. (See comment in
// ElementRestyler::Restyle.)
nsTArray<RefPtr<GeckoStyleContext>>& mSwappedStructOwners;
// Whether this is the root of the restyle.
bool mIsRootOfRestyle;
#ifdef ACCESSIBILITY
const DesiredA11yNotifications mDesiredA11yNotifications;
DesiredA11yNotifications mKidsDesiredA11yNotifications;
A11yNotificationType mOurA11yNotification;
nsTArray<nsIContent*>& mVisibleKidsOfHiddenElement;
bool mWasFrameVisible;
#endif
#ifdef RESTYLE_LOGGING
int32_t mLoggingDepth;
#endif
};
/**
* This pushes any display:contents nodes onto a TreeMatchContext.
* Use it before resolving style for kids of aParent where aParent
* (and further ancestors) may be display:contents nodes which have
* not yet been pushed onto TreeMatchContext.
*/
class MOZ_RAII AutoDisplayContentsAncestorPusher final
{
public:
typedef mozilla::dom::Element Element;
AutoDisplayContentsAncestorPusher(TreeMatchContext& aTreeMatchContext,
nsPresContext* aPresContext,
nsIContent* aParent);
~AutoDisplayContentsAncestorPusher();
bool IsEmpty() const { return mAncestors.Length() == 0; }
private:
TreeMatchContext& mTreeMatchContext;
nsPresContext* const mPresContext;
AutoTArray<mozilla::dom::Element*, 4> mAncestors;
};
} // namespace mozilla
#endif /* mozilla_GeckoRestyleManager_h */

Просмотреть файл

@ -1,485 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/**
* A class which manages pending restyles. This handles keeping track
* of what nodes restyles need to happen on and so forth.
*/
#include "RestyleTracker.h"
#include "GeckoProfiler.h"
#include "nsCSSFrameConstructor.h"
#include "nsIContentInlines.h"
#include "nsIDocument.h"
#include "nsStyleChangeList.h"
#include "mozilla/dom/ElementInlines.h"
#include "mozilla/GeckoRestyleManager.h"
#include "RestyleTrackerInlines.h"
#include "nsTransitionManager.h"
#include "mozilla/AutoRestyleTimelineMarker.h"
namespace mozilla {
#ifdef RESTYLE_LOGGING
static nsCString
GetDocumentURI(nsIDocument* aDocument)
{
nsCString result;
nsAutoString url;
nsresult rv = aDocument->GetDocumentURI(url);
if (NS_SUCCEEDED(rv)) {
result.Append(NS_ConvertUTF16toUTF8(url).get());
}
return result;
}
static nsCString
FrameTagToString(dom::Element* aElement)
{
nsCString result;
nsIFrame* frame = aElement->GetPrimaryFrame();
if (frame) {
nsFrame::ListTag(result, frame);
} else {
nsAutoString buf;
aElement->NodeInfo()->NameAtom()->ToString(buf);
result.AppendPrintf("(%s@%p)", NS_ConvertUTF16toUTF8(buf).get(), aElement);
}
return result;
}
#endif
inline nsIDocument*
RestyleTracker::Document() const {
return mRestyleManager->PresContext()->Document();
}
#define RESTYLE_ARRAY_STACKSIZE 128
struct RestyleEnumerateData : RestyleTracker::Hints {
RefPtr<dom::Element> mElement;
#ifdef MOZ_GECKO_PROFILER
UniqueProfilerBacktrace mBacktrace;
#endif
};
inline void
RestyleTracker::ProcessOneRestyle(Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aChangeHint,
const RestyleHintData& aRestyleHintData)
{
NS_PRECONDITION((aRestyleHint & eRestyle_LaterSiblings) == 0,
"Someone should have handled this before calling us");
NS_PRECONDITION(Document(), "Must have a document");
NS_PRECONDITION(aElement->GetComposedDoc() == Document(),
"Element has unexpected document");
LOG_RESTYLE("aRestyleHint = %s, aChangeHint = %s",
GeckoRestyleManager::RestyleHintToString(aRestyleHint).get(),
GeckoRestyleManager::ChangeHintToString(aChangeHint).get());
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
if (aRestyleHint & ~eRestyle_LaterSiblings) {
#ifdef RESTYLE_LOGGING
if (ShouldLogRestyle() && primaryFrame &&
GeckoRestyleManager::StructsToLog() != 0) {
LOG_RESTYLE("style context tree before restyle:");
LOG_RESTYLE_INDENT();
primaryFrame->StyleContext()->AsGecko()->LogStyleContextTree(
LoggingDepth(), GeckoRestyleManager::StructsToLog());
}
#endif
mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
*this, aRestyleHint, aRestyleHintData);
} else if (aChangeHint &&
(primaryFrame ||
(aChangeHint & nsChangeHint_ReconstructFrame))) {
// Don't need to recompute style; just apply the hint
nsStyleChangeList changeList(StyleBackendType::Gecko);
changeList.AppendChange(primaryFrame, aElement, aChangeHint);
mRestyleManager->ProcessRestyledFrames(changeList);
}
}
void
RestyleTracker::DoProcessRestyles()
{
#ifdef MOZ_GECKO_PROFILER
nsAutoCString docURL("N/A");
if (profiler_is_active()) {
nsIURI *uri = Document()->GetDocumentURI();
if (uri) {
docURL = uri->GetSpecOrDefault();
}
}
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
"RestyleTracker::DoProcessRestyles", CSS, docURL);
#endif
// Create a AnimationsWithDestroyedFrame during restyling process to
// stop animations and transitions on elements that have no frame at the end
// of the restyling process.
RestyleManager::AnimationsWithDestroyedFrame
animationsWithDestroyedFrame(mRestyleManager);
// Create a ReframingStyleContexts struct on the stack and put it in our
// mReframingStyleContexts for almost all of the remaining scope of
// this function.
//
// It needs to be *in* scope during BeginProcessingRestyles, which
// might (if mDoRebuildAllStyleData is true) do substantial amounts of
// restyle processing.
//
// However, it needs to be *out* of scope during
// EndProcessingRestyles, since we should release the style contexts
// it holds prior to any EndReconstruct call that
// EndProcessingRestyles makes. This is because in EndReconstruct we
// try to destroy the old rule tree using the GC mechanism, which
// means it only gets destroyed if it's unreferenced (and if it's
// referenced, we assert). So we want the ReframingStyleContexts
// (which holds old style contexts) to be destroyed before the
// EndReconstruct so those style contexts go away before
// EndReconstruct.
{
GeckoRestyleManager::ReframingStyleContexts
reframingStyleContexts(mRestyleManager);
mRestyleManager->BeginProcessingRestyles(*this);
LOG_RESTYLE("Processing %d pending %srestyles with %d restyle roots for %s",
mPendingRestyles.Count(),
mRestyleManager->PresContext()->TransitionManager()->
InAnimationOnlyStyleUpdate()
? (const char*) "animation " : (const char*) "",
static_cast<int>(mRestyleRoots.Length()),
GetDocumentURI(Document()).get());
LOG_RESTYLE_INDENT();
// loop so that we process any restyle events generated by processing
while (mPendingRestyles.Count()) {
if (mHaveLaterSiblingRestyles) {
// Convert them to individual restyles on all the later siblings
AutoTArray<RefPtr<Element>, RESTYLE_ARRAY_STACKSIZE> laterSiblingArr;
for (auto iter = mPendingRestyles.Iter(); !iter.Done(); iter.Next()) {
auto element = static_cast<dom::Element*>(iter.Key());
MOZ_ASSERT(!element->IsStyledByServo(),
"Should not have Servo-styled elements here");
// Only collect the entries that actually need restyling by us (and
// haven't, for example, already been restyled).
// It's important to not mess with the flags on entries not in our
// document.
if (element->GetComposedDoc() == Document() &&
element->HasFlag(RestyleBit()) &&
(iter.Data()->mRestyleHint & eRestyle_LaterSiblings)) {
laterSiblingArr.AppendElement(element);
}
}
for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) {
Element* element = laterSiblingArr[i];
MOZ_ASSERT(!element->IsStyledByServo());
for (nsIContent* sibling = element->GetNextSibling();
sibling;
sibling = sibling->GetNextSibling()) {
if (sibling->IsElement()) {
LOG_RESTYLE("adding pending restyle for %s due to "
"eRestyle_LaterSiblings hint on %s",
FrameTagToString(sibling->AsElement()).get(),
FrameTagToString(element->AsElement()).get());
if (AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
nsChangeHint(0))) {
// Nothing else to do here; we'll handle the following
// siblings when we get to |sibling| in laterSiblingArr.
break;
}
}
}
}
// Now remove all those eRestyle_LaterSiblings bits
for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) {
Element* element = laterSiblingArr[i];
NS_ASSERTION(element->HasFlag(RestyleBit()), "How did that happen?");
RestyleData* data;
#ifdef DEBUG
bool found =
#endif
mPendingRestyles.Get(element, &data);
NS_ASSERTION(found, "Where did our entry go?");
data->mRestyleHint =
nsRestyleHint(data->mRestyleHint & ~eRestyle_LaterSiblings);
if (Element* parent = element->GetFlattenedTreeParentElement()) {
parent->UnsetFlags(ELEMENT_HAS_CHILD_WITH_LATER_SIBLINGS_HINT);
}
}
LOG_RESTYLE("%d pending restyles after expanding out "
"eRestyle_LaterSiblings", mPendingRestyles.Count());
mHaveLaterSiblingRestyles = false;
}
uint32_t rootCount;
while ((rootCount = mRestyleRoots.Length())) {
// Make sure to pop the element off our restyle root array, so
// that we can freely append to the array as we process this
// element.
RefPtr<Element> element;
element.swap(mRestyleRoots[rootCount - 1]);
mRestyleRoots.RemoveElementAt(rootCount - 1);
LOG_RESTYLE("processing style root %s at index %d",
FrameTagToString(element).get(), rootCount - 1);
LOG_RESTYLE_INDENT();
// Do the document check before calling GetRestyleData, since we
// don't want to do the sibling-processing GetRestyleData does if
// the node is no longer relevant.
if (element->GetComposedDoc() != Document()) {
// Content node has been removed from our document; nothing else
// to do here
LOG_RESTYLE("skipping, no longer in the document");
continue;
}
nsAutoPtr<RestyleData> data;
if (!GetRestyleData(element, data)) {
LOG_RESTYLE("skipping, already restyled");
continue;
}
{
AutoRestyleTimelineMarker marker(
mRestyleManager->PresContext()->GetDocShell(),
data->mRestyleHint & eRestyle_AllHintsWithAnimations);
#ifdef MOZ_GECKO_PROFILER
Maybe<AutoProfilerTracing> tracing;
if (profiler_feature_active(ProfilerFeature::Restyle)) {
tracing.emplace("Paint", "Styles", Move(data->mBacktrace));
}
#endif
ProcessOneRestyle(element, data->mRestyleHint, data->mChangeHint,
data->mRestyleHintData);
AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
}
}
if (mHaveLaterSiblingRestyles) {
// Keep processing restyles for now
continue;
}
// Now we only have entries with change hints left. To be safe in
// case of reentry from the handing of the change hint, use a
// scratch array instead of calling out to ProcessOneRestyle while
// enumerating the hashtable. Use the stack if we can, otherwise
// fall back on heap-allocation.
AutoTArray<RestyleEnumerateData, RESTYLE_ARRAY_STACKSIZE> restyleArr;
RestyleEnumerateData* restylesToProcess =
restyleArr.AppendElements(mPendingRestyles.Count());
if (restylesToProcess) {
RestyleEnumerateData* restyle = restylesToProcess;
#ifdef RESTYLE_LOGGING
uint32_t count = 0;
#endif
for (auto iter = mPendingRestyles.Iter(); !iter.Done(); iter.Next()) {
auto element = static_cast<dom::Element*>(iter.Key());
RestyleTracker::RestyleData* data = iter.Data();
// Only collect the entries that actually need restyling by us (and
// haven't, for example, already been restyled).
// It's important to not mess with the flags on entries not in our
// document.
if (element->GetComposedDoc() != Document() ||
!element->HasFlag(RestyleBit())) {
LOG_RESTYLE("skipping pending restyle %s, already restyled or no "
"longer in the document",
FrameTagToString(element).get());
continue;
}
NS_ASSERTION(
!element->HasFlag(RootBit()) ||
// Maybe we're just not reachable via the frame tree?
(element->GetFlattenedTreeParent() &&
(!element->GetFlattenedTreeParent()->GetPrimaryFrame() ||
element->GetFlattenedTreeParent()->GetPrimaryFrame()->IsLeaf() ||
element->GetComposedDoc()->GetShell()->FrameConstructor()
->GetDisplayContentsStyleFor(element))) ||
// Or not reachable due to an async reinsert we have
// pending? If so, we'll have a reframe hint around.
// That incidentally makes it safe that we still have
// the bit, since any descendants that didn't get added
// to the roots list because we had the bits will be
// completely restyled in a moment.
(data->mChangeHint & nsChangeHint_ReconstructFrame),
"Why did this not get handled while processing mRestyleRoots?");
// Unset the restyle bits now, so if they get readded later as we
// process we won't clobber that adding of the bit.
element->UnsetFlags(RestyleBit() |
RootBit() |
ConditionalDescendantsBit());
restyle->mElement = element;
restyle->mRestyleHint = data->mRestyleHint;
restyle->mChangeHint = data->mChangeHint;
// We can move data since we'll be clearing mPendingRestyles after
// we finish enumerating it.
restyle->mRestyleHintData = Move(data->mRestyleHintData);
#ifdef MOZ_GECKO_PROFILER
restyle->mBacktrace = Move(data->mBacktrace);
#endif
#ifdef RESTYLE_LOGGING
count++;
#endif
// Increment to the next slot in the array
restyle++;
}
RestyleEnumerateData* lastRestyle = restyle;
// Clear the hashtable now that we don't need it anymore
mPendingRestyles.Clear();
#ifdef RESTYLE_LOGGING
uint32_t index = 0;
#endif
for (RestyleEnumerateData* currentRestyle = restylesToProcess;
currentRestyle != lastRestyle;
++currentRestyle) {
LOG_RESTYLE("processing pending restyle %s at index %d/%d",
FrameTagToString(currentRestyle->mElement).get(),
index++, count);
LOG_RESTYLE_INDENT();
#ifdef MOZ_GECKO_PROFILER
Maybe<AutoProfilerTracing> tracing;
if (profiler_feature_active(ProfilerFeature::Restyle)) {
tracing.emplace("Paint", "Styles",
Move(currentRestyle->mBacktrace));
}
#endif
{
AutoRestyleTimelineMarker marker(
mRestyleManager->PresContext()->GetDocShell(),
currentRestyle->mRestyleHint & eRestyle_AllHintsWithAnimations);
ProcessOneRestyle(currentRestyle->mElement,
currentRestyle->mRestyleHint,
currentRestyle->mChangeHint,
currentRestyle->mRestyleHintData);
}
}
}
}
}
// mPendingRestyles is now empty.
mHaveSelectors = false;
mRestyleManager->EndProcessingRestyles();
}
bool
RestyleTracker::GetRestyleData(Element* aElement, nsAutoPtr<RestyleData>& aData)
{
NS_PRECONDITION(aElement->GetComposedDoc() == Document(),
"Unexpected document; this will lead to incorrect behavior!");
if (!aElement->HasFlag(RestyleBit())) {
NS_ASSERTION(!aElement->HasFlag(RootBit()), "Bogus root bit?");
return false;
}
mPendingRestyles.Remove(aElement, &aData);
NS_ASSERTION(aData.get(), "Must have data if restyle bit is set");
if (aData->mRestyleHint & eRestyle_LaterSiblings) {
// Someone readded the eRestyle_LaterSiblings hint for this
// element. Leave it around for now, but remove the other restyle
// hints and the change hint for it. Also unset its root bit,
// since it's no longer a root with the new restyle data.
// During a normal restyle, we should have already processed the
// mDescendants array the last time we processed the restyle
// for this element. But in RebuildAllStyleData, we don't initially
// expand out eRestyle_LaterSiblings, so we can get in here the
// first time we need to process a restyle for this element. In that
// case, it's fine for us to have a non-empty mDescendants, since
// we know that RebuildAllStyleData adds eRestyle_ForceDescendants
// and we're guaranteed we'll restyle the entire tree.
NS_ASSERTION(mRestyleManager->InRebuildAllStyleData() ||
aData->mDescendants.IsEmpty(),
"expected descendants to be handled by now");
RestyleData* newData = new RestyleData;
newData->mChangeHint = nsChangeHint(0);
newData->mRestyleHint = eRestyle_LaterSiblings;
mPendingRestyles.Put(aElement, newData);
aElement->UnsetFlags(RootBit());
aData->mRestyleHint =
nsRestyleHint(aData->mRestyleHint & ~eRestyle_LaterSiblings);
} else {
aElement->UnsetFlags(mRestyleBits);
}
return true;
}
void
RestyleTracker::AddRestyleRootsIfAwaitingRestyle(
const nsTArray<RefPtr<Element>>& aElements)
{
// The RestyleData for a given element has stored in mDescendants
// the list of descendants we need to end up restyling. Since we
// won't necessarily end up restyling them, due to the restyle
// process finishing early (see how RestyleResult::eStop is handled
// in ElementRestyler::Restyle), we add them to the list of restyle
// roots to handle the next time around the
// RestyleTracker::DoProcessRestyles loop.
//
// Note that aElements must maintain the same invariant
// that mRestyleRoots does, i.e. that ancestors appear after descendants.
// Since we call AddRestyleRootsIfAwaitingRestyle only after we have
// removed the restyle root we are currently processing from the end of
// mRestyleRoots, and the only elements we get here in aElements are
// descendants of that restyle root, we are safe to simply append to the
// end of mRestyleRoots to maintain its invariant.
for (size_t i = 0; i < aElements.Length(); i++) {
Element* element = aElements[i];
if (element->HasFlag(RestyleBit())) {
mRestyleRoots.AppendElement(element);
}
}
}
void
RestyleTracker::ClearSelectors()
{
if (!mHaveSelectors) {
return;
}
for (auto it = mPendingRestyles.Iter(); !it.Done(); it.Next()) {
RestyleData* data = it.Data();
if (data->mRestyleHint & eRestyle_SomeDescendants) {
data->mRestyleHint =
(data->mRestyleHint & ~eRestyle_SomeDescendants) | eRestyle_Subtree;
data->mRestyleHintData.mSelectorsForDescendants.Clear();
} else {
MOZ_ASSERT(data->mRestyleHintData.mSelectorsForDescendants.IsEmpty());
}
}
mHaveSelectors = false;
}
} // namespace mozilla

Просмотреть файл

@ -88,11 +88,6 @@ EXPORTS.mozilla += [
'UndisplayedNode.h',
]
if CONFIG['MOZ_OLD_STYLE']:
EXPORTS.mozilla += [
'GeckoRestyleManager.h',
]
UNIFIED_SOURCES += [
'AccessibleCaret.cpp',
'AccessibleCaretEventHub.cpp',
@ -130,12 +125,6 @@ UNIFIED_SOURCES += [
'ZoomConstraintsClient.cpp',
]
if CONFIG['MOZ_OLD_STYLE']:
UNIFIED_SOURCES += [
'GeckoRestyleManager.cpp',
'RestyleTracker.cpp',
]
# nsRefreshDriver.cpp needs to be built separately because of name clashes in the OS X headers
SOURCES += [
'nsRefreshDriver.cpp',

Просмотреть файл

@ -1,928 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* representation of a CSS style sheet */
#include "mozilla/CSSStyleSheet.h"
#include "nsAtom.h"
#include "nsCSSRuleProcessor.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/Element.h"
#include "mozilla/css/NameSpaceRule.h"
#include "mozilla/css/GroupRule.h"
#include "mozilla/css/ImportRule.h"
#include "nsCSSRules.h"
#include "nsMediaList.h"
#include "nsIDocument.h"
#include "nsPresContext.h"
#include "nsGkAtoms.h"
#include "nsQueryObject.h"
#include "nsString.h"
#include "nsStyleSet.h"
#include "nsTArray.h"
#include "mozilla/dom/CSSRuleList.h"
#include "nsIDOMNode.h"
#include "nsError.h"
#include "nsCSSParser.h"
#include "mozilla/css/Loader.h"
#include "nsNameSpaceManager.h"
#include "nsXMLNameSpaceMap.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsIScriptSecurityManager.h"
#include "mozAutoDocUpdate.h"
#include "nsMediaFeatures.h"
#include "nsDOMClassInfoID.h"
#include "mozilla/Likely.h"
#include "nsComponentManagerUtils.h"
#include "NullPrincipal.h"
#include "mozilla/RuleProcessorCache.h"
#include "nsIStyleSheetLinkingElement.h"
#include "nsDOMWindowUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
// -------------------------------
// Style Rule List for the DOM
//
class CSSRuleListImpl final : public CSSRuleList
{
public:
explicit CSSRuleListImpl(CSSStyleSheet *aStyleSheet);
virtual CSSStyleSheet* GetParentObject() override;
virtual css::Rule*
IndexedGetter(uint32_t aIndex, bool& aFound) override;
virtual uint32_t
Length() override;
void DropReference() { mStyleSheet = nullptr; }
protected:
virtual ~CSSRuleListImpl();
CSSStyleSheet* mStyleSheet;
};
CSSRuleListImpl::CSSRuleListImpl(CSSStyleSheet *aStyleSheet)
{
// Not reference counted to avoid circular references.
// The style sheet will tell us when its going away.
mStyleSheet = aStyleSheet;
}
CSSRuleListImpl::~CSSRuleListImpl()
{
}
CSSStyleSheet*
CSSRuleListImpl::GetParentObject()
{
return mStyleSheet;
}
uint32_t
CSSRuleListImpl::Length()
{
if (!mStyleSheet) {
return 0;
}
return AssertedCast<uint32_t>(mStyleSheet->StyleRuleCount());
}
css::Rule*
CSSRuleListImpl::IndexedGetter(uint32_t aIndex, bool& aFound)
{
aFound = false;
if (mStyleSheet) {
// ensure rules have correct parent
mStyleSheet->EnsureUniqueInner();
css::Rule* rule = mStyleSheet->GetStyleRuleAt(aIndex);
if (rule) {
aFound = true;
return rule;
}
}
// Per spec: "Return Value ... null if ... not a valid index."
return nullptr;
}
namespace mozilla {
// -------------------------------
// CSS Style Sheet Inner Data Container
//
CSSStyleSheetInner::CSSStyleSheetInner(CORSMode aCORSMode,
ReferrerPolicy aReferrerPolicy,
const SRIMetadata& aIntegrity)
: StyleSheetInfo(aCORSMode, aReferrerPolicy, aIntegrity)
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
}
bool
CSSStyleSheet::RebuildChildList(css::Rule* aRule,
ChildSheetListBuilder* aBuilder)
{
int32_t type = aRule->GetType();
if (type < css::Rule::IMPORT_RULE) {
// Keep going till we get to the import rules.
return true;
}
if (type != css::Rule::IMPORT_RULE) {
// We're past all the import rules; stop the enumeration.
return false;
}
css::ImportRule* importRule = static_cast<css::ImportRule*>(aRule);
StyleSheet* sheet = importRule->GetStyleSheet();
if (!sheet) {
return true;
}
(*aBuilder->sheetSlot) = sheet;
aBuilder->SetParentLinks(*aBuilder->sheetSlot);
aBuilder->sheetSlot = &(*aBuilder->sheetSlot)->mNext;
return true;
}
size_t
CSSStyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = StyleSheet::SizeOfIncludingThis(aMallocSizeOf);
const CSSStyleSheet* s = this;
while (s) {
// Each inner can be shared by multiple sheets. So we only count the inner
// if this sheet is the last one in the list of those sharing it. As a
// result, the last such sheet takes all the blame for the memory
// consumption of the inner, which isn't ideal but it's better than
// double-counting the inner. We use last instead of first since the first
// sheet may be held in the nsXULPrototypeCache and not used in a window at
// all.
if (s->Inner()->mSheets.LastElement() == s) {
n += s->Inner()->SizeOfIncludingThis(aMallocSizeOf);
}
// Measurement of the following members may be added later if DMD finds it
// is worthwhile:
// - s->mRuleCollection
// - s->mRuleProcessors
//
// The following members are not measured:
// - s->mOwnerRule, because it's non-owning
s = s->mNext ? s->mNext->AsGecko() : nullptr;
}
return n;
}
CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
CSSStyleSheet* aPrimarySheet)
: StyleSheetInfo(aCopy, aPrimarySheet)
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
for (css::Rule* rule : aCopy.mOrderedRules) {
RefPtr<css::Rule> clone = rule->Clone();
mOrderedRules.AppendObject(clone);
clone->SetStyleSheet(aPrimarySheet);
}
StyleSheet::ChildSheetListBuilder builder = { &mFirstChild, aPrimarySheet };
for (css::Rule* rule : mOrderedRules) {
if (!CSSStyleSheet::RebuildChildList(rule, &builder)) {
break;
}
}
RebuildNameSpaces();
}
CSSStyleSheetInner::~CSSStyleSheetInner()
{
MOZ_COUNT_DTOR(CSSStyleSheetInner);
for (css::Rule* rule : mOrderedRules) {
rule->SetStyleSheet(nullptr);
}
}
StyleSheetInfo*
CSSStyleSheetInner::CloneFor(StyleSheet* aPrimarySheet)
{
return new CSSStyleSheetInner(*this,
static_cast<CSSStyleSheet*>(aPrimarySheet));
}
void
CSSStyleSheetInner::RemoveSheet(StyleSheet* aSheet)
{
if (aSheet == mSheets.ElementAt(0) && mSheets.Length() > 1) {
StyleSheet* sheet = mSheets[1];
for (css::Rule* rule : mOrderedRules) {
rule->SetStyleSheet(sheet);
}
}
// Don't do anything after this call, because superclass implementation
// may delete this.
StyleSheetInfo::RemoveSheet(aSheet);
}
static void
AddNamespaceRuleToMap(css::Rule* aRule, nsXMLNameSpaceMap* aMap)
{
NS_ASSERTION(aRule->GetType() == css::Rule::NAMESPACE_RULE, "Bogus rule type");
RefPtr<css::NameSpaceRule> nameSpaceRule = do_QueryObject(aRule);
nsAutoString urlSpec;
nameSpaceRule->GetURLSpec(urlSpec);
aMap->AddPrefix(nameSpaceRule->GetPrefix(), urlSpec);
}
void
CSSStyleSheetInner::RebuildNameSpaces()
{
// Just nuke our existing namespace map, if any
if (NS_SUCCEEDED(CreateNamespaceMap())) {
for (css::Rule* rule : mOrderedRules) {
switch (rule->GetType()) {
case css::Rule::NAMESPACE_RULE:
AddNamespaceRuleToMap(rule, mNameSpaceMap);
continue;
case css::Rule::CHARSET_RULE:
case css::Rule::IMPORT_RULE:
continue;
}
break;
}
}
}
nsresult
CSSStyleSheetInner::CreateNamespaceMap()
{
mNameSpaceMap = nsXMLNameSpaceMap::Create(false);
NS_ENSURE_TRUE(mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY);
// Override the default namespace map behavior for the null prefix to
// return the wildcard namespace instead of the null namespace.
mNameSpaceMap->AddPrefix(nullptr, kNameSpaceID_Unknown);
return NS_OK;
}
size_t
CSSStyleSheetInner::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
n += mOrderedRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (size_t i = 0; i < mOrderedRules.Length(); i++) {
n += mOrderedRules[i]->SizeOfIncludingThis(aMallocSizeOf);
}
n += mFirstChild ? mFirstChild->SizeOfIncludingThis(aMallocSizeOf) : 0;
// Measurement of the following members may be added later if DMD finds it is
// worthwhile:
// - mSheetURI
// - mOriginalSheetURI
// - mBaseURI
// - mPrincipal
// - mNameSpaceMap
//
// The following members are not measured:
// - mSheets, because it's non-owning
return n;
}
// -------------------------------
// CSS Style Sheet
//
CSSStyleSheet::CSSStyleSheet(css::SheetParsingMode aParsingMode,
CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy)
: StyleSheet(StyleBackendType::Gecko, aParsingMode),
mInRuleProcessorCache(false),
mRuleProcessors(nullptr)
{
mInner = new CSSStyleSheetInner(aCORSMode, aReferrerPolicy,
SRIMetadata());
mInner->AddSheet(this);
}
CSSStyleSheet::CSSStyleSheet(css::SheetParsingMode aParsingMode,
CORSMode aCORSMode,
ReferrerPolicy aReferrerPolicy,
const SRIMetadata& aIntegrity)
: StyleSheet(StyleBackendType::Gecko, aParsingMode),
mInRuleProcessorCache(false),
mRuleProcessors(nullptr)
{
mInner = new CSSStyleSheetInner(aCORSMode, aReferrerPolicy,
aIntegrity);
mInner->AddSheet(this);
}
CSSStyleSheet::CSSStyleSheet(const CSSStyleSheet& aCopy,
CSSStyleSheet* aParentToUse,
dom::CSSImportRule* aOwnerRuleToUse,
nsIDocument* aDocumentToUse,
nsINode* aOwningNodeToUse)
: StyleSheet(aCopy,
aParentToUse,
aOwnerRuleToUse,
aDocumentToUse,
aOwningNodeToUse)
, mInRuleProcessorCache(false)
, mRuleProcessors(nullptr)
{
if (HasForcedUniqueInner()) { // CSSOM's been there, force full copy now
NS_ASSERTION(mInner->mComplete,
"Why have rules been accessed on an incomplete sheet?");
// FIXME: handle failure?
//
// NOTE: It's important to call this from the subclass, since it could
// access uninitialized members otherwise.
EnsureUniqueInner();
}
}
CSSStyleSheet::~CSSStyleSheet()
{
}
void
CSSStyleSheet::LastRelease()
{
DropRuleCollection();
// XXX The document reference is not reference counted and should
// not be released. The document will let us know when it is going
// away.
if (mRuleProcessors) {
NS_ASSERTION(mRuleProcessors->Length() == 0, "destructing sheet with rule processor reference");
delete mRuleProcessors; // weak refs, should be empty here anyway
mRuleProcessors = nullptr;
}
if (mInRuleProcessorCache) {
RuleProcessorCache::RemoveSheet(this);
}
}
void
CSSStyleSheet::DropRuleCollection()
{
if (mRuleCollection) {
mRuleCollection->DropReference();
mRuleCollection = nullptr;
}
}
void
CSSStyleSheet::UnlinkInner()
{
// We can only have a cycle through our inner if we have a unique inner,
// because otherwise there are no JS wrappers for anything in the inner.
if (mInner->mSheets.Length() != 1) {
return;
}
for (css::Rule* rule : Inner()->mOrderedRules) {
rule->SetStyleSheet(nullptr);
}
Inner()->mOrderedRules.Clear();
StyleSheet::UnlinkInner();
}
void
CSSStyleSheet::TraverseInner(nsCycleCollectionTraversalCallback &cb)
{
// We can only have a cycle through our inner if we have a unique inner,
// because otherwise there are no JS wrappers for anything in the inner.
if (mInner->mSheets.Length() != 1) {
return;
}
const nsCOMArray<css::Rule>& rules = Inner()->mOrderedRules;
for (int32_t i = 0, count = rules.Count(); i < count; ++i) {
if (!rules[i]->IsCCLeaf()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mOrderedRules[i]");
cb.NoteXPCOMChild(rules[i]);
}
}
StyleSheet::TraverseInner(cb);
}
// QueryInterface implementation for CSSStyleSheet
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSStyleSheet)
if (aIID.Equals(NS_GET_IID(CSSStyleSheet)))
foundInterface = reinterpret_cast<nsISupports*>(this);
else
NS_INTERFACE_MAP_END_INHERITING(StyleSheet)
NS_IMPL_ADDREF_INHERITED(CSSStyleSheet, StyleSheet)
NS_IMPL_RELEASE_INHERITED(CSSStyleSheet, StyleSheet)
NS_IMPL_CYCLE_COLLECTION_CLASS(CSSStyleSheet)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSStyleSheet)
// We do not unlink mNext; our parent will handle that. If we
// unlinked it here, our parent would not be able to walk its list
// of child sheets and null out the back-references to it, if we got
// unlinked before it does.
tmp->DropRuleCollection();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(StyleSheet)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSStyleSheet, StyleSheet)
// We do not traverse mNext; our parent will handle that. See
// comments in Unlink for why.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleCollection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
nsresult
CSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor* aProcessor)
{
if (! mRuleProcessors) {
mRuleProcessors = new AutoTArray<nsCSSRuleProcessor*, 8>();
if (!mRuleProcessors)
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ASSERTION(mRuleProcessors->NoIndex == mRuleProcessors->IndexOf(aProcessor),
"processor already registered");
mRuleProcessors->AppendElement(aProcessor); // weak ref
return NS_OK;
}
nsresult
CSSStyleSheet::DropRuleProcessor(nsCSSRuleProcessor* aProcessor)
{
if (!mRuleProcessors)
return NS_ERROR_FAILURE;
return mRuleProcessors->RemoveElement(aProcessor)
? NS_OK
: NS_ERROR_FAILURE;
}
bool
CSSStyleSheet::UseForPresentation(nsPresContext* aPresContext,
nsMediaQueryResultCacheKey& aKey) const
{
if (mMedia) {
MOZ_ASSERT(aPresContext);
auto media = static_cast<nsMediaList*>(mMedia.get());
return media->Matches(aPresContext, &aKey);
}
return true;
}
bool
CSSStyleSheet::HasRules() const
{
return StyleRuleCount() != 0;
}
void
CSSStyleSheet::EnabledStateChangedInternal()
{
ClearRuleCascades();
}
void
CSSStyleSheet::AppendStyleRule(css::Rule* aRule)
{
NS_PRECONDITION(nullptr != aRule, "null arg");
WillDirty();
Inner()->mOrderedRules.AppendObject(aRule);
aRule->SetStyleSheet(this);
DidDirty();
if (css::Rule::NAMESPACE_RULE == aRule->GetType()) {
#ifdef DEBUG
nsresult rv =
#endif
RegisterNamespaceRule(aRule);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"RegisterNamespaceRule returned error");
}
}
int32_t
CSSStyleSheet::StyleRuleCount() const
{
return Inner()->mOrderedRules.Count();
}
css::Rule*
CSSStyleSheet::GetStyleRuleAt(int32_t aIndex) const
{
// Important: If this function is ever made scriptable, we must add
// a security check here. See GetCssRules below for an example.
return Inner()->mOrderedRules.SafeObjectAt(aIndex);
}
already_AddRefed<StyleSheet>
CSSStyleSheet::Clone(StyleSheet* aCloneParent,
dom::CSSImportRule* aCloneOwnerRule,
nsIDocument* aCloneDocument,
nsINode* aCloneOwningNode) const
{
RefPtr<StyleSheet> clone = new CSSStyleSheet(*this,
static_cast<CSSStyleSheet*>(aCloneParent),
aCloneOwnerRule,
aCloneDocument,
aCloneOwningNode);
return clone.forget();
}
#ifdef DEBUG
static void
ListRules(const nsCOMArray<css::Rule>& aRules, FILE* aOut, int32_t aIndent)
{
for (int32_t index = aRules.Count() - 1; index >= 0; --index) {
aRules.ObjectAt(index)->List(aOut, aIndent);
}
}
void
CSSStyleSheet::List(FILE* out, int32_t aIndent) const
{
StyleSheet::List(out, aIndent);
fprintf_stderr(out, "%s", "Rules in source order:\n");
ListRules(Inner()->mOrderedRules, out, aIndent);
}
#endif
void
CSSStyleSheet::ClearRuleCascades()
{
// We might be in ClearRuleCascadesInternal because we had a modification
// to the sheet that resulted in an nsCSSSelector being destroyed.
// Tell the RestyleManager for each document we're used in
// so that they can drop any nsCSSSelector pointers (used for
// eRestyle_SomeDescendants) in their mPendingRestyles.
for (StyleSetHandle setHandle : mStyleSets) {
setHandle->AsGecko()->ClearSelectors();
}
bool removedSheetFromRuleProcessorCache = false;
if (mRuleProcessors) {
nsCSSRuleProcessor **iter = mRuleProcessors->Elements(),
**end = iter + mRuleProcessors->Length();
for(; iter != end; ++iter) {
if (!removedSheetFromRuleProcessorCache && (*iter)->IsShared()) {
// Since the sheet has been modified, we need to remove all
// RuleProcessorCache entries that contain this sheet, as the
// list of @-moz-document rules might have changed.
RuleProcessorCache::RemoveSheet(this);
removedSheetFromRuleProcessorCache = true;
}
(*iter)->ClearRuleCascades();
}
}
if (mParent) {
static_cast<CSSStyleSheet*>(mParent)->ClearRuleCascades();
}
}
void
CSSStyleSheet::DidDirty()
{
MOZ_ASSERT(!mInner->mComplete || HasForcedUniqueInner(),
"caller must have called WillDirty()");
ClearRuleCascades();
}
nsresult
CSSStyleSheet::RegisterNamespaceRule(css::Rule* aRule)
{
if (!Inner()->mNameSpaceMap) {
nsresult rv = Inner()->CreateNamespaceMap();
NS_ENSURE_SUCCESS(rv, rv);
}
AddNamespaceRuleToMap(aRule, Inner()->mNameSpaceMap);
return NS_OK;
}
CSSRuleList*
CSSStyleSheet::GetCssRulesInternal()
{
if (!mRuleCollection) {
mRuleCollection = new CSSRuleListImpl(this);
}
return mRuleCollection;
}
uint32_t
CSSStyleSheet::InsertRuleInternal(const nsAString& aRule,
uint32_t aIndex,
ErrorResult& aRv)
{
MOZ_ASSERT(mInner->mComplete);
WillDirty();
if (aIndex > uint32_t(Inner()->mOrderedRules.Count())) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return 0;
}
NS_ASSERTION(uint32_t(Inner()->mOrderedRules.Count()) <= INT32_MAX,
"Too many style rules!");
// Hold strong ref to the CSSLoader in case the document update
// kills the document
RefPtr<css::Loader> loader;
if (mDocument) {
loader = mDocument->CSSLoader();
NS_ASSERTION(loader, "Document with no CSS loader!");
}
nsCSSParser css(loader, this);
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
RefPtr<css::Rule> rule;
aRv = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
mInner->mPrincipal, getter_AddRefs(rule));
if (NS_WARN_IF(aRv.Failed())) {
return 0;
}
// Hierarchy checking.
int32_t newType = rule->GetType();
// check that we're not inserting before a charset rule
css::Rule* nextRule = Inner()->mOrderedRules.SafeObjectAt(aIndex);
if (nextRule) {
int32_t nextType = nextRule->GetType();
if (nextType == css::Rule::CHARSET_RULE) {
aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
return 0;
}
if (nextType == css::Rule::IMPORT_RULE &&
newType != css::Rule::CHARSET_RULE &&
newType != css::Rule::IMPORT_RULE) {
aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
return 0;
}
if (nextType == css::Rule::NAMESPACE_RULE &&
newType != css::Rule::CHARSET_RULE &&
newType != css::Rule::IMPORT_RULE &&
newType != css::Rule::NAMESPACE_RULE) {
aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
return 0;
}
}
if (aIndex != 0) {
// no inserting charset at nonzero position
if (newType == css::Rule::CHARSET_RULE) {
aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
return 0;
}
css::Rule* prevRule = Inner()->mOrderedRules.SafeObjectAt(aIndex - 1);
int32_t prevType = prevRule->GetType();
if (newType == css::Rule::IMPORT_RULE &&
prevType != css::Rule::CHARSET_RULE &&
prevType != css::Rule::IMPORT_RULE) {
aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
return 0;
}
if (newType == css::Rule::NAMESPACE_RULE &&
prevType != css::Rule::CHARSET_RULE &&
prevType != css::Rule::IMPORT_RULE &&
prevType != css::Rule::NAMESPACE_RULE) {
aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
return 0;
}
}
if (!Inner()->mOrderedRules.InsertObjectAt(rule, aIndex)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return 0;
}
DidDirty();
rule->SetStyleSheet(this);
int32_t type = rule->GetType();
if (type == css::Rule::NAMESPACE_RULE) {
// XXXbz does this screw up when inserting a namespace rule before
// another namespace rule that binds the same prefix to a different
// namespace?
aRv = RegisterNamespaceRule(rule);
if (NS_WARN_IF(aRv.Failed())) {
return 0;
}
}
// We don't notify immediately for @import rules, but rather when
// the sheet the rule is importing is loaded (see StyleSheetLoaded)
if (type != css::Rule::IMPORT_RULE || !RuleHasPendingChildSheet(rule)) {
RuleAdded(*rule);
}
return aIndex;
}
void
CSSStyleSheet::DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv)
{
// XXX TBI: handle @rule types
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
WillDirty();
if (aIndex >= uint32_t(Inner()->mOrderedRules.Count())) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
NS_ASSERTION(uint32_t(Inner()->mOrderedRules.Count()) <= INT32_MAX,
"Too many style rules!");
// Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt
RefPtr<css::Rule> rule = Inner()->mOrderedRules.ObjectAt(aIndex);
if (rule) {
Inner()->mOrderedRules.RemoveObjectAt(aIndex);
rule->SetStyleSheet(nullptr);
RuleRemoved(*rule);
}
}
nsresult
CSSStyleSheet::InsertRuleIntoGroupInternal(const nsAString& aRule,
css::GroupRule* aGroup,
uint32_t aIndex)
{
// Hold strong ref to the CSSLoader in case the document update
// kills the document
RefPtr<css::Loader> loader;
if (mDocument) {
loader = mDocument->CSSLoader();
NS_ASSERTION(loader, "Document with no CSS loader!");
}
nsCSSParser css(loader, this);
RefPtr<css::Rule> rule;
nsresult result = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
mInner->mPrincipal, getter_AddRefs(rule));
if (NS_FAILED(result))
return result;
switch (rule->GetType()) {
case css::Rule::STYLE_RULE:
case css::Rule::MEDIA_RULE:
case css::Rule::FONT_FACE_RULE:
case css::Rule::PAGE_RULE:
case css::Rule::KEYFRAMES_RULE:
case css::Rule::COUNTER_STYLE_RULE:
case css::Rule::DOCUMENT_RULE:
case css::Rule::SUPPORTS_RULE:
// these types are OK to insert into a group
break;
case css::Rule::CHARSET_RULE:
case css::Rule::IMPORT_RULE:
case css::Rule::NAMESPACE_RULE:
// these aren't
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
default:
NS_NOTREACHED("unexpected rule type");
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
return aGroup->InsertStyleRuleAt(aIndex, rule);
}
// nsICSSLoaderObserver implementation
NS_IMETHODIMP
CSSStyleSheet::StyleSheetLoaded(StyleSheet* aSheet,
bool aWasAlternate,
nsresult aStatus)
{
MOZ_ASSERT(aSheet->IsGecko(),
"why we were called back with a ServoStyleSheet?");
CSSStyleSheet* sheet = aSheet->AsGecko();
if (sheet->GetParentSheet() == nullptr) {
return NS_OK; // ignore if sheet has been detached already (see parseSheet)
}
NS_ASSERTION(this == sheet->GetParentSheet(),
"We are being notified of a sheet load for a sheet that is not our child!");
if (NS_SUCCEEDED(aStatus)) {
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
RuleAdded(*sheet->GetOwnerRule());
}
return NS_OK;
}
nsresult
CSSStyleSheet::ReparseSheet(const nsAString& aInput)
{
// Not doing this if the sheet is not complete!
if (!mInner->mComplete) {
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
// Hold strong ref to the CSSLoader in case the document update
// kills the document
RefPtr<css::Loader> loader;
if (mDocument) {
loader = mDocument->CSSLoader();
NS_ASSERTION(loader, "Document with no CSS loader!");
} else {
loader = new css::Loader(StyleBackendType::Gecko, nullptr);
}
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
WillDirty();
// detach existing rules (including child sheets via import rules)
css::LoaderReusableStyleSheets reusableSheets;
int ruleCount;
while ((ruleCount = Inner()->mOrderedRules.Count()) != 0) {
RefPtr<css::Rule> rule = Inner()->mOrderedRules.ObjectAt(ruleCount - 1);
Inner()->mOrderedRules.RemoveObjectAt(ruleCount - 1);
rule->SetStyleSheet(nullptr);
if (rule->GetType() == css::Rule::IMPORT_RULE) {
auto importRule = static_cast<css::ImportRule*>(rule.get());
RefPtr<StyleSheet> sheet = importRule->GetStyleSheet();
if (sheet && sheet->GetOriginalURI()) {
reusableSheets.AddReusableSheet(sheet);
}
}
RuleRemoved(*rule);
}
// nuke child sheets list and current namespace map
for (StyleSheet* child = GetFirstChild(); child; ) {
NS_ASSERTION(child->mParent == this, "Child sheet is not parented to this!");
StyleSheet* next = child->mNext;
child->mParent = nullptr;
child->SetAssociatedDocument(nullptr, NotOwnedByDocument);
child->mNext = nullptr;
child = next;
}
SheetInfo().mFirstChild = nullptr;
Inner()->mNameSpaceMap = nullptr;
uint32_t lineNumber = 1;
if (mOwningNode) {
nsCOMPtr<nsIStyleSheetLinkingElement> link = do_QueryInterface(mOwningNode);
if (link) {
lineNumber = link->GetLineNumber();
}
}
nsCSSParser parser(loader, this);
nsresult rv = parser.ParseSheet(aInput, mInner->mSheetURI, mInner->mBaseURI,
mInner->mPrincipal, /* aLoadData = */ nullptr,
lineNumber, &reusableSheets);
DidDirty(); // we are always 'dirty' here since we always remove rules first
NS_ENSURE_SUCCESS(rv, rv);
// notify document of all new rules
for (int32_t index = 0; index < Inner()->mOrderedRules.Count(); ++index) {
RefPtr<css::Rule> rule = Inner()->mOrderedRules.ObjectAt(index);
if (rule->GetType() == css::Rule::IMPORT_RULE &&
RuleHasPendingChildSheet(rule)) {
continue; // notify when loaded (see StyleSheetLoaded)
}
RuleAdded(*rule);
}
// Our rules are no longer considered modified.
ClearModifiedRules();
return NS_OK;
}
} // namespace mozilla

Просмотреть файл

@ -1,204 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* representation of a CSS style sheet */
#ifndef mozilla_CSSStyleSheet_h
#define mozilla_CSSStyleSheet_h
#include "mozilla/Attributes.h"
#include "mozilla/IncrementalClearCOMRuleArray.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInfo.h"
#include "mozilla/css/SheetParsingMode.h"
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsTArrayForwardDeclare.h"
#include "nsStringFwd.h"
#include "mozilla/CORSMode.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/net/ReferrerPolicy.h"
#include "mozilla/dom/SRIMetadata.h"
class CSSRuleListImpl;
class nsCSSRuleProcessor;
class nsIURI;
class nsMediaQueryResultCacheKey;
class nsPresContext;
class nsXMLNameSpaceMap;
namespace mozilla {
class CSSStyleSheet;
struct ChildSheetListBuilder;
namespace css {
class GroupRule;
} // namespace css
namespace dom {
class CSSRuleList;
class Element;
} // namespace dom
// -------------------------------
// CSS Style Sheet Inner Data Container
//
struct CSSStyleSheetInner : public StyleSheetInfo
{
CSSStyleSheetInner(CORSMode aCORSMode,
ReferrerPolicy aReferrerPolicy,
const dom::SRIMetadata& aIntegrity);
CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
CSSStyleSheet* aPrimarySheet);
~CSSStyleSheetInner();
StyleSheetInfo* CloneFor(StyleSheet* aPrimarySheet) override;
void RemoveSheet(StyleSheet* aSheet) override;
void RebuildNameSpaces();
// Create a new namespace map
nsresult CreateNamespaceMap();
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
IncrementalClearCOMRuleArray mOrderedRules;
nsAutoPtr<nsXMLNameSpaceMap> mNameSpaceMap;
};
// -------------------------------
// CSS Style Sheet
//
// CID for the CSSStyleSheet class
// 7985c7ac-9ddc-444d-9899-0c86ec122f54
#define NS_CSS_STYLE_SHEET_IMPL_CID \
{ 0x7985c7ac, 0x9ddc, 0x444d, \
{ 0x98, 0x99, 0x0c, 0x86, 0xec, 0x12, 0x2f, 0x54 } }
class CSSStyleSheet final : public StyleSheet
{
public:
typedef net::ReferrerPolicy ReferrerPolicy;
CSSStyleSheet(css::SheetParsingMode aParsingMode,
CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy);
CSSStyleSheet(css::SheetParsingMode aParsingMode,
CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy,
const dom::SRIMetadata& aIntegrity);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSStyleSheet, StyleSheet)
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_SHEET_IMPL_CID)
bool HasRules() const;
#ifdef DEBUG
void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
// XXX do these belong here or are they generic?
void AppendStyleRule(css::Rule* aRule);
int32_t StyleRuleCount() const;
css::Rule* GetStyleRuleAt(int32_t aIndex) const;
nsXMLNameSpaceMap* GetNameSpaceMap() const {
return Inner()->mNameSpaceMap;
}
already_AddRefed<StyleSheet> Clone(StyleSheet* aCloneParent,
dom::CSSImportRule* aCloneOwnerRule,
nsIDocument* aCloneDocument,
nsINode* aCloneOwningNode) const final;
nsresult AddRuleProcessor(nsCSSRuleProcessor* aProcessor);
nsresult DropRuleProcessor(nsCSSRuleProcessor* aProcessor);
// nsICSSLoaderObserver interface
NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasAlternate,
nsresult aStatus) override;
bool UseForPresentation(nsPresContext* aPresContext,
nsMediaQueryResultCacheKey& aKey) const;
nsresult ReparseSheet(const nsAString& aInput);
void SetInRuleProcessorCache() { mInRuleProcessorCache = true; }
// Function used as a callback to rebuild our inner's child sheet
// list after we clone a unique inner for ourselves.
static bool RebuildChildList(css::Rule* aRule,
ChildSheetListBuilder* aBuilder);
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
void DidDirty() override;
private:
CSSStyleSheet(const CSSStyleSheet& aCopy,
CSSStyleSheet* aParentToUse,
dom::CSSImportRule* aOwnerRuleToUse,
nsIDocument* aDocumentToUse,
nsINode* aOwningNodeToUse);
CSSStyleSheet(const CSSStyleSheet& aCopy) = delete;
CSSStyleSheet& operator=(const CSSStyleSheet& aCopy) = delete;
protected:
virtual ~CSSStyleSheet();
void LastRelease();
void ClearRuleCascades();
// Add the namespace mapping from this @namespace rule to our namespace map
nsresult RegisterNamespaceRule(css::Rule* aRule);
// Drop our reference to mRuleCollection
void DropRuleCollection();
CSSStyleSheetInner* Inner() const
{
return static_cast<CSSStyleSheetInner*>(mInner);
}
// Unlink our inner, if needed, for cycle collection
virtual void UnlinkInner() override;
// Traverse our inner, if needed, for cycle collection
virtual void TraverseInner(nsCycleCollectionTraversalCallback &) override;
protected:
// Internal methods which do not have security check and completeness check.
dom::CSSRuleList* GetCssRulesInternal();
uint32_t InsertRuleInternal(const nsAString& aRule,
uint32_t aIndex, ErrorResult& aRv);
void DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv);
nsresult InsertRuleIntoGroupInternal(const nsAString& aRule,
css::GroupRule* aGroup,
uint32_t aIndex);
void EnabledStateChangedInternal();
RefPtr<CSSRuleListImpl> mRuleCollection;
bool mInRuleProcessorCache;
AutoTArray<nsCSSRuleProcessor*, 8>* mRuleProcessors;
friend class mozilla::StyleSheet;
friend class ::nsCSSRuleProcessor;
};
NS_DEFINE_STATIC_IID_ACCESSOR(CSSStyleSheet, NS_CSS_STYLE_SHEET_IMPL_CID)
} // namespace mozilla
#endif /* !defined(mozilla_CSSStyleSheet_h) */

Просмотреть файл

@ -1,194 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* CSS Custom Property assignments for a Declaration at a given priority */
#include "CSSVariableDeclarations.h"
#include "CSSVariableResolver.h"
#include "nsCSSScanner.h"
#include "nsRuleData.h"
// These three special string values are used to represent specified values of
// 'initial', 'inherit' and 'unset'. (Note that none of these are valid
// variable values.)
#define INITIAL_VALUE "!"
#define INHERIT_VALUE ";"
#define UNSET_VALUE ")"
namespace mozilla {
CSSVariableDeclarations::CSSVariableDeclarations()
{
MOZ_COUNT_CTOR(CSSVariableDeclarations);
}
CSSVariableDeclarations::CSSVariableDeclarations(const CSSVariableDeclarations& aOther)
{
MOZ_COUNT_CTOR(CSSVariableDeclarations);
CopyVariablesFrom(aOther);
}
#ifdef DEBUG
CSSVariableDeclarations::~CSSVariableDeclarations()
{
MOZ_COUNT_DTOR(CSSVariableDeclarations);
}
#endif
CSSVariableDeclarations&
CSSVariableDeclarations::operator=(const CSSVariableDeclarations& aOther)
{
if (this == &aOther) {
return *this;
}
mVariables.Clear();
CopyVariablesFrom(aOther);
return *this;
}
void
CSSVariableDeclarations::CopyVariablesFrom(const CSSVariableDeclarations& aOther)
{
for (auto iter = aOther.mVariables.ConstIter(); !iter.Done(); iter.Next()) {
mVariables.Put(iter.Key(), iter.UserData());
}
}
bool
CSSVariableDeclarations::Has(const nsAString& aName) const
{
nsString value;
return mVariables.Get(aName, &value);
}
bool
CSSVariableDeclarations::Get(const nsAString& aName,
Type& aType,
nsString& aTokenStream) const
{
nsString value;
if (!mVariables.Get(aName, &value)) {
return false;
}
if (value.EqualsLiteral(INITIAL_VALUE)) {
aType = eInitial;
aTokenStream.Truncate();
} else if (value.EqualsLiteral(INHERIT_VALUE)) {
aType = eInherit;
aTokenStream.Truncate();
} else if (value.EqualsLiteral(UNSET_VALUE)) {
aType = eUnset;
aTokenStream.Truncate();
} else {
aType = eTokenStream;
aTokenStream = value;
}
return true;
}
void
CSSVariableDeclarations::PutTokenStream(const nsAString& aName,
const nsString& aTokenStream)
{
MOZ_ASSERT(!aTokenStream.EqualsLiteral(INITIAL_VALUE) &&
!aTokenStream.EqualsLiteral(INHERIT_VALUE) &&
!aTokenStream.EqualsLiteral(UNSET_VALUE));
mVariables.Put(aName, aTokenStream);
}
void
CSSVariableDeclarations::PutInitial(const nsAString& aName)
{
mVariables.Put(aName, NS_LITERAL_STRING(INITIAL_VALUE));
}
void
CSSVariableDeclarations::PutInherit(const nsAString& aName)
{
mVariables.Put(aName, NS_LITERAL_STRING(INHERIT_VALUE));
}
void
CSSVariableDeclarations::PutUnset(const nsAString& aName)
{
mVariables.Put(aName, NS_LITERAL_STRING(UNSET_VALUE));
}
void
CSSVariableDeclarations::Remove(const nsAString& aName)
{
mVariables.Remove(aName);
}
void
CSSVariableDeclarations::MapRuleInfoInto(nsRuleData* aRuleData)
{
if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Variables))) {
return;
}
if (!aRuleData->mVariables) {
aRuleData->mVariables = new CSSVariableDeclarations(*this);
} else {
for (auto iter = mVariables.Iter(); !iter.Done(); iter.Next()) {
nsDataHashtable<nsStringHashKey, nsString>& variables =
aRuleData->mVariables->mVariables;
const nsAString& aName = iter.Key();
variables.LookupForAdd(aName).OrInsert(
[&iter] () { return iter.UserData(); });
}
}
}
void
CSSVariableDeclarations::AddVariablesToResolver(
CSSVariableResolver* aResolver) const
{
for (auto iter = mVariables.ConstIter(); !iter.Done(); iter.Next()) {
const nsAString& name = iter.Key();
nsString value = iter.UserData();
if (value.EqualsLiteral(INITIAL_VALUE)) {
// Values of 'initial' are treated the same as an invalid value in the
// variable resolver.
aResolver->Put(name, EmptyString(),
eCSSTokenSerialization_Nothing,
eCSSTokenSerialization_Nothing,
false);
} else if (value.EqualsLiteral(INHERIT_VALUE) ||
value.EqualsLiteral(UNSET_VALUE)) {
// Values of 'inherit' and 'unset' don't need any handling, since it means
// we just need to keep whatever value is currently in the resolver. This
// is because the specified variable declarations already have only the
// winning declaration for the variable and no longer have any of the
// others.
} else {
// At this point, we don't know what token types are at the start and end
// of the specified variable value. These will be determined later during
// the resolving process.
aResolver->Put(name, value,
eCSSTokenSerialization_Nothing,
eCSSTokenSerialization_Nothing,
false);
}
}
}
size_t
CSSVariableDeclarations::SizeOfIncludingThis(
mozilla::MallocSizeOf aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
n += mVariables.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (auto iter = mVariables.ConstIter(); !iter.Done(); iter.Next()) {
n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
n += iter.Data().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
}
return n;
}
} // namespace mozilla

Просмотреть файл

@ -1,140 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* CSS Custom Property assignments for a Declaration at a given priority */
#ifndef mozilla_CSSVariableDeclarations_h
#define mozilla_CSSVariableDeclarations_h
#include "nsDataHashtable.h"
namespace mozilla {
class CSSVariableResolver;
} // namespace mozilla
struct nsRuleData;
namespace mozilla {
class CSSVariableDeclarations
{
public:
CSSVariableDeclarations();
CSSVariableDeclarations(const CSSVariableDeclarations& aOther);
#ifdef DEBUG
~CSSVariableDeclarations();
#endif
CSSVariableDeclarations& operator=(const CSSVariableDeclarations& aOther);
/**
* Returns whether this set of variable declarations includes a variable
* with a given name.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name).
*/
bool Has(const nsAString& aName) const;
/**
* Represents the type of a variable value.
*/
enum Type {
eTokenStream, // a stream of CSS tokens (the usual type for variables)
eInitial, // 'initial'
eInherit, // 'inherit'
eUnset // 'unset'
};
/**
* Gets the value of a variable in this set of variable declarations.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name).
* @param aType Out parameter into which the type of the variable value will
* be stored.
* @param aValue Out parameter into which the value of the variable will
* be stored. If the variable is 'initial', 'inherit' or 'unset', this will
* be the empty string.
* @return Whether a variable with the given name was found. When false
* is returned, aType and aValue will not be modified.
*/
bool Get(const nsAString& aName, Type& aType, nsString& aValue) const;
/**
* Adds or modifies an existing entry in this set of variable declarations
* to have the value 'initial'.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name) whose value is to be set.
*/
void PutInitial(const nsAString& aName);
/**
* Adds or modifies an existing entry in this set of variable declarations
* to have the value 'inherit'.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name) whose value is to be set.
*/
void PutInherit(const nsAString& aName);
/**
* Adds or modifies an existing entry in this set of variable declarations
* to have the value 'unset'.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name) whose value is to be set.
*/
void PutUnset(const nsAString& aName);
/**
* Adds or modifies an existing entry in this set of variable declarations
* to have a token stream value.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name) whose value is to be set.
* @param aTokenStream The CSS token stream.
*/
void PutTokenStream(const nsAString& aName, const nsString& aTokenStream);
/**
* Removes an entry in this set of variable declarations.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name) whose entry is to be removed.
*/
void Remove(const nsAString& aName);
/**
* Returns the number of entries in this set of variable declarations.
*/
uint32_t Count() const { return mVariables.Count(); }
/**
* Copies each variable value from this object into aRuleData, unless that
* variable already exists on aRuleData.
*/
void MapRuleInfoInto(nsRuleData* aRuleData);
/**
* Copies the variables from this object into aResolver, marking them as
* specified values.
*/
void AddVariablesToResolver(CSSVariableResolver* aResolver) const;
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
private:
/**
* Adds all the variable declarations from aOther into this object.
*/
void CopyVariablesFrom(const CSSVariableDeclarations& aOther);
nsDataHashtable<nsStringHashKey, nsString> mVariables;
};
} // namespace mozilla
#endif

Просмотреть файл

@ -1,269 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* object that resolves CSS variables using specified and inherited variable
* values
*/
#include "CSSVariableResolver.h"
#include "CSSVariableDeclarations.h"
#include "CSSVariableValues.h"
#include "mozilla/PodOperations.h"
#include "mozilla/UniquePtr.h"
#include <algorithm>
namespace mozilla {
/**
* Data used by the EnumerateVariableReferences callback. Reset must be called
* on it before it is used.
*/
class EnumerateVariableReferencesData
{
public:
explicit EnumerateVariableReferencesData(CSSVariableResolver& aResolver)
: mResolver(aResolver)
, mReferences(MakeUnique<bool[]>(aResolver.mVariables.Length()))
{
}
/**
* Resets the data so that it can be passed to another call of
* EnumerateVariableReferences for a different variable.
*/
void Reset()
{
PodZero(mReferences.get(), mResolver.mVariables.Length());
mReferencesNonExistentVariable = false;
}
void RecordVariableReference(const nsAString& aVariableName)
{
size_t id;
if (mResolver.mVariableIDs.Get(aVariableName, &id)) {
mReferences[id] = true;
} else {
mReferencesNonExistentVariable = true;
}
}
bool HasReferenceToVariable(size_t aID) const
{
return mReferences[aID];
}
bool ReferencesNonExistentVariable() const
{
return mReferencesNonExistentVariable;
}
private:
CSSVariableResolver& mResolver;
// Array of booleans, where each index is a variable ID. If an element is
// true, it indicates that the variable we have called
// EnumerateVariableReferences for has a reference to the variable with
// that ID.
const UniquePtr<bool[]> mReferences;
// Whether the variable we have called EnumerateVariableReferences for
// references a variable that does not exist in the resolver.
bool mReferencesNonExistentVariable;
};
static void
RecordVariableReference(const nsAString& aVariableName,
void* aData)
{
static_cast<EnumerateVariableReferencesData*>(aData)->
RecordVariableReference(aVariableName);
}
void
CSSVariableResolver::RemoveCycles(size_t v)
{
mVariables[v].mIndex = mNextIndex;
mVariables[v].mLowLink = mNextIndex;
mVariables[v].mInStack = true;
mStack.AppendElement(v);
mNextIndex++;
for (size_t i = 0, n = mReferences[v].Length(); i < n; i++) {
size_t w = mReferences[v][i];
if (!mVariables[w].mIndex) {
RemoveCycles(w);
mVariables[v].mLowLink = std::min(mVariables[v].mLowLink,
mVariables[w].mLowLink);
} else if (mVariables[w].mInStack) {
mVariables[v].mLowLink = std::min(mVariables[v].mLowLink,
mVariables[w].mIndex);
}
}
if (mVariables[v].mLowLink == mVariables[v].mIndex) {
if (mStack.LastElement() == v) {
// A strongly connected component consisting of a single variable is not
// necessarily invalid. We handle variables that reference themselves
// earlier, in CSSVariableResolver::Resolve.
mVariables[mStack.LastElement()].mInStack = false;
mStack.TruncateLength(mStack.Length() - 1);
} else {
size_t w;
do {
w = mStack.LastElement();
mVariables[w].mValue.Truncate(0);
mVariables[w].mInStack = false;
mStack.TruncateLength(mStack.Length() - 1);
} while (w != v);
}
}
}
void
CSSVariableResolver::ResolveVariable(size_t aID)
{
if (mVariables[aID].mValue.IsEmpty() || mVariables[aID].mWasInherited) {
// The variable is invalid or was inherited. We can just copy the value
// and its first/last token information across.
mOutput->Put(mVariables[aID].mVariableName,
mVariables[aID].mValue,
mVariables[aID].mFirstToken,
mVariables[aID].mLastToken);
} else {
// Otherwise we need to resolve the variable references, after resolving
// all of our dependencies first. We do this even for variables that we
// know do not reference other variables so that we can find their
// first/last token.
//
// XXX We might want to do this first/last token finding during
// EnumerateVariableReferences, so that we can avoid calling
// ResolveVariableValue and parsing the value again.
for (size_t i = 0, n = mReferences[aID].Length(); i < n; i++) {
size_t j = mReferences[aID][i];
if (aID != j && !mVariables[j].mResolved) {
ResolveVariable(j);
}
}
nsString resolvedValue;
nsCSSTokenSerializationType firstToken, lastToken;
if (mParser.ResolveVariableValue(mVariables[aID].mValue, mOutput,
resolvedValue, firstToken, lastToken)) {
mOutput->Put(mVariables[aID].mVariableName, resolvedValue,
firstToken, lastToken);
} else {
mOutput->Put(mVariables[aID].mVariableName, EmptyString(),
eCSSTokenSerialization_Nothing, eCSSTokenSerialization_Nothing);
}
}
mVariables[aID].mResolved = true;
}
void
CSSVariableResolver::Resolve(const CSSVariableValues* aInherited,
const CSSVariableDeclarations* aSpecified)
{
MOZ_ASSERT(!mResolved);
// The only time we would be worried about having a null aInherited is
// for the root, but in that case nsRuleNode::ComputeVariablesData will
// happen to pass in whatever we're using as mOutput for aInherited,
// which will initially be empty.
MOZ_ASSERT(aInherited);
MOZ_ASSERT(aSpecified);
aInherited->AddVariablesToResolver(this);
aSpecified->AddVariablesToResolver(this);
// First we look at each variable's value and record which other variables
// it references.
size_t n = mVariables.Length();
mReferences.SetLength(n);
EnumerateVariableReferencesData data(*this);
for (size_t id = 0; id < n; id++) {
data.Reset();
if (!mVariables[id].mWasInherited &&
!mVariables[id].mValue.IsEmpty()) {
if (mParser.EnumerateVariableReferences(mVariables[id].mValue,
RecordVariableReference,
&data)) {
// Convert the boolean array of dependencies in |data| to a list
// of dependencies.
for (size_t i = 0; i < n; i++) {
if (data.HasReferenceToVariable(i)) {
mReferences[id].AppendElement(i);
}
}
// If a variable references itself, it is invalid. (RemoveCycles
// does not check for cycles consisting of a single variable, so we
// check here.)
if (data.HasReferenceToVariable(id)) {
mVariables[id].mValue.Truncate();
}
// Also record whether it referenced any variables that don't exist
// in the resolver, so that we can ensure we still resolve its value
// in ResolveVariable, even though its mReferences list is empty.
mVariables[id].mReferencesNonExistentVariable =
data.ReferencesNonExistentVariable();
} else {
MOZ_ASSERT(false, "EnumerateVariableReferences should not have failed "
"if we previously parsed the specified value");
mVariables[id].mValue.Truncate(0);
}
}
}
// Next we remove any cycles in variable references using Tarjan's strongly
// connected components finding algorithm, setting variables in cycles to
// have an invalid value.
mNextIndex = 1;
for (size_t id = 0; id < n; id++) {
if (!mVariables[id].mIndex) {
RemoveCycles(id);
MOZ_ASSERT(mStack.IsEmpty());
}
}
// Finally we construct the computed value for the variable by substituting
// any variable references.
for (size_t id = 0; id < n; id++) {
if (!mVariables[id].mResolved) {
ResolveVariable(id);
}
}
#ifdef DEBUG
mResolved = true;
#endif
}
void
CSSVariableResolver::Put(const nsAString& aVariableName,
nsString aValue,
nsCSSTokenSerializationType aFirstToken,
nsCSSTokenSerializationType aLastToken,
bool aWasInherited)
{
MOZ_ASSERT(!mResolved);
size_t id;
if (mVariableIDs.Get(aVariableName, &id)) {
MOZ_ASSERT(mVariables[id].mWasInherited && !aWasInherited,
"should only overwrite inherited variables with specified "
"variables");
mVariables[id].mValue = aValue;
mVariables[id].mFirstToken = aFirstToken;
mVariables[id].mLastToken = aLastToken;
mVariables[id].mWasInherited = aWasInherited;
} else {
id = mVariables.Length();
mVariableIDs.Put(aVariableName, id);
mVariables.AppendElement(Variable(aVariableName, aValue,
aFirstToken, aLastToken, aWasInherited));
}
}
} // namespace mozilla

Просмотреть файл

@ -1,149 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* object that resolves CSS variables using specified and inherited variable
* values
*/
#ifndef mozilla_CSSVariableResolver_h
#define mozilla_CSSVariableResolver_h
#include "mozilla/DebugOnly.h"
#include "nsCSSParser.h"
#include "nsCSSScanner.h"
#include "nsDataHashtable.h"
#include "nsTArray.h"
namespace mozilla {
class CSSVariableDeclarations;
class CSSVariableValues;
class EnumerateVariableReferencesData;
class CSSVariableResolver
{
friend class CSSVariableDeclarations;
friend class CSSVariableValues;
friend class EnumerateVariableReferencesData;
public:
/**
* Creates a new CSSVariableResolver that will output a set of resolved,
* computed variables into aOutput.
*/
explicit CSSVariableResolver(CSSVariableValues* aOutput)
: mOutput(aOutput)
#ifdef DEBUG
, mResolved(false)
#endif
{
MOZ_ASSERT(aOutput);
}
/**
* Resolves the set of inherited variables from aInherited and the
* set of specified variables from aSpecified. The resolved variables
* are written into mOutput.
*/
void Resolve(const CSSVariableValues* aInherited,
const CSSVariableDeclarations* aSpecified);
private:
struct Variable
{
Variable(const nsAString& aVariableName,
nsString aValue,
nsCSSTokenSerializationType aFirstToken,
nsCSSTokenSerializationType aLastToken,
bool aWasInherited)
: mVariableName(aVariableName)
, mValue(aValue)
, mFirstToken(aFirstToken)
, mLastToken(aLastToken)
, mWasInherited(aWasInherited)
, mResolved(false)
, mReferencesNonExistentVariable(false)
, mInStack(false)
, mIndex(0)
, mLowLink(0) { }
nsString mVariableName;
nsString mValue;
nsCSSTokenSerializationType mFirstToken;
nsCSSTokenSerializationType mLastToken;
// Whether this variable came from the set of inherited variables.
bool mWasInherited;
// Whether this variable has been resolved yet.
bool mResolved;
// Whether this variables includes any references to non-existent variables.
bool mReferencesNonExistentVariable;
// Bookkeeping for the cycle remover algorithm.
bool mInStack;
size_t mIndex;
size_t mLowLink;
};
/**
* Adds or modifies an existing entry in the set of variables to be resolved.
* This is intended to be called by the AddVariablesToResolver functions on
* the CSSVariableDeclarations and CSSVariableValues objects passed in to
* Resolve.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name) whose value is to be set.
* @param aValue The variable value.
* @param aFirstToken The type of token at the start of the variable value.
* @param aLastToken The type of token at the en of the variable value.
* @param aWasInherited Whether this variable came from the set of inherited
* variables.
*/
void Put(const nsAString& aVariableName,
nsString aValue,
nsCSSTokenSerializationType aFirstToken,
nsCSSTokenSerializationType aLastToken,
bool aWasInherited);
// Helper functions for Resolve.
void RemoveCycles(size_t aID);
void ResolveVariable(size_t aID);
// A mapping of variable names to an ID that indexes into mVariables
// and mReferences.
nsDataHashtable<nsStringHashKey, size_t> mVariableIDs;
// The set of variables.
nsTArray<Variable> mVariables;
// The list of variables that each variable references.
nsTArray<nsTArray<size_t> > mReferences;
// The next index to assign to a variable found during the cycle removing
// algorithm's traversal of the variable reference graph.
size_t mNextIndex;
// Stack of variable IDs that we push to as we traverse the variable reference
// graph while looking for cycles. Variable::mInStack reflects whether a
// given variable has its ID in mStack.
nsTArray<size_t> mStack;
// CSS parser to use for parsing property values with variable references.
nsCSSParser mParser;
// The object to output the resolved variables into.
CSSVariableValues* mOutput;
#ifdef DEBUG
// Whether Resolve has been called.
bool mResolved;
#endif
};
} // namespace mozilla
#endif

Просмотреть файл

@ -1,148 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* computed CSS Variable values */
#include "CSSVariableValues.h"
#include "CSSVariableResolver.h"
namespace mozilla {
CSSVariableValues::CSSVariableValues()
{
MOZ_COUNT_CTOR(CSSVariableValues);
}
CSSVariableValues::CSSVariableValues(const CSSVariableValues& aOther)
{
MOZ_COUNT_CTOR(CSSVariableValues);
CopyVariablesFrom(aOther);
}
#ifdef DEBUG
CSSVariableValues::~CSSVariableValues()
{
MOZ_COUNT_DTOR(CSSVariableValues);
}
#endif
CSSVariableValues&
CSSVariableValues::operator=(const CSSVariableValues& aOther)
{
if (this == &aOther) {
return *this;
}
mVariableIDs.Clear();
mVariables.Clear();
CopyVariablesFrom(aOther);
return *this;
}
bool
CSSVariableValues::operator==(const CSSVariableValues& aOther) const
{
if (mVariables.Length() != aOther.mVariables.Length()) {
return false;
}
for (size_t thisIndex = 0; thisIndex < mVariables.Length(); ++thisIndex) {
size_t otherIndex;
if (!aOther.mVariableIDs.Get(mVariables[thisIndex].mVariableName,
&otherIndex)) {
return false;
}
const nsString& otherValue = aOther.mVariables[otherIndex].mValue;
if (!mVariables[thisIndex].mValue.Equals(otherValue)) {
return false;
}
}
return true;
}
size_t
CSSVariableValues::Count() const
{
return mVariables.Length();
}
bool
CSSVariableValues::Get(const nsAString& aName, nsString& aValue) const
{
size_t id;
if (!mVariableIDs.Get(aName, &id)) {
return false;
}
aValue = mVariables[id].mValue;
return true;
}
bool
CSSVariableValues::Get(const nsAString& aName,
nsString& aValue,
nsCSSTokenSerializationType& aFirstToken,
nsCSSTokenSerializationType& aLastToken) const
{
size_t id;
if (!mVariableIDs.Get(aName, &id)) {
return false;
}
aValue = mVariables[id].mValue;
aFirstToken = mVariables[id].mFirstToken;
aLastToken = mVariables[id].mLastToken;
return true;
}
void
CSSVariableValues::GetVariableAt(size_t aIndex, nsAString& aName) const
{
aName = mVariables[aIndex].mVariableName;
}
void
CSSVariableValues::Put(const nsAString& aName,
nsString aValue,
nsCSSTokenSerializationType aFirstToken,
nsCSSTokenSerializationType aLastToken)
{
size_t id;
if (mVariableIDs.Get(aName, &id)) {
mVariables[id].mValue = aValue;
mVariables[id].mFirstToken = aFirstToken;
mVariables[id].mLastToken = aLastToken;
} else {
id = mVariables.Length();
mVariableIDs.Put(aName, id);
mVariables.AppendElement(Variable(aName, aValue, aFirstToken, aLastToken));
}
}
void
CSSVariableValues::CopyVariablesFrom(const CSSVariableValues& aOther)
{
for (size_t i = 0, n = aOther.mVariables.Length(); i < n; i++) {
Put(aOther.mVariables[i].mVariableName,
aOther.mVariables[i].mValue,
aOther.mVariables[i].mFirstToken,
aOther.mVariables[i].mLastToken);
}
}
void
CSSVariableValues::AddVariablesToResolver(CSSVariableResolver* aResolver) const
{
for (size_t i = 0, n = mVariables.Length(); i < n; i++) {
aResolver->Put(mVariables[i].mVariableName,
mVariables[i].mValue,
mVariables[i].mFirstToken,
mVariables[i].mLastToken,
true);
}
}
} // namespace mozilla

Просмотреть файл

@ -1,148 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* computed CSS Variable values */
#ifndef mozilla_CSSVariableValues_h
#define mozilla_CSSVariableValues_h
#include "nsCSSScanner.h"
#include "nsDataHashtable.h"
#include "nsTArray.h"
namespace mozilla {
class CSSVariableResolver;
class CSSVariableValues
{
public:
CSSVariableValues();
CSSVariableValues(const CSSVariableValues& aOther);
#ifdef DEBUG
~CSSVariableValues();
#endif
CSSVariableValues& operator=(const CSSVariableValues& aOther);
bool operator==(const CSSVariableValues& aOther) const;
bool operator!=(const CSSVariableValues& aOther) const
{ return !(*this == aOther); }
/**
* Gets the value of a variable in this set of computed variables.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name).
* @param aValue Out parameter into which the value of the variable will
* be stored.
* @return Whether a variable with the given name was found. When false
* is returned, aValue will not be modified.
*/
bool Get(const nsAString& aName, nsString& aValue) const;
/**
* Gets the value of a variable in this set of computed variables, along
* with information on the types of tokens that appear at the start and
* end of the token stream.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name).
* @param aValue Out parameter into which the value of the variable will
* be stored.
* @param aFirstToken The type of token at the start of the variable value.
* @param aLastToken The type of token at the en of the variable value.
* @return Whether a variable with the given name was found. When false
* is returned, aValue, aFirstToken and aLastToken will not be modified.
*/
bool Get(const nsAString& aName,
nsString& aValue,
nsCSSTokenSerializationType& aFirstToken,
nsCSSTokenSerializationType& aLastToken) const;
/**
* Gets the name of the variable at the given index.
*
* Variables on this object are ordered, and that order is just determined
* based on the order that they are added to the object. A consistent
* ordering is required for CSSDeclaration objects in the DOM.
* CSSDeclarations expose property names as indexed properties, which need to
* be stable.
*
* @param aIndex The index of the variable to get.
* @param aName Out parameter into which the name of the variable will be
* stored.
*/
void GetVariableAt(size_t aIndex, nsAString& aName) const;
/**
* Gets the number of variables stored on this object.
*/
size_t Count() const;
/**
* Adds or modifies an existing entry in this set of variable values.
*
* @param aName The variable name (not including any "--" prefix that would
* be part of the custom property name) whose value is to be set.
* @param aValue The variable value.
* @param aFirstToken The type of token at the start of the variable value.
* @param aLastToken The type of token at the en of the variable value.
*/
void Put(const nsAString& aName,
nsString aValue,
nsCSSTokenSerializationType aFirstToken,
nsCSSTokenSerializationType aLastToken);
/**
* Copies the variables from this object into aResolver, marking them as
* computed, inherited values.
*/
void AddVariablesToResolver(CSSVariableResolver* aResolver) const;
private:
struct Variable
{
Variable()
: mFirstToken(eCSSTokenSerialization_Nothing)
, mLastToken(eCSSTokenSerialization_Nothing)
{}
Variable(const nsAString& aVariableName,
nsString aValue,
nsCSSTokenSerializationType aFirstToken,
nsCSSTokenSerializationType aLastToken)
: mVariableName(aVariableName)
, mValue(aValue)
, mFirstToken(aFirstToken)
, mLastToken(aLastToken)
{}
nsString mVariableName;
nsString mValue;
nsCSSTokenSerializationType mFirstToken;
nsCSSTokenSerializationType mLastToken;
};
/**
* Adds all the variables from aOther into this object.
*/
void CopyVariablesFrom(const CSSVariableValues& aOther);
/**
* Map of variable names to IDs. Variable IDs are indexes into
* mVariables.
*/
nsDataHashtable<nsStringHashKey, size_t> mVariableIDs;
/**
* Array of variables, indexed by variable ID.
*/
nsTArray<Variable> mVariables;
};
} // namespace mozilla
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,418 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* representation of a declaration block (or style attribute) in a CSS
* stylesheet
*/
#ifndef mozilla_css_Declaration_h
#define mozilla_css_Declaration_h
// This header is in EXPORTS because it's used in several places in content/,
// but it's not really a public interface.
#ifndef MOZILLA_INTERNAL_API
#error "This file should only be included within libxul"
#endif
#include "mozilla/Attributes.h"
#include "mozilla/DeclarationBlock.h"
#include "mozilla/MemoryReporting.h"
#include "CSSVariableDeclarations.h"
#include "nsCSSDataBlock.h"
#include "nsCSSPropertyID.h"
#include "nsCSSProps.h"
#include "nsIStyleRule.h"
#include "nsStringFwd.h"
#include "nsTArray.h"
#include <stdio.h>
// feec07b8-3fe6-491e-90d5-cc93f853e048
#define NS_CSS_DECLARATION_IMPL_CID \
{ 0xfeec07b8, 0x3fe6, 0x491e, \
{ 0x90, 0xd5, 0xcc, 0x93, 0xf8, 0x53, 0xe0, 0x48 } }
class nsHTMLCSSStyleSheet;
namespace mozilla {
namespace css {
class Rule;
class Declaration;
/**
* ImportantStyleData is the implementation of nsIStyleRule (a source of
* style data) representing the style data coming from !important rules;
* the !important declarations need a separate nsIStyleRule object since
* they fit at a different point in the cascade.
*
* ImportantStyleData is allocated only as part of a Declaration object.
*/
class ImportantStyleData final : public nsIStyleRule
{
public:
NS_DECL_ISUPPORTS
inline ::mozilla::css::Declaration* Declaration();
// nsIStyleRule interface
virtual void MapRuleInfoInto(nsRuleData* aRuleData) override;
virtual bool MightMapInheritedStyleData() override;
virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
nsCSSValue* aValue) override;
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
private:
ImportantStyleData() {}
~ImportantStyleData() {}
friend class ::mozilla::css::Declaration;
};
// Declaration objects have unusual lifetime rules. Every declaration
// begins life in an invalid state which ends when InitializeEmpty or
// CompressFrom is called upon it. After that, it can be attached to
// exactly one style rule, and will be destroyed when that style rule
// is destroyed. A declaration becomes immutable (via a SetImmutable
// call) when it is matched (put in the rule tree); after that, it must
// be copied before it can be modified, which is taken care of by
// |EnsureMutable|.
class Declaration final : public DeclarationBlock
, public nsIStyleRule
{
public:
/**
* Construct an |Declaration| that is in an invalid state (null
* |mData|) and cannot be used until its |CompressFrom| method or
* |InitializeEmpty| method is called.
*/
Declaration() : DeclarationBlock(StyleBackendType::Gecko) {}
Declaration(const Declaration& aCopy);
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_DECLARATION_IMPL_CID)
// If this ever becomes cycle-collected, please change the CC implementation
// for StyleRule to traverse it.
NS_DECL_ISUPPORTS
private:
~Declaration();
public:
// nsIStyleRule implementation
virtual void MapRuleInfoInto(nsRuleData *aRuleData) override;
virtual bool MightMapInheritedStyleData() override;
virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
nsCSSValue* aValue) override;
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
/**
* |ValueAppended| must be called to maintain this declaration's
* |mOrder| whenever a property is parsed into an expanded data block
* for this declaration. aProperty must not be a shorthand.
*/
void ValueAppended(nsCSSPropertyID aProperty);
void GetPropertyValue(const nsAString& aProperty, nsAString& aValue) const;
void GetPropertyValueByID(nsCSSPropertyID aPropID, nsAString& aValue) const;
bool GetPropertyIsImportant(const nsAString& aProperty) const;
// The two functions below returns whether there is any change to this
// declaration block, i.e. whether any property is actually removed.
bool RemoveProperty(const nsAString& aProperty);
bool RemovePropertyByID(nsCSSPropertyID aProperty);
bool HasProperty(nsCSSPropertyID aProperty) const;
bool HasImportantData() const {
return mImportantData || mImportantVariables;
}
/**
* Adds a custom property declaration to this object.
*
* @param aName The variable name (i.e., without the "--" prefix).
* @param aType The type of value the variable has.
* @param aValue The value of the variable, if aType is
* CSSVariableDeclarations::eTokenStream.
* @param aIsImportant Whether the declaration is !important.
* @param aOverrideImportant When aIsImportant is false, whether an
* existing !important declaration will be overridden.
*/
void AddVariable(const nsAString& aName,
CSSVariableDeclarations::Type aType,
const nsString& aValue,
bool aIsImportant,
bool aOverrideImportant);
/**
* Removes a custom property declaration from this object, and
* return whether the variable existed.
*
* @param aName The variable name (i.e., without the "--" prefix).
*/
bool RemoveVariable(const nsAString& aName);
/**
* Gets the string value for a custom property declaration of a variable
* with a given name.
*
* @param aName The variable name (i.e., without the "--" prefix).
* @param aValue Out parameter into which the variable's value will be
* stored. If the value is 'initial' or 'inherit', that exact string
* will be stored in aValue.
*/
void GetVariableValue(const nsAString& aName, nsAString& aValue) const;
/**
* Returns whether the custom property declaration for a variable with
* the given name was !important.
*/
bool GetVariableIsImportant(const nsAString& aName) const;
uint32_t Count() const {
return mOrder.Length();
}
// Returns whether we actually had a property at aIndex
bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const;
void ToString(nsAString& aString) const;
nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; }
nsCSSCompressedDataBlock* GetImportantBlock() const { return mImportantData; }
void AssertNotExpanded() const {
MOZ_ASSERT(mData, "should only be called when not expanded");
}
/**
* Initialize this declaration as holding no data. Cannot fail.
*/
void InitializeEmpty();
/**
* Transfer all of the state from |aExpandedData| into this declaration.
* After calling, |aExpandedData| should be in its initial state.
* Callers must make sure mOrder is updated as necessary.
*/
void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) {
MOZ_ASSERT(!mData, "oops");
MOZ_ASSERT(!mImportantData, "oops");
aExpandedData->Compress(getter_Transfers(mData),
getter_Transfers(mImportantData),
mOrder);
aExpandedData->AssertInitialState();
}
/**
* Transfer all of the state from this declaration into
* |aExpandedData| and put this declaration temporarily into an
* invalid state (ended by |CompressFrom| or |InitializeEmpty|) that
* should last only during parsing. During this time only
* |ValueAppended| should be called.
*/
void ExpandTo(nsCSSExpandedDataBlock *aExpandedData) {
AssertMutable();
aExpandedData->AssertInitialState();
MOZ_ASSERT(mData, "oops");
aExpandedData->Expand(mData.forget(), mImportantData.forget());
}
void MapImportantRuleInfoInto(nsRuleData *aRuleData) const {
AssertNotExpanded();
MOZ_ASSERT(mImportantData || mImportantVariables,
"must have important data or variables");
if (mImportantData) {
mImportantData->MapRuleInfoInto(aRuleData);
}
if (mImportantVariables) {
mImportantVariables->MapRuleInfoInto(aRuleData);
}
}
bool MapsImportantInheritedStyleData() const;
/**
* Attempt to replace the value for |aProperty| stored in this
* declaration with the matching value from |aFromBlock|.
* This method may only be called on a mutable declaration.
* It will fail (returning false) if |aProperty| is shorthand,
* is not already in this declaration, or does not have the indicated
* importance level. If it returns true, it erases the value in
* |aFromBlock|. |aChanged| is set to true if the declaration
* changed as a result of the call, and to false otherwise.
*/
bool TryReplaceValue(nsCSSPropertyID aProperty, bool aIsImportant,
nsCSSExpandedDataBlock& aFromBlock,
bool* aChanged)
{
AssertMutable();
AssertNotExpanded();
if (nsCSSProps::IsShorthand(aProperty)) {
*aChanged = false;
return false;
}
nsCSSCompressedDataBlock *block = aIsImportant ? mImportantData : mData;
// mImportantData might be null
if (!block) {
*aChanged = false;
return false;
}
#ifdef DEBUG
{
nsCSSCompressedDataBlock *other = aIsImportant ? mData : mImportantData;
MOZ_ASSERT(!other || !other->ValueFor(aProperty) ||
!block->ValueFor(aProperty),
"Property both important and not?");
}
#endif
return block->TryReplaceValue(aProperty, aFromBlock, aChanged);
}
bool HasNonImportantValueFor(nsCSSPropertyID aProperty) const {
MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty), "must be longhand");
return !!mData->ValueFor(aProperty);
}
/**
* Clear the data, in preparation for its replacement with entirely
* new data by a call to |CompressFrom|.
*/
void ClearData() {
AssertMutable();
mData = nullptr;
mImportantData = nullptr;
mVariables = nullptr;
mImportantVariables = nullptr;
mOrder.Clear();
mVariableOrder.Clear();
}
ImportantStyleData* GetImportantStyleData() {
if (HasImportantData()) {
return &mImportantStyleData;
}
return nullptr;
}
private:
Declaration& operator=(const Declaration& aCopy) = delete;
bool operator==(const Declaration& aCopy) const = delete;
void GetPropertyValueInternal(nsCSSPropertyID aProperty, nsAString& aValue,
bool* aIsTokenStream = nullptr) const;
bool GetPropertyIsImportantByID(nsCSSPropertyID aProperty) const;
static void AppendImportanceToString(bool aIsImportant, nsAString& aString);
// return whether there was a value in |aValue| (i.e., it had a non-null unit)
bool AppendValueToString(nsCSSPropertyID aProperty, nsAString& aResult,
bool* aIsTokenStream = nullptr) const;
// Helper for ToString with strange semantics regarding aValue.
void AppendPropertyAndValueToString(nsCSSPropertyID aProperty,
nsAString& aResult,
nsAutoString& aValue,
bool aValueIsTokenStream) const;
// helper for ToString that serializes a custom property declaration for
// a variable with the specified name
void AppendVariableAndValueToString(const nsAString& aName,
nsAString& aResult) const;
void GetImageLayerValue(nsCSSCompressedDataBlock *data,
nsAString& aValue,
const nsCSSPropertyID aTable[]) const;
void GetImageLayerPositionValue(nsCSSCompressedDataBlock *data,
nsAString& aValue,
const nsCSSPropertyID aTable[]) const;
public:
/**
* Returns the property at the given index in the ordered list of
* declarations. For custom properties, eCSSPropertyExtra_variable
* is returned.
*/
nsCSSPropertyID GetPropertyAt(uint32_t aIndex) const {
uint32_t value = mOrder[aIndex];
if (value >= eCSSProperty_COUNT) {
return eCSSPropertyExtra_variable;
}
return nsCSSPropertyID(value);
}
/**
* Gets the name of the custom property at the given index in the ordered
* list of declarations.
*/
void GetCustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const {
MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT);
uint32_t variableIndex = mOrder[aIndex] - eCSSProperty_COUNT;
aResult.Truncate();
aResult.AppendLiteral("--");
aResult.Append(mVariableOrder[variableIndex]);
}
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
private:
// The order of properties in this declaration. Longhand properties are
// represented by their nsCSSPropertyID value, and each custom property (--*)
// is represented by a value that begins at eCSSProperty_COUNT.
//
// Subtracting eCSSProperty_COUNT from those values that represent custom
// properties results in an index into mVariableOrder, which identifies the
// specific variable the custom property declaration is for.
AutoTArray<uint32_t, 8> mOrder;
// variable names of custom properties found in mOrder
nsTArray<nsString> mVariableOrder;
// never null, except while expanded, or before the first call to
// InitializeEmpty or CompressFrom.
nsAutoPtr<nsCSSCompressedDataBlock> mData;
// may be null
nsAutoPtr<nsCSSCompressedDataBlock> mImportantData;
// may be null
nsAutoPtr<CSSVariableDeclarations> mVariables;
// may be null
nsAutoPtr<CSSVariableDeclarations> mImportantVariables;
friend class ImportantStyleData;
ImportantStyleData mImportantStyleData;
};
inline ::mozilla::css::Declaration*
ImportantStyleData::Declaration()
{
union {
char* ch; /* for pointer arithmetic */
::mozilla::css::Declaration* declaration;
ImportantStyleData* importantData;
} u;
u.importantData = this;
u.ch -= offsetof(::mozilla::css::Declaration, mImportantStyleData);
return u.declaration;
}
NS_DEFINE_STATIC_IID_ACCESSOR(Declaration, NS_CSS_DECLARATION_IMPL_CID)
} // namespace css
} // namespace mozilla
#endif /* mozilla_css_Declaration_h */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,313 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_GeckoStyleContext_h
#define mozilla_GeckoStyleContext_h
#include "nsStyleContext.h"
namespace mozilla {
class GeckoStyleContext final : public nsStyleContext {
public:
static inline already_AddRefed<GeckoStyleContext>
TakeRef(already_AddRefed<nsStyleContext> aStyleContext);
GeckoStyleContext(GeckoStyleContext* aParent,
nsAtom* aPseudoTag,
CSSPseudoElementType aPseudoType,
already_AddRefed<nsRuleNode> aRuleNode,
bool aSkipParentDisplayBasedStyleFixup);
void* operator new(size_t sz, nsPresContext* aPresContext);
nsPresContext* PresContext() const {
return RuleNode()->PresContext();
}
void AddChild(GeckoStyleContext* aChild);
void RemoveChild(GeckoStyleContext* aChild);
GeckoStyleContext* GetParent() const { return mParent; }
bool IsLinkContext() const {
return GetStyleIfVisited() &&
GetStyleIfVisited()->GetParent() == GetParent();
}
/**
* Moves this style context to a new parent.
*
* This function violates style context tree immutability, and
* is a very low-level function and should only be used after verifying
* many conditions that make it safe to call.
*/
void MoveTo(GeckoStyleContext* aNewParent);
void* GetUniqueStyleData(const nsStyleStructID& aSID);
void* CreateEmptyStyleData(const nsStyleStructID& aSID);
// To be called only from nsStyleSet / ServoStyleSet.
void SetStyleIfVisited(already_AddRefed<GeckoStyleContext> aStyleIfVisited);
GeckoStyleContext* GetStyleIfVisited() const { return mStyleIfVisited; };
#ifdef DEBUG
/**
* Initializes a cached pref, which is only used in DEBUG code.
*/
static void Initialize();
#endif
/**
* Ensures the same structs are cached on this style context as would be
* done if we called aOther->CalcDifference(this).
*/
void EnsureSameStructsCached(nsStyleContext* aOldContext);
/**
* Sets the NS_STYLE_INELIGIBLE_FOR_SHARING bit on this style context
* and its descendants. If it finds a descendant that has the bit
* already set, assumes that it can skip that subtree.
*/
void SetIneligibleForSharing();
/**
* On each descendant of this style context, clears out any cached inherited
* structs indicated in aStructs.
*/
void ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
// Find, if it already exists *and is easily findable* (i.e., near the
// start of the child list), a style context whose:
// * GetPseudo() matches aPseudoTag
// * mRuleNode matches aSource
// * !!GetStyleIfVisited() == !!aSourceIfVisited, and, if they're
// non-null, GetStyleIfVisited()->mRuleNode == aSourceIfVisited
// * RelevantLinkVisited() == aRelevantLinkVisited
already_AddRefed<GeckoStyleContext>
FindChildWithRules(const nsAtom* aPseudoTag,
nsRuleNode* aSource,
nsRuleNode* aSourceIfVisited,
bool aRelevantLinkVisited);
// Tell this style context to cache aStruct as the struct for aSID
void SetStyle(nsStyleStructID aSID, void* aStruct);
/*
* Get the style data for a style struct. This is the most important
* member function of nsStyleContext. It fills in a const pointer
* to a style data struct that is appropriate for the style context's
* frame. This struct may be shared with other contexts (either in
* the rule tree or the style context tree), so it should not be
* modified.
*
* This function will NOT return null (even when out of memory) when
* given a valid style struct ID, so the result does not need to be
* null-checked.
*
* The typesafe functions below are preferred to the use of this
* function, both because they're easier to read and because they're
* faster.
*/
const void* NS_FASTCALL StyleData(nsStyleStructID aSID) MOZ_NONNULL_RETURN;
#ifdef DEBUG
void ListDescendants(FILE* out, int32_t aIndent);
#endif
#ifdef RESTYLE_LOGGING
// This only gets called under call trees where we've already checked
// that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
// It exists here just to satisfy LOG_RESTYLE's expectations.
bool ShouldLogRestyle() { return true; }
void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
void LogStyleContextTree(bool aFirst, uint32_t aStructs);
int32_t& LoggingDepth();
nsCString GetCachedStyleDataAsString(uint32_t aStructs);
#endif
// Only called for Gecko-backed nsStyleContexts.
void ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup);
bool HasNoChildren() const;
nsRuleNode* RuleNode() const {
MOZ_ASSERT(mRuleNode);
return mRuleNode;
}
bool HasSingleReference() const {
NS_ASSERTION(mRefCnt != 0,
"do not call HasSingleReference on a newly created "
"nsStyleContext with no references yet");
return mRefCnt == 1;
}
void AddRef() {
if (mRefCnt == UINT32_MAX) {
NS_WARNING("refcount overflow, leaking object");
return;
}
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
return;
}
void Release() {
if (mRefCnt == UINT32_MAX) {
NS_WARNING("refcount overflow, leaking object");
return;
}
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
if (mRefCnt == 0) {
Destroy();
return;
}
return;
}
~GeckoStyleContext();
/**
* Swaps owned style struct pointers between this and aNewContext, on
* the assumption that aNewContext is the new style context for a frame
* and this is the old one. aStructs indicates which structs to consider
* swapping; only those which are owned in both this and aNewContext
* will be swapped.
*
* Additionally, if there are identical struct pointers for one of the
* structs indicated by aStructs, and it is not an owned struct on this,
* then the cached struct slot on this will be set to null. If the struct
* has been swapped on an ancestor, this style context (being the old one)
* will be left caching the struct pointer on the new ancestor, despite
* inheriting from the old ancestor. This is not normally a problem, as
* this style context will usually be destroyed by being released at the
* end of ElementRestyler::Restyle; but for style contexts held on to outside
* of the frame, we need to clear out the cached pointer so that if we need
* it again we'll re-fetch it from the new ancestor.
*/
void SwapStyleData(GeckoStyleContext* aNewContext, uint32_t aStructs);
void DestroyCachedStructs(nsPresContext* aPresContext);
/**
* Return style data that is currently cached on the style context.
* Only returns the structs we cache ourselves; never consults the
* rule tree.
*
* For "internal" use only in nsStyleContext and nsRuleNode.
*/
const void* GetCachedStyleData(nsStyleStructID aSID)
{
const void* cachedData;
if (nsCachedStyleData::IsReset(aSID)) {
if (mCachedResetData) {
cachedData = mCachedResetData->mStyleStructs[aSID];
} else {
cachedData = nullptr;
}
} else {
cachedData = mCachedInheritedData.mStyleStructs[aSID];
}
return cachedData;
}
// mCachedInheritedData and mCachedResetData point to both structs that
// are owned by this style context and structs that are owned by one of
// this style context's ancestors (which are indirectly owned since this
// style context owns a reference to its parent). If the bit in |mBits|
// is set for a struct, that means that the pointer for that struct is
// owned by an ancestor or by the rule node rather than by this style context.
// Since style contexts typically have some inherited data but only sometimes
// have reset data, we always allocate the mCachedInheritedData, but only
// sometimes allocate the mCachedResetData.
nsResetStyleData* mCachedResetData; // Cached reset style data.
nsInheritedStyleData mCachedInheritedData; // Cached inherited style data
uint32_t mRefCnt;
#ifdef DEBUG
void AssertStructsNotUsedElsewhere(GeckoStyleContext* aDestroyingContext,
int32_t aLevels) const;
#endif
private:
// Helper for ClearCachedInheritedStyleDataOnDescendants.
void DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
void Destroy();
void SetStyleBits();
void FinishConstruction();
// Children are kept in two circularly-linked lists. The list anchor
// is not part of the list (null for empty), and we point to the first
// child.
// mEmptyChild for children whose rule node is the root rule node, and
// mChild for other children. The order of children is not
// meaningful.
GeckoStyleContext* mChild;
GeckoStyleContext* mEmptyChild;
GeckoStyleContext* mPrevSibling;
GeckoStyleContext* mNextSibling;
RefPtr<nsRuleNode> mRuleNode;
RefPtr<GeckoStyleContext> mParent;
// Style to be used instead for the R, G, and B components of color,
// background-color, and border-*-color if the nearest ancestor link
// element is visited (see RelevantLinkVisited()).
RefPtr<GeckoStyleContext> mStyleIfVisited;
#ifdef DEBUG
public:
struct AutoCheckDependency {
GeckoStyleContext* mStyleContext;
nsStyleStructID mOuterSID;
AutoCheckDependency(GeckoStyleContext* aContext, nsStyleStructID aInnerSID)
: mStyleContext(aContext)
{
mOuterSID = aContext->mComputingStruct;
MOZ_ASSERT(mOuterSID == nsStyleStructID_None ||
DependencyAllowed(mOuterSID, aInnerSID),
"Undeclared dependency, see generate-stylestructlist.py");
aContext->mComputingStruct = aInnerSID;
}
~AutoCheckDependency()
{
mStyleContext->mComputingStruct = mOuterSID;
}
};
void FrameAddRef() {
++mFrameRefCnt;
}
void FrameRelease() {
--mFrameRefCnt;
}
uint32_t FrameRefCnt() const {
return mFrameRefCnt;
}
private:
// Used to check for undeclared dependencies.
// See AUTO_CHECK_DEPENDENCY in nsStyleContextInlines.h.
nsStyleStructID mComputingStruct;
uint32_t mFrameRefCnt; // number of frames that use this
// as their style context
#define AUTO_CHECK_DEPENDENCY(gecko_, sid_) \
mozilla::GeckoStyleContext::AutoCheckDependency checkNesting_(gecko_, sid_)
#else
#define AUTO_CHECK_DEPENDENCY(gecko_, sid_)
#endif
};
}
#endif // mozilla_GeckoStyleContext_h

Просмотреть файл

@ -1,70 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* class for CSS @import rules */
#ifndef mozilla_css_ImportRule_h__
#define mozilla_css_ImportRule_h__
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/CSSImportRule.h"
#include "nsStringFwd.h"
class nsMediaList;
namespace mozilla {
class CSSStyleSheet;
class StyleSheet;
namespace dom {
class MediaList;
}
namespace css {
class ImportRule final : public dom::CSSImportRule
{
public:
ImportRule(nsMediaList* aMedia, const nsString& aURLSpec,
uint32_t aLineNumber, uint32_t aColumnNumber);
private:
// for |Clone|
ImportRule(const ImportRule& aCopy);
~ImportRule();
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ImportRule, Rule)
// Rule methods
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
virtual already_AddRefed<Rule> Clone() const override;
void SetSheet(CSSStyleSheet*);
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
// WebIDL interface
void GetCssText(nsAString& aCssText) const override;
void GetHref(nsAString& aHref) const final;
dom::MediaList* GetMedia() const final;
StyleSheet* GetStyleSheet() const final;
private:
nsString mURLSpec;
RefPtr<nsMediaList> mMedia;
RefPtr<CSSStyleSheet> mChildSheet;
};
} // namespace css
} // namespace mozilla
#endif /* mozilla_css_ImportRule_h__ */

Просмотреть файл

@ -1,81 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
#include "mozilla/IncrementalClearCOMRuleArray.h"
#include <algorithm> // For std::min
#include "nsCycleCollector.h"
#include "mozilla/DeferredFinalize.h"
#include "nsTArray.h"
#include "nsCCUncollectableMarker.h"
using namespace mozilla;
typedef nsCOMArray<css::Rule> RuleArray;
typedef nsTArray<RuleArray> RuleArrayArray;
// These methods are based on those in DeferredFinalizerImpl.
static void*
AppendRulesArrayPointer(void* aData, void* aObject)
{
RuleArrayArray* rulesArray = static_cast<RuleArrayArray*>(aData);
RuleArray* oldRules = static_cast<RuleArray*>(aObject);
if (!rulesArray) {
rulesArray = new RuleArrayArray();
}
RuleArray* newRules = rulesArray->AppendElement();
newRules->SwapElements(*oldRules);
return rulesArray;
}
// Remove up to |aSliceBudget| css::Rules from the arrays, starting at
// the end of the last array.
static bool
DeferredFinalizeRulesArray(uint32_t aSliceBudget, void* aData)
{
MOZ_ASSERT(aSliceBudget > 0, "nonsensical/useless call with aSliceBudget == 0");
RuleArrayArray* rulesArray = static_cast<RuleArrayArray*>(aData);
size_t newOuterLen = rulesArray->Length();
while (aSliceBudget > 0 && newOuterLen > 0) {
RuleArray& lastArray = rulesArray->ElementAt(newOuterLen - 1);
uint32_t innerLen = lastArray.Length();
uint32_t currSlice = std::min(innerLen, aSliceBudget);
uint32_t newInnerLen = innerLen - currSlice;
lastArray.TruncateLength(newInnerLen);
aSliceBudget -= currSlice;
if (newInnerLen == 0) {
newOuterLen -= 1;
}
}
rulesArray->TruncateLength(newOuterLen);
if (newOuterLen == 0) {
delete rulesArray;
return true;
}
return false;
}
void
IncrementalClearCOMRuleArray::Clear()
{
// Destroy the array incrementally if it is long and we
// haven't started shutting down.
if (Length() > 10 && nsCCUncollectableMarker::sGeneration) {
DeferredFinalize(AppendRulesArrayPointer, DeferredFinalizeRulesArray, this);
} else {
nsCOMArray<css::Rule>::Clear();
}
MOZ_ASSERT(Length() == 0);
}

Просмотреть файл

@ -1,28 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_IncrementalClearCOMRuleArray_h
#define mozilla_IncrementalClearCOMRuleArray_h
#include "nsCOMArray.h"
namespace mozilla {
namespace css {
class Rule;
} // namespace css
class IncrementalClearCOMRuleArray : public nsCOMArray<css::Rule>
{
public:
IncrementalClearCOMRuleArray() {}
~IncrementalClearCOMRuleArray() { Clear(); }
void Clear();
};
} // namespace mozilla
#endif /* !defined(mozilla_IncrementalClearCOMRuleArray_h) */

Просмотреть файл

@ -1,63 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/* class for CSS @namespace rules */
#ifndef mozilla_css_NameSpaceRule_h__
#define mozilla_css_NameSpaceRule_h__
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/CSSNamespaceRule.h"
class nsAtom;
// IID for the NameSpaceRule class {f0b0dbe1-5031-4a21-b06a-dc141ef2af98}
#define NS_CSS_NAMESPACE_RULE_IMPL_CID \
{0xf0b0dbe1, 0x5031, 0x4a21, {0xb0, 0x6a, 0xdc, 0x14, 0x1e, 0xf2, 0xaf, 0x98}}
namespace mozilla {
namespace css {
class NameSpaceRule final : public dom::CSSNamespaceRule
{
public:
NameSpaceRule(nsAtom* aPrefix, const nsString& aURLSpec,
uint32_t aLineNumber, uint32_t aColumnNumber);
private:
// for |Clone|
NameSpaceRule(const NameSpaceRule& aCopy);
~NameSpaceRule();
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_NAMESPACE_RULE_IMPL_CID)
NS_DECL_ISUPPORTS_INHERITED
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
virtual already_AddRefed<Rule> Clone() const override;
nsAtom* GetPrefix() const final { return mPrefix; }
void GetURLSpec(nsString& aURLSpec) const final { aURLSpec = mURLSpec; }
// WebIDL interface
void GetCssText(nsAString& aCssText) const override;
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const final;
private:
RefPtr<nsAtom> mPrefix;
nsString mURLSpec;
};
NS_DEFINE_STATIC_IID_ACCESSOR(NameSpaceRule, NS_CSS_NAMESPACE_RULE_IMPL_CID)
} // namespace css
} // namespace mozilla
#endif /* mozilla_css_NameSpaceRule_h__ */

Просмотреть файл

@ -1,53 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* an object that stores the result of determining whether a style struct that
* was computed can be cached in the rule tree, and if so, what the cache
* key is
*/
#include "RuleNodeCacheConditions.h"
#include "nsStyleContext.h"
#include "WritingModes.h"
using namespace mozilla;
bool
RuleNodeCacheConditions::Matches(nsStyleContext* aStyleContext) const
{
MOZ_ASSERT(Cacheable());
if ((mBits & eHaveFontSize) &&
mFontSize != aStyleContext->StyleFont()->mFont.size) {
return false;
}
if ((mBits & eHaveWritingMode) &&
(mWritingMode != WritingMode(aStyleContext).GetBits())) {
return false;
}
return true;
}
#ifdef DEBUG
void
RuleNodeCacheConditions::List() const
{
printf("{ ");
bool first = true;
if (mBits & eHaveFontSize) {
printf("FontSize(%d)", mFontSize);
first = false;
}
if (mBits & eHaveWritingMode) {
if (!first) {
printf(", ");
}
printf("WritingMode(0x%x)", mWritingMode);
}
printf(" }");
}
#endif

Просмотреть файл

@ -1,287 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* cache of re-usable nsCSSRuleProcessors for given sets of style sheets
*/
#include "RuleProcessorCache.h"
#include <algorithm>
#include "mozilla/CSSStyleSheet.h"
#include "nsCSSRuleProcessor.h"
#include "nsThreadUtils.h"
using namespace mozilla;
NS_IMPL_ISUPPORTS(RuleProcessorCache, nsIMemoryReporter)
MOZ_DEFINE_MALLOC_SIZE_OF(RuleProcessorCacheMallocSizeOf)
NS_IMETHODIMP
RuleProcessorCache::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize)
{
MOZ_COLLECT_REPORT(
"explicit/layout/rule-processor-cache", KIND_HEAP, UNITS_BYTES,
SizeOfIncludingThis(RuleProcessorCacheMallocSizeOf),
"Memory used for cached rule processors.");
return NS_OK;
}
RuleProcessorCache::~RuleProcessorCache()
{
UnregisterWeakMemoryReporter(this);
for (Entry& e : mEntries) {
for (DocumentEntry& de : e.mDocumentEntries) {
if (de.mRuleProcessor->GetExpirationState()->IsTracked()) {
mExpirationTracker.RemoveObject(de.mRuleProcessor);
}
de.mRuleProcessor->SetInRuleProcessorCache(false);
}
}
}
void
RuleProcessorCache::InitMemoryReporter()
{
RegisterWeakMemoryReporter(this);
}
/* static */ bool
RuleProcessorCache::EnsureGlobal()
{
MOZ_ASSERT(NS_IsMainThread());
if (gShutdown) {
return false;
}
if (!gRuleProcessorCache) {
gRuleProcessorCache = new RuleProcessorCache;
gRuleProcessorCache->InitMemoryReporter();
}
return true;
}
/* static */ void
RuleProcessorCache::RemoveSheet(CSSStyleSheet* aSheet)
{
if (!EnsureGlobal()) {
return;
}
gRuleProcessorCache->DoRemoveSheet(aSheet);
}
#ifdef DEBUG
/* static */ bool
RuleProcessorCache::HasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
{
if (!EnsureGlobal()) {
return false;
}
return gRuleProcessorCache->DoHasRuleProcessor(aRuleProcessor);
}
#endif
/* static */ void
RuleProcessorCache::RemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
{
if (!EnsureGlobal()) {
return;
}
gRuleProcessorCache->DoRemoveRuleProcessor(aRuleProcessor);
}
/* static */ nsCSSRuleProcessor*
RuleProcessorCache::GetRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
nsPresContext* aPresContext)
{
if (!EnsureGlobal()) {
return nullptr;
}
return gRuleProcessorCache->DoGetRuleProcessor(aSheets, aPresContext);
}
/* static */ void
RuleProcessorCache::PutRuleProcessor(
const nsTArray<CSSStyleSheet*>& aSheets,
nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
const nsDocumentRuleResultCacheKey& aCacheKey,
nsCSSRuleProcessor* aRuleProcessor)
{
if (!EnsureGlobal()) {
return;
}
gRuleProcessorCache->DoPutRuleProcessor(aSheets, Move(aDocumentRulesInSheets),
aCacheKey, aRuleProcessor);
}
/* static */ void
RuleProcessorCache::StartTracking(nsCSSRuleProcessor* aRuleProcessor)
{
if (!EnsureGlobal()) {
return;
}
return gRuleProcessorCache->DoStartTracking(aRuleProcessor);
}
/* static */ void
RuleProcessorCache::StopTracking(nsCSSRuleProcessor* aRuleProcessor)
{
if (!EnsureGlobal()) {
return;
}
return gRuleProcessorCache->DoStopTracking(aRuleProcessor);
}
void
RuleProcessorCache::DoRemoveSheet(CSSStyleSheet* aSheet)
{
auto last = std::remove_if(mEntries.begin(), mEntries.end(),
HasSheet_ThenRemoveRuleProcessors(this, aSheet));
mEntries.TruncateLength(last - mEntries.begin());
}
nsCSSRuleProcessor*
RuleProcessorCache::DoGetRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
nsPresContext* aPresContext)
{
for (Entry& e : mEntries) {
if (e.mSheets == aSheets) {
for (DocumentEntry& de : e.mDocumentEntries) {
if (de.mCacheKey.Matches(aPresContext, e.mDocumentRulesInSheets)) {
return de.mRuleProcessor;
}
}
// Entry::mSheets is unique; if we matched aSheets but didn't
// find a matching DocumentEntry, we won't find one later in
// mEntries.
return nullptr;
}
}
return nullptr;
}
void
RuleProcessorCache::DoPutRuleProcessor(
const nsTArray<CSSStyleSheet*>& aSheets,
nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
const nsDocumentRuleResultCacheKey& aCacheKey,
nsCSSRuleProcessor* aRuleProcessor)
{
MOZ_ASSERT(!aRuleProcessor->IsInRuleProcessorCache());
Entry* entry = nullptr;
for (Entry& e : mEntries) {
if (e.mSheets == aSheets) {
entry = &e;
break;
}
}
if (!entry) {
entry = mEntries.AppendElement();
entry->mSheets = aSheets;
entry->mDocumentRulesInSheets = aDocumentRulesInSheets;
for (CSSStyleSheet* sheet : aSheets) {
sheet->SetInRuleProcessorCache();
}
} else {
MOZ_ASSERT(entry->mDocumentRulesInSheets == aDocumentRulesInSheets,
"DocumentRule array shouldn't have changed");
}
#ifdef DEBUG
for (DocumentEntry& de : entry->mDocumentEntries) {
MOZ_ASSERT(de.mCacheKey != aCacheKey,
"should not have duplicate document cache keys");
}
#endif
DocumentEntry* documentEntry = entry->mDocumentEntries.AppendElement();
documentEntry->mCacheKey = aCacheKey;
documentEntry->mRuleProcessor = aRuleProcessor;
aRuleProcessor->SetInRuleProcessorCache(true);
}
#ifdef DEBUG
bool
RuleProcessorCache::DoHasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
{
for (Entry& e : mEntries) {
for (DocumentEntry& de : e.mDocumentEntries) {
if (de.mRuleProcessor == aRuleProcessor) {
return true;
}
}
}
return false;
}
#endif
void
RuleProcessorCache::DoRemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
{
MOZ_ASSERT(aRuleProcessor->IsInRuleProcessorCache());
aRuleProcessor->SetInRuleProcessorCache(false);
mExpirationTracker.RemoveObjectIfTracked(aRuleProcessor);
for (Entry& e : mEntries) {
for (size_t i = 0; i < e.mDocumentEntries.Length(); i++) {
if (e.mDocumentEntries[i].mRuleProcessor == aRuleProcessor) {
e.mDocumentEntries.RemoveElementAt(i);
return;
}
}
}
MOZ_ASSERT_UNREACHABLE("should have found rule processor");
}
void
RuleProcessorCache::DoStartTracking(nsCSSRuleProcessor* aRuleProcessor)
{
mExpirationTracker.AddObject(aRuleProcessor);
}
void
RuleProcessorCache::DoStopTracking(nsCSSRuleProcessor* aRuleProcessor)
{
mExpirationTracker.RemoveObjectIfTracked(aRuleProcessor);
}
size_t
RuleProcessorCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
{
size_t n = aMallocSizeOf(this);
int count = 0;
n += mEntries.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (Entry& e : mEntries) {
n += e.mDocumentEntries.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (DocumentEntry& de : e.mDocumentEntries) {
count++;
n += de.mRuleProcessor->SizeOfIncludingThis(aMallocSizeOf);
}
}
return n;
}
void
RuleProcessorCache::ExpirationTracker::RemoveObjectIfTracked(
nsCSSRuleProcessor* aRuleProcessor)
{
if (aRuleProcessor->GetExpirationState()->IsTracked()) {
RemoveObject(aRuleProcessor);
}
}
bool RuleProcessorCache::gShutdown = false;
mozilla::StaticRefPtr<RuleProcessorCache> RuleProcessorCache::gRuleProcessorCache;

Просмотреть файл

@ -1,148 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* cache of re-usable nsCSSRuleProcessors for given sets of style sheets
*/
#ifndef mozilla_RuleProcessorCache_h
#define mozilla_RuleProcessorCache_h
#include "mozilla/MemoryReporting.h"
#include "mozilla/StaticPtr.h"
#include "nsCSSRuleProcessor.h"
#include "nsExpirationTracker.h"
#include "nsMediaList.h"
#include "nsIMemoryReporter.h"
#include "nsTArray.h"
class nsCSSRuleProcessor;
namespace mozilla {
class CSSStyleSheet;
namespace css {
class DocumentRule;
} // namespace css
} // namespace mozilla
namespace mozilla {
/**
* The RuleProcessorCache is a singleton object that caches
* nsCSSRuleProcessors keyed off a list of style sheets and the result of
* evaluating all @-moz-documents in the style sheets. nsStyleSet gets and
* puts nsCSSRuleProcessors from/to the RuleProcessorCache.
*
* State bits on CSSStyleSheet and nsCSSRuleProcessor track whether they are in
* the RuleProcessorCache. This lets us remove them from the RuleProcessorCache
* when they're going away.
*/
class RuleProcessorCache final : public nsIMemoryReporter
{
NS_DECL_ISUPPORTS
NS_DECL_NSIMEMORYREPORTER
public:
static nsCSSRuleProcessor* GetRuleProcessor(
const nsTArray<CSSStyleSheet*>& aSheets,
nsPresContext* aPresContext);
static void PutRuleProcessor(
const nsTArray<CSSStyleSheet*>& aSheets,
nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
const nsDocumentRuleResultCacheKey& aCacheKey,
nsCSSRuleProcessor* aRuleProcessor);
static void StartTracking(nsCSSRuleProcessor* aRuleProcessor);
static void StopTracking(nsCSSRuleProcessor* aRuleProcessor);
#ifdef DEBUG
static bool HasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
#endif
static void RemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
static void RemoveSheet(CSSStyleSheet* aSheet);
static void Shutdown() { gShutdown = true; gRuleProcessorCache = nullptr; }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
private:
class ExpirationTracker : public nsExpirationTracker<nsCSSRuleProcessor,3>
{
public:
explicit ExpirationTracker(RuleProcessorCache* aCache)
: nsExpirationTracker<nsCSSRuleProcessor,3>(
10000, "RuleProcessorCache::ExpirationTracker",
SystemGroup::EventTargetFor(TaskCategory::Other))
{}
void RemoveObjectIfTracked(nsCSSRuleProcessor* aRuleProcessor);
virtual void NotifyExpired(nsCSSRuleProcessor* aRuleProcessor) override {
mozilla::RuleProcessorCache::RemoveRuleProcessor(aRuleProcessor);
}
};
RuleProcessorCache() : mExpirationTracker(this) {}
~RuleProcessorCache();
void InitMemoryReporter();
static bool EnsureGlobal();
static StaticRefPtr<RuleProcessorCache> gRuleProcessorCache;
static bool gShutdown;
void DoRemoveSheet(CSSStyleSheet* aSheet);
nsCSSRuleProcessor* DoGetRuleProcessor(
const nsTArray<CSSStyleSheet*>& aSheets,
nsPresContext* aPresContext);
void DoPutRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
const nsDocumentRuleResultCacheKey& aCacheKey,
nsCSSRuleProcessor* aRuleProcessor);
#ifdef DEBUG
bool DoHasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
#endif
void DoRemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
void DoStartTracking(nsCSSRuleProcessor* aRuleProcessor);
void DoStopTracking(nsCSSRuleProcessor* aRuleProcessor);
struct DocumentEntry {
nsDocumentRuleResultCacheKey mCacheKey;
RefPtr<nsCSSRuleProcessor> mRuleProcessor;
};
struct Entry {
nsTArray<CSSStyleSheet*> mSheets;
nsTArray<css::DocumentRule*> mDocumentRulesInSheets;
nsTArray<DocumentEntry> mDocumentEntries;
};
// Function object to test whether an Entry object has a given sheet
// in its mSheets array. If it does, removes all of its rule processors
// before returning true.
struct HasSheet_ThenRemoveRuleProcessors {
HasSheet_ThenRemoveRuleProcessors(RuleProcessorCache* aCache,
CSSStyleSheet* aSheet)
: mCache(aCache), mSheet(aSheet) {}
bool operator()(Entry& aEntry) {
if (aEntry.mSheets.Contains(mSheet)) {
for (DocumentEntry& de : aEntry.mDocumentEntries) {
de.mRuleProcessor->SetInRuleProcessorCache(false);
mCache->mExpirationTracker.RemoveObjectIfTracked(de.mRuleProcessor);
}
return true;
}
return false;
}
RuleProcessorCache* mCache;
CSSStyleSheet* mSheet;
};
ExpirationTracker mExpirationTracker;
nsTArray<Entry> mEntries;
};
} // namespace mozilla
#endif // mozilla_RuleProcessorCache_h

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,397 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* representation of CSS style rules (selectors+declaration) and CSS
* selectors
*/
#ifndef mozilla_css_StyleRule_h__
#define mozilla_css_StyleRule_h__
#include "mozilla/Attributes.h"
#include "mozilla/BindingStyleRule.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/StyleSetHandle.h"
#include "mozilla/UniquePtr.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsCSSPseudoElements.h"
#include "nsIStyleRule.h"
class nsAtom;
struct nsCSSSelectorList;
namespace mozilla {
enum class CSSPseudoClassType : uint8_t;
class CSSStyleSheet;
} // namespace mozilla
struct nsAtomList {
public:
explicit nsAtomList(nsAtom* aAtom);
explicit nsAtomList(const nsString& aAtomValue);
~nsAtomList(void);
/** Do a deep clone. Should be used only on the first in the linked list. */
nsAtomList* Clone() const { return Clone(true); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
RefPtr<nsAtom> mAtom;
nsAtomList* mNext;
private:
nsAtomList* Clone(bool aDeep) const;
nsAtomList(const nsAtomList& aCopy) = delete;
nsAtomList& operator=(const nsAtomList& aCopy) = delete;
};
struct nsPseudoClassList {
public:
typedef mozilla::CSSPseudoClassType CSSPseudoClassType;
explicit nsPseudoClassList(CSSPseudoClassType aType);
nsPseudoClassList(CSSPseudoClassType aType, const char16_t *aString);
nsPseudoClassList(CSSPseudoClassType aType, const int32_t *aIntPair);
nsPseudoClassList(CSSPseudoClassType aType,
nsCSSSelectorList *aSelectorList /* takes ownership */);
~nsPseudoClassList(void);
/** Do a deep clone. Should be used only on the first in the linked list. */
nsPseudoClassList* Clone() const { return Clone(true); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
union {
// For a given value of mType, we have either:
// a. no value, which means mMemory is always null
// (if none of the conditions for (b), (c), or (d) is true)
// b. a string value, which means mString/mMemory is non-null
// (if nsCSSPseudoClasses::HasStringArg(mType))
// c. an integer pair value, which means mNumbers/mMemory is non-null
// (if nsCSSPseudoClasses::HasNthPairArg(mType))
// d. a selector list, which means mSelectors is non-null
// (if nsCSSPseudoClasses::HasSelectorListArg(mType))
void* mMemory; // mString and mNumbers use moz_xmalloc/free
char16_t* mString;
int32_t* mNumbers;
nsCSSSelectorList* mSelectors;
} u;
CSSPseudoClassType mType;
nsPseudoClassList* mNext;
private:
nsPseudoClassList* Clone(bool aDeep) const;
nsPseudoClassList(const nsPseudoClassList& aCopy) = delete;
nsPseudoClassList& operator=(const nsPseudoClassList& aCopy) = delete;
};
#define NS_ATTR_FUNC_SET 0 // [attr]
#define NS_ATTR_FUNC_EQUALS 1 // [attr=value]
#define NS_ATTR_FUNC_INCLUDES 2 // [attr~=value] (space separated)
#define NS_ATTR_FUNC_DASHMATCH 3 // [attr|=value] ('-' truncated)
#define NS_ATTR_FUNC_BEGINSMATCH 4 // [attr^=value] (begins with)
#define NS_ATTR_FUNC_ENDSMATCH 5 // [attr$=value] (ends with)
#define NS_ATTR_FUNC_CONTAINSMATCH 6 // [attr*=value] (contains substring)
struct nsAttrSelector {
public:
enum class ValueCaseSensitivity : uint8_t {
CaseSensitive,
CaseInsensitive,
CaseInsensitiveInHTML
};
nsAttrSelector(int32_t aNameSpace, const nsString& aAttr);
nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction,
const nsString& aValue,
ValueCaseSensitivity aValueCaseSensitivity);
nsAttrSelector(int32_t aNameSpace, nsAtom* aLowercaseAttr,
nsAtom* aCasedAttr, uint8_t aFunction,
const nsString& aValue,
ValueCaseSensitivity aValueCaseSensitivity);
~nsAttrSelector(void);
/** Do a deep clone. Should be used only on the first in the linked list. */
nsAttrSelector* Clone() const { return Clone(true); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
bool IsValueCaseSensitive(bool aInHTML) const {
return mValueCaseSensitivity == ValueCaseSensitivity::CaseSensitive ||
(!aInHTML &&
mValueCaseSensitivity == ValueCaseSensitivity::CaseInsensitiveInHTML);
}
nsString mValue;
nsAttrSelector* mNext;
RefPtr<nsAtom> mLowercaseAttr;
RefPtr<nsAtom> mCasedAttr;
int32_t mNameSpace;
uint8_t mFunction;
ValueCaseSensitivity mValueCaseSensitivity;
private:
nsAttrSelector* Clone(bool aDeep) const;
nsAttrSelector(const nsAttrSelector& aCopy) = delete;
nsAttrSelector& operator=(const nsAttrSelector& aCopy) = delete;
};
struct nsCSSSelector {
public:
typedef mozilla::CSSPseudoClassType CSSPseudoClassType;
nsCSSSelector(void);
~nsCSSSelector(void);
/** Do a deep clone. Should be used only on the first in the linked list. */
nsCSSSelector* Clone() const { return Clone(true, true); }
void Reset(void);
void SetNameSpace(int32_t aNameSpace);
void SetTag(const nsString& aTag);
void AddID(const nsString& aID);
void AddClass(const nsString& aClass);
void AddPseudoClass(CSSPseudoClassType aType);
void AddPseudoClass(CSSPseudoClassType aType, const char16_t* aString);
void AddPseudoClass(CSSPseudoClassType aType, const int32_t* aIntPair);
// takes ownership of aSelectorList
void AddPseudoClass(CSSPseudoClassType aType,
nsCSSSelectorList* aSelectorList);
void AddAttribute(int32_t aNameSpace, const nsString& aAttr);
void AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc,
const nsString& aValue,
nsAttrSelector::ValueCaseSensitivity aValueCaseSensitivity);
void SetOperator(char16_t aOperator);
inline bool HasTagSelector() const {
return !!mCasedTag;
}
inline bool IsPseudoElement() const {
return mLowercaseTag && !mCasedTag;
}
// Calculate the specificity of this selector (not including its mNext!).
int32_t CalcWeight() const;
void ToString(nsAString& aString, mozilla::CSSStyleSheet* aSheet,
bool aAppend = false) const;
bool IsRestrictedSelector() const {
return PseudoType() == mozilla::CSSPseudoElementType::NotPseudo;
}
#ifdef DEBUG
nsCString RestrictedSelectorToString() const;
#endif
private:
void AddPseudoClassInternal(nsPseudoClassList *aPseudoClass);
nsCSSSelector* Clone(bool aDeepNext, bool aDeepNegations) const;
void AppendToStringWithoutCombinators(
nsAString& aString,
mozilla::CSSStyleSheet* aSheet,
bool aUseStandardNamespacePrefixes) const;
void AppendToStringWithoutCombinatorsOrNegations(
nsAString& aString,
mozilla::CSSStyleSheet* aSheet,
bool aIsNegated,
bool aUseStandardNamespacePrefixes) const;
// Returns true if this selector can have a namespace specified (which
// happens if and only if the default namespace would apply to this
// selector).
bool CanBeNamespaced(bool aIsNegated) const;
// Calculate the specificity of this selector (not including its mNext
// or its mNegations).
int32_t CalcWeightWithoutNegations() const;
public:
// Get and set the selector's pseudo type
mozilla::CSSPseudoElementType PseudoType() const { return mPseudoType; }
void SetPseudoType(mozilla::CSSPseudoElementType aType) {
mPseudoType = aType;
}
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
// For case-sensitive documents, mLowercaseTag is the same as mCasedTag,
// but in case-insensitive documents (HTML) mLowercaseTag is lowercase.
// Also, for pseudo-elements mCasedTag will be null but mLowercaseTag
// contains their name.
RefPtr<nsAtom> mLowercaseTag;
RefPtr<nsAtom> mCasedTag;
nsAtomList* mIDList;
nsAtomList* mClassList;
nsPseudoClassList* mPseudoClassList; // atom for the pseudo, string for
// the argument to functional pseudos
nsAttrSelector* mAttrList;
nsCSSSelector* mNegations;
nsCSSSelector* mNext;
int32_t mNameSpace;
char16_t mOperator;
private:
// The underlying type of CSSPseudoElementType is uint8_t and
// it packs well with mOperator. (char16_t + uint8_t is less than 32bits.)
mozilla::CSSPseudoElementType mPseudoType;
nsCSSSelector(const nsCSSSelector& aCopy) = delete;
nsCSSSelector& operator=(const nsCSSSelector& aCopy) = delete;
};
/**
* A selector list is the unit of selectors that each style rule has.
* For example, "P B, H1 B { ... }" would be a selector list with two
* items (where each |nsCSSSelectorList| object's |mSelectors| has
* an |mNext| for the P or H1). We represent them as linked lists.
*/
namespace mozilla {
namespace css {
class StyleRule;
} // namespace css
} // namespace mozilla
struct nsCSSSelectorList {
nsCSSSelectorList(void);
~nsCSSSelectorList(void);
/**
* Create a new selector and push it onto the beginning of |mSelectors|,
* setting its |mNext| to the current value of |mSelectors|. If there is an
* earlier selector, set its |mOperator| to |aOperator|; else |aOperator|
* must be char16_t(0).
* Returns the new selector.
* The list owns the new selector.
* The caller is responsible for updating |mWeight|.
*/
nsCSSSelector* AddSelector(char16_t aOperator);
/**
* Point |mSelectors| to its |mNext|, and delete the first node in the old
* |mSelectors|.
* Should only be used on a list with more than one selector in it.
*/
void RemoveRightmostSelector();
/**
* Should be used only on the first in the list
*/
void ToString(nsAString& aResult, mozilla::CSSStyleSheet* aSheet);
/**
* Do a deep clone. Should be used only on the first in the list.
*/
nsCSSSelectorList* Clone() const { return Clone(true); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
nsCSSSelector* mSelectors;
int32_t mWeight;
nsCSSSelectorList* mNext;
protected:
friend class mozilla::css::StyleRule;
nsCSSSelectorList* Clone(bool aDeep) const;
private:
nsCSSSelectorList(const nsCSSSelectorList& aCopy) = delete;
nsCSSSelectorList& operator=(const nsCSSSelectorList& aCopy) = delete;
};
// 464bab7a-2fce-4f30-ab44-b7a5f3aae57d
#define NS_CSS_STYLE_RULE_IMPL_CID \
{ 0x464bab7a, 0x2fce, 0x4f30, \
{ 0xab, 0x44, 0xb7, 0xa5, 0xf3, 0xaa, 0xe5, 0x7d } }
class DOMCSSDeclarationImpl;
namespace mozilla {
namespace css {
class Declaration;
class StyleRule final : public BindingStyleRule
{
public:
StyleRule(nsCSSSelectorList* aSelector,
Declaration *aDeclaration,
uint32_t aLineNumber, uint32_t aColumnNumber);
private:
// for |Clone|
StyleRule(const StyleRule& aCopy);
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_RULE_IMPL_CID)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(StyleRule, Rule)
bool IsCCLeaf() const override;
uint32_t GetSelectorCount() override;
nsresult GetSelectorText(uint32_t aSelectorIndex,
nsAString& aText) override;
nsresult GetSpecificity(uint32_t aSelectorIndex,
uint64_t* aSpecificity) override;
nsresult SelectorMatchesElement(dom::Element* aElement,
uint32_t aSelectorIndex,
const nsAString& aPseudo,
bool* aMatches) override;
mozilla::NotNull<DeclarationBlock*> GetDeclarationBlock() const override;
// WebIDL interface
uint16_t Type() const override;
void GetCssText(nsAString& aCssText) const override;
void GetSelectorText(nsAString& aSelectorText) final;
void SetSelectorText(const nsAString& aSelectorText) final;
nsICSSDeclaration* Style() override;
// null for style attribute
nsCSSSelectorList* Selector() { return mSelector; }
Declaration* GetDeclaration() const { return mDeclaration; }
void SetDeclaration(Declaration* aDecl);
int32_t GetType() const override;
already_AddRefed<Rule> Clone() const override;
#ifdef DEBUG
void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
private:
~StyleRule();
// Drop our references to mDeclaration and mRule, and let them know we're
// doing that.
void DropReferences();
nsCSSSelectorList*
GetSelectorAtIndex(uint32_t aIndex, ErrorResult& rv);
private:
nsCSSSelectorList* mSelector; // null for style attribute
RefPtr<Declaration> mDeclaration;
// We own it, and it aggregates its refcount with us.
UniquePtr<DOMCSSDeclarationImpl> mDOMDeclaration;
private:
StyleRule& operator=(const StyleRule& aCopy) = delete;
};
NS_DEFINE_STATIC_IID_ACCESSOR(StyleRule, NS_CSS_STYLE_RULE_IMPL_CID)
} // namespace css
} // namespace mozilla
#endif /* mozilla_css_StyleRule_h__ */

Просмотреть файл

@ -70,18 +70,6 @@ EXPORTS += [
'nsTimingFunction.h',
]
if CONFIG['MOZ_OLD_STYLE']:
EXPORTS += [
'nsCSSRuleProcessor.h',
'nsIStyleRule.h',
'nsIStyleRuleProcessor.h',
'nsMediaList.h',
'nsRuleData.h',
'nsRuleNode.h',
'nsRuleWalker.h',
'nsStyleSet.h',
]
EXPORTS.mozilla += [
'AnimationCollection.h',
'BindingStyleRule.h',
@ -139,17 +127,6 @@ EXPORTS.mozilla += [
'URLExtraData.h',
]
if CONFIG['MOZ_OLD_STYLE']:
EXPORTS.mozilla += [
'CSSStyleSheet.h',
'CSSVariableDeclarations.h',
'CSSVariableResolver.h',
'CSSVariableValues.h',
'GeckoStyleContext.h',
'IncrementalClearCOMRuleArray.h',
'RuleProcessorCache.h',
]
EXPORTS.mozilla.dom += [
'CSS.h',
'CSSFontFeatureValuesRule.h',
@ -183,14 +160,6 @@ EXPORTS.mozilla.css += [
'URLMatchingFunction.h',
]
if CONFIG['MOZ_OLD_STYLE']:
EXPORTS.mozilla.css += [
'Declaration.h',
'ImportRule.h',
'NameSpaceRule.h',
'StyleRule.h',
]
UNIFIED_SOURCES += [
'AnimationCollection.cpp',
'BindingStyleRule.cpp',
@ -276,29 +245,6 @@ UNIFIED_SOURCES += [
'URLExtraData.cpp',
]
if CONFIG['MOZ_OLD_STYLE']:
UNIFIED_SOURCES += [
'CSSStyleSheet.cpp',
'CSSVariableDeclarations.cpp',
'CSSVariableResolver.cpp',
'CSSVariableValues.cpp',
'Declaration.cpp',
'GeckoStyleContext.cpp',
'IncrementalClearCOMRuleArray.cpp',
'nsCSSDataBlock.cpp',
'nsCSSParser.cpp',
'nsCSSRuleProcessor.cpp',
'nsCSSRules.cpp',
'nsMediaList.cpp',
'nsNthIndexCache.cpp',
'nsRuleData.cpp',
'nsRuleNode.cpp',
'nsStyleSet.cpp',
'RuleNodeCacheConditions.cpp',
'RuleProcessorCache.cpp',
'StyleRule.cpp',
]
SOURCES += [
# Both nsCSSPseudoElements.cpp and nsCSSPseudoClasses.cpp defined a
# 'mozPlaceholder' static atom.

Просмотреть файл

@ -1,805 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* compact representation of the property-value pairs within a CSS
* declaration, and the code for expanding and compacting it
*/
#include "nsCSSDataBlock.h"
#include "CSSVariableImageTable.h"
#include "mozilla/css/Declaration.h"
#include "mozilla/css/ImageLoader.h"
#include "mozilla/CORSMode.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/WritingModes.h"
#include "nsAutoPtr.h"
#include "nsIDocument.h"
#include "nsRuleData.h"
#include "nsStyleContext.h"
#include "nsStyleSet.h"
using namespace mozilla;
using namespace mozilla::css;
/**
* Does a fast move of aSource to aDest. The previous value in
* aDest is cleanly destroyed, and aSource is cleared. Returns
* true if, before the copy, the value at aSource compared unequal
* to the value at aDest; false otherwise.
*/
static bool
MoveValue(nsCSSValue* aSource, nsCSSValue* aDest)
{
bool changed = (*aSource != *aDest);
aDest->~nsCSSValue();
memcpy(aDest, aSource, sizeof(nsCSSValue));
new (aSource) nsCSSValue();
return changed;
}
static bool
ShouldIgnoreColors(nsRuleData *aRuleData)
{
return aRuleData->mLevel != SheetType::Agent &&
aRuleData->mLevel != SheetType::User &&
!aRuleData->mPresContext->UseDocumentColors();
}
/**
* Tries to call |nsCSSValue::StartImageLoad()| on an image source.
* Image sources are specified by |url()| or |-moz-image-rect()| function.
*/
static void
TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument,
nsStyleContext* aContext, nsCSSPropertyID aProperty,
bool aForTokenStream)
{
MOZ_ASSERT(aDocument);
if (aValue.GetUnit() == eCSSUnit_URL) {
// The 'mask-image' property accepts local reference URIs.
// For example,
// mask-image: url(#mask_id); // refer to a SVG mask element, whose id is
// // "mask_id", in the current document.
// For such 'mask-image' values (pointing to an in-document element),
// there is no need to trigger image download.
if (aProperty == eCSSProperty_mask_image) {
// Filter out all fragment URLs.
// Since nsCSSValue::GetURLStructValue runs much faster than
// nsIURI::EqualsExceptRef bellow, we get performance gain by this
// early return.
URLValue* urlValue = aValue.GetURLStructValue();
if (urlValue->IsLocalRef()) {
return;
}
// Even though urlValue is not a fragment URL, it might still refer to
// an internal resource.
// For example, aDocument base URL is "http://foo/index.html" and
// intentionally references a mask-image at
// url(http://foo/index.html#mask) which still refers to a resource in
// aDocument.
nsIURI* imageURI = aValue.GetURLValue();
if (imageURI) {
nsIURI* docURI = aDocument->GetDocumentURI();
bool isEqualExceptRef = false;
nsresult rv = imageURI->EqualsExceptRef(docURI, &isEqualExceptRef);
if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
return;
}
}
}
CORSMode mode =
nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOAD_USE_CORS) ?
CORSMode::CORS_ANONYMOUS :
CORSMode::CORS_NONE;
aValue.StartImageLoad(aDocument, mode);
if (aForTokenStream && aContext) {
CSSVariableImageTable::Add(aContext, aProperty,
aValue.GetImageStructValue());
}
}
else if (aValue.GetUnit() == eCSSUnit_Image) {
// If we already have a request, see if this document needs to clone it.
imgIRequest* request = aValue.GetImageValue(nullptr);
if (request) {
ImageValue* imageValue = aValue.GetImageStructValue();
aDocument->StyleImageLoader()->MaybeRegisterCSSImage(imageValue);
if (aForTokenStream && aContext) {
CSSVariableImageTable::Add(aContext, aProperty, imageValue);
}
}
}
else if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
nsCSSValue::Array* arguments = aValue.GetArrayValue();
MOZ_ASSERT(arguments->Count() == 6, "unexpected num of arguments");
const nsCSSValue& image = arguments->Item(1);
TryToStartImageLoadOnValue(image, aDocument, aContext, aProperty,
aForTokenStream);
}
}
static void
TryToStartImageLoad(const nsCSSValue& aValue, nsIDocument* aDocument,
nsStyleContext* aContext, nsCSSPropertyID aProperty,
bool aForTokenStream)
{
if (aValue.GetUnit() == eCSSUnit_List) {
for (const nsCSSValueList* l = aValue.GetListValue(); l; l = l->mNext) {
TryToStartImageLoad(l->mValue, aDocument, aContext, aProperty,
aForTokenStream);
}
} else if (nsCSSProps::PropHasFlags(aProperty,
CSS_PROPERTY_IMAGE_IS_IN_ARRAY_0)) {
if (aValue.GetUnit() == eCSSUnit_Array) {
TryToStartImageLoadOnValue(aValue.GetArrayValue()->Item(0), aDocument,
aContext, aProperty, aForTokenStream);
}
} else {
TryToStartImageLoadOnValue(aValue, aDocument, aContext, aProperty,
aForTokenStream);
}
}
static inline bool
ShouldStartImageLoads(nsRuleData *aRuleData, nsCSSPropertyID aProperty)
{
// Don't initiate image loads for if-visited styles. This is
// important because:
// (1) it's a waste of CPU and bandwidth
// (2) in some cases we'd start the image load on a style change
// where we wouldn't have started the load initially, which makes
// which links are visited detectable to Web pages (see bug
// 557287)
return !aRuleData->mStyleContext->IsStyleIfVisited() &&
nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_START_IMAGE_LOADS);
}
static void
MapSinglePropertyInto(nsCSSPropertyID aTargetProp,
const nsCSSValue* aSrcValue,
nsCSSValue* aTargetValue,
nsRuleData* aRuleData)
{
MOZ_ASSERT(!nsCSSProps::PropHasFlags(aTargetProp, CSS_PROPERTY_LOGICAL),
"Can't map into a logical property");
MOZ_ASSERT(aSrcValue->GetUnit() != eCSSUnit_Null, "oops");
// Although aTargetValue is the nsCSSValue we are going to write into,
// we also look at its value before writing into it. This is done
// when aTargetValue is a token stream value, which is the case when we
// have just re-parsed a property that had a variable reference (in
// nsCSSParser::ParsePropertyWithVariableReferences). TryToStartImageLoad
// then records any resulting ImageValue objects in the
// CSSVariableImageTable, to give them the appropriate lifetime.
MOZ_ASSERT(aTargetValue->GetUnit() == eCSSUnit_TokenStream ||
aTargetValue->GetUnit() == eCSSUnit_Null,
"aTargetValue must only be a token stream (when re-parsing "
"properties with variable references) or null");
if (ShouldStartImageLoads(aRuleData, aTargetProp)) {
nsIDocument* doc = aRuleData->mPresContext->Document();
TryToStartImageLoad(*aSrcValue, doc, aRuleData->mStyleContext,
aTargetProp,
aTargetValue->GetUnit() == eCSSUnit_TokenStream);
}
*aTargetValue = *aSrcValue;
if (nsCSSProps::PropHasFlags(aTargetProp,
CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) &&
ShouldIgnoreColors(aRuleData))
{
if (aTargetProp == eCSSProperty_background_color) {
// Force non-'transparent' background
// colors to the user's default.
if (aTargetValue->IsNonTransparentColor()) {
aTargetValue->SetColorValue(aRuleData->mPresContext->
DefaultBackgroundColor());
}
} else {
// Ignore 'color', 'border-*-color', etc.
*aTargetValue = nsCSSValue();
}
}
}
/**
* If aProperty is a logical property, converts it to the equivalent physical
* property based on writing mode information obtained from aRuleData's
* style context.
*/
static inline void
EnsurePhysicalProperty(nsCSSPropertyID& aProperty, nsRuleData* aRuleData)
{
bool isAxisProperty =
nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_AXIS);
bool isBlock =
nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_BLOCK_AXIS);
int index;
if (isAxisProperty) {
LogicalAxis logicalAxis = isBlock ? eLogicalAxisBlock : eLogicalAxisInline;
uint8_t wm = aRuleData->mStyleContext->StyleVisibility()->mWritingMode;
PhysicalAxis axis =
WritingMode::PhysicalAxisForLogicalAxis(wm, logicalAxis);
// We rely on physical axis constants values matching the order of the
// physical properties in the logical group array.
static_assert(eAxisVertical == 0 && eAxisHorizontal == 1,
"unexpected axis constant values");
index = axis;
} else {
bool isEnd =
nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_END_EDGE);
LogicalEdge edge = isEnd ? eLogicalEdgeEnd : eLogicalEdgeStart;
// We handle block axis logical properties separately to save a bit of
// work that the WritingMode constructor does that is unnecessary
// unless we have an inline axis property.
mozilla::Side side;
if (isBlock) {
uint8_t wm = aRuleData->mStyleContext->StyleVisibility()->mWritingMode;
side = WritingMode::PhysicalSideForBlockAxis(wm, edge);
} else {
WritingMode wm(aRuleData->mStyleContext);
side = wm.PhysicalSideForInlineAxis(edge);
}
// We rely on the physical side constant values matching the order of
// the physical properties in the logical group array.
static_assert(eSideTop == 0 && eSideRight == 1 &&
eSideBottom == 2 && eSideLeft == 3,
"unexpected side constant values");
index = side;
}
const nsCSSPropertyID* props = nsCSSProps::LogicalGroup(aProperty);
size_t len = isAxisProperty ? 2 : 4;
#ifdef DEBUG
for (size_t i = 0; i < len; i++) {
MOZ_ASSERT(props[i] != eCSSProperty_UNKNOWN,
"unexpected logical group length");
}
MOZ_ASSERT(props[len] == eCSSProperty_UNKNOWN,
"unexpected logical group length");
#endif
for (size_t i = 0; i < len; i++) {
if (aRuleData->ValueFor(props[i])->GetUnit() == eCSSUnit_Null) {
// A declaration of one of the logical properties in this logical
// group (but maybe not aProperty) would be the winning
// declaration in the cascade. This means that it's reasonably
// likely that this logical property could be the winning
// declaration in the cascade for some values of writing-mode,
// direction, and text-orientation. (It doesn't mean that for
// sure, though. For example, if this is a block-start logical
// property, and all but the bottom physical property were set.
// But the common case we want to hit here is logical declarations
// that are completely overridden by a shorthand.)
//
// If this logical property could be the winning declaration in
// the cascade for some values of writing-mode, direction, and
// text-orientation, then we have to fault the resulting style
// struct out of the rule tree. We can't cache anything on the
// rule tree if it depends on data from the style context, since
// data cached in the rule tree could be used with a style context
// with a different value of the depended-upon data.
uint8_t wm = WritingMode(aRuleData->mStyleContext).GetBits();
aRuleData->mConditions.SetWritingModeDependency(wm);
break;
}
}
aProperty = props[index];
}
void
nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
{
// If we have no data for these structs, then return immediately.
// This optimization should make us return most of the time, so we
// have to worry much less (although still some) about the speed of
// the rest of the function.
if (!(aRuleData->mSIDs & mStyleBits))
return;
// We process these in reverse order so that we end up mapping the
// right property when one can be expressed using both logical and
// physical property names.
for (uint32_t i = mNumProps; i-- > 0; ) {
nsCSSPropertyID iProp = PropertyAtIndex(i);
if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) &
aRuleData->mSIDs) {
if (nsCSSProps::PropHasFlags(iProp, CSS_PROPERTY_LOGICAL)) {
EnsurePhysicalProperty(iProp, aRuleData);
}
nsCSSValue* target = aRuleData->ValueFor(iProp);
if (target->GetUnit() == eCSSUnit_Null) {
const nsCSSValue *val = ValueAtIndex(i);
// In order for variable resolution to have the right information
// about the stylesheet level of a value, that level needs to be
// stored on the token stream. We can't do that at creation time
// because the CSS parser (which creates the object) has no idea
// about the stylesheet level, so we do it here instead, where
// the rule walking will have just updated aRuleData.
if (val->GetUnit() == eCSSUnit_TokenStream) {
val->GetTokenStreamValue()->mLevel = aRuleData->mLevel;
}
MapSinglePropertyInto(iProp, val, target, aRuleData);
}
}
}
}
const nsCSSValue*
nsCSSCompressedDataBlock::ValueFor(nsCSSPropertyID aProperty) const
{
MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
"Don't call for shorthands");
// If we have no data for this struct, then return immediately.
// This optimization should make us return most of the time, so we
// have to worry much less (although still some) about the speed of
// the rest of the function.
if (!(nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]) &
mStyleBits))
return nullptr;
for (uint32_t i = 0; i < mNumProps; i++) {
if (PropertyAtIndex(i) == aProperty) {
return ValueAtIndex(i);
}
}
return nullptr;
}
bool
nsCSSCompressedDataBlock::TryReplaceValue(nsCSSPropertyID aProperty,
nsCSSExpandedDataBlock& aFromBlock,
bool *aChanged)
{
nsCSSValue* newValue = aFromBlock.PropertyAt(aProperty);
MOZ_ASSERT(newValue && newValue->GetUnit() != eCSSUnit_Null,
"cannot replace with empty value");
const nsCSSValue* oldValue = ValueFor(aProperty);
if (!oldValue) {
*aChanged = false;
return false;
}
*aChanged = MoveValue(newValue, const_cast<nsCSSValue*>(oldValue));
aFromBlock.ClearPropertyBit(aProperty);
return true;
}
nsCSSCompressedDataBlock*
nsCSSCompressedDataBlock::Clone() const
{
nsAutoPtr<nsCSSCompressedDataBlock>
result(new(mNumProps) nsCSSCompressedDataBlock(mNumProps));
result->mStyleBits = mStyleBits;
for (uint32_t i = 0; i < mNumProps; i++) {
result->SetPropertyAtIndex(i, PropertyAtIndex(i));
result->CopyValueToIndex(i, ValueAtIndex(i));
}
return result.forget();
}
nsCSSCompressedDataBlock::~nsCSSCompressedDataBlock()
{
for (uint32_t i = 0; i < mNumProps; i++) {
#ifdef DEBUG
(void)PropertyAtIndex(i); // this checks the property is in range
#endif
const nsCSSValue* val = ValueAtIndex(i);
MOZ_ASSERT(val->GetUnit() != eCSSUnit_Null, "oops");
val->~nsCSSValue();
}
}
/* static */ nsCSSCompressedDataBlock*
nsCSSCompressedDataBlock::CreateEmptyBlock()
{
nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock(0);
return result;
}
size_t
nsCSSCompressedDataBlock::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
for (uint32_t i = 0; i < mNumProps; i++) {
n += ValueAtIndex(i)->SizeOfExcludingThis(aMallocSizeOf);
}
return n;
}
bool
nsCSSCompressedDataBlock::HasDefaultBorderImageSlice() const
{
const nsCSSValueList *slice =
ValueFor(eCSSProperty_border_image_slice)->GetListValue();
return !slice->mNext &&
slice->mValue.GetRectValue().AllSidesEqualTo(
nsCSSValue(1.0f, eCSSUnit_Percent));
}
bool
nsCSSCompressedDataBlock::HasDefaultBorderImageWidth() const
{
const nsCSSRect &width =
ValueFor(eCSSProperty_border_image_width)->GetRectValue();
return width.AllSidesEqualTo(nsCSSValue(1.0f, eCSSUnit_Number));
}
bool
nsCSSCompressedDataBlock::HasDefaultBorderImageOutset() const
{
const nsCSSRect &outset =
ValueFor(eCSSProperty_border_image_outset)->GetRectValue();
return outset.AllSidesEqualTo(nsCSSValue(0.0f, eCSSUnit_Number));
}
bool
nsCSSCompressedDataBlock::HasDefaultBorderImageRepeat() const
{
const nsCSSValuePair &repeat =
ValueFor(eCSSProperty_border_image_repeat)->GetPairValue();
return repeat.BothValuesEqualTo(nsCSSValue(StyleBorderImageRepeat::Stretch));
}
/*****************************************************************************/
nsCSSExpandedDataBlock::nsCSSExpandedDataBlock()
{
AssertInitialState();
}
nsCSSExpandedDataBlock::~nsCSSExpandedDataBlock()
{
AssertInitialState();
}
void
nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
bool aImportant)
{
/*
* Save needless copying and allocation by copying the memory
* corresponding to the stored data in the compressed block.
*/
for (uint32_t i = 0; i < aBlock->mNumProps; i++) {
nsCSSPropertyID iProp = aBlock->PropertyAtIndex(i);
MOZ_ASSERT(!nsCSSProps::IsShorthand(iProp), "out of range");
MOZ_ASSERT(!HasPropertyBit(iProp),
"compressed block has property multiple times");
SetPropertyBit(iProp);
if (aImportant)
SetImportantBit(iProp);
const nsCSSValue* val = aBlock->ValueAtIndex(i);
nsCSSValue* dest = PropertyAt(iProp);
MOZ_ASSERT(val->GetUnit() != eCSSUnit_Null, "oops");
MOZ_ASSERT(dest->GetUnit() == eCSSUnit_Null,
"expanding into non-empty block");
#ifdef NS_BUILD_REFCNT_LOGGING
dest->~nsCSSValue();
#endif
memcpy(dest, val, sizeof(nsCSSValue));
}
// Set the number of properties to zero so that we don't destroy the
// remnants of what we just copied.
aBlock->SetNumPropsToZero();
delete aBlock;
}
void
nsCSSExpandedDataBlock::Expand(nsCSSCompressedDataBlock *aNormalBlock,
nsCSSCompressedDataBlock *aImportantBlock)
{
MOZ_ASSERT(aNormalBlock, "unexpected null block");
AssertInitialState();
DoExpand(aNormalBlock, false);
if (aImportantBlock) {
DoExpand(aImportantBlock, true);
}
}
void
nsCSSExpandedDataBlock::ComputeNumProps(uint32_t* aNumPropsNormal,
uint32_t* aNumPropsImportant)
{
*aNumPropsNormal = *aNumPropsImportant = 0;
for (size_t iHigh = 0; iHigh < nsCSSPropertyIDSet::kChunkCount; ++iHigh) {
if (!mPropertiesSet.HasPropertyInChunk(iHigh))
continue;
for (size_t iLow = 0; iLow < nsCSSPropertyIDSet::kBitsInChunk; ++iLow) {
if (!mPropertiesSet.HasPropertyAt(iHigh, iLow))
continue;
#ifdef DEBUG
nsCSSPropertyID iProp = nsCSSPropertyIDSet::CSSPropertyAt(iHigh, iLow);
#endif
MOZ_ASSERT(!nsCSSProps::IsShorthand(iProp), "out of range");
MOZ_ASSERT(PropertyAt(iProp)->GetUnit() != eCSSUnit_Null,
"null value while computing size");
if (mPropertiesImportant.HasPropertyAt(iHigh, iLow))
(*aNumPropsImportant)++;
else
(*aNumPropsNormal)++;
}
}
}
void
nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock,
nsCSSCompressedDataBlock **aImportantBlock,
const nsTArray<uint32_t>& aOrder)
{
nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important;
uint32_t i_normal = 0, i_important = 0;
uint32_t numPropsNormal, numPropsImportant;
ComputeNumProps(&numPropsNormal, &numPropsImportant);
result_normal =
new(numPropsNormal) nsCSSCompressedDataBlock(numPropsNormal);
if (numPropsImportant != 0) {
result_important =
new(numPropsImportant) nsCSSCompressedDataBlock(numPropsImportant);
} else {
result_important = nullptr;
}
/*
* Save needless copying and allocation by copying the memory
* corresponding to the stored data in the expanded block, and then
* clearing the data in the expanded block.
*/
for (size_t i = 0; i < aOrder.Length(); i++) {
nsCSSPropertyID iProp = static_cast<nsCSSPropertyID>(aOrder[i]);
if (iProp >= eCSSProperty_COUNT) {
// a custom property
continue;
}
MOZ_ASSERT(mPropertiesSet.HasProperty(iProp),
"aOrder identifies a property not in the expanded "
"data block");
MOZ_ASSERT(!nsCSSProps::IsShorthand(iProp), "out of range");
bool important = mPropertiesImportant.HasProperty(iProp);
nsCSSCompressedDataBlock *result =
important ? result_important : result_normal;
uint32_t* ip = important ? &i_important : &i_normal;
nsCSSValue* val = PropertyAt(iProp);
MOZ_ASSERT(val->GetUnit() != eCSSUnit_Null,
"Null value while compressing");
result->SetPropertyAtIndex(*ip, iProp);
result->RawCopyValueToIndex(*ip, val);
new (val) nsCSSValue();
(*ip)++;
result->mStyleBits |=
nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]);
}
MOZ_ASSERT(numPropsNormal == i_normal, "bad numProps");
if (result_important) {
MOZ_ASSERT(numPropsImportant == i_important, "bad numProps");
}
#ifdef DEBUG
{
// assert that we didn't have any other properties on this expanded data
// block that we didn't find in aOrder
uint32_t numPropsInSet = 0;
for (size_t iHigh = 0; iHigh < nsCSSPropertyIDSet::kChunkCount; iHigh++) {
if (!mPropertiesSet.HasPropertyInChunk(iHigh)) {
continue;
}
for (size_t iLow = 0; iLow < nsCSSPropertyIDSet::kBitsInChunk; iLow++) {
if (mPropertiesSet.HasPropertyAt(iHigh, iLow)) {
numPropsInSet++;
}
}
}
MOZ_ASSERT(numPropsNormal + numPropsImportant == numPropsInSet,
"aOrder missing properties from the expanded data block");
}
#endif
ClearSets();
AssertInitialState();
*aNormalBlock = result_normal.forget();
*aImportantBlock = result_important.forget();
}
void
nsCSSExpandedDataBlock::AddLonghandProperty(nsCSSPropertyID aProperty,
const nsCSSValue& aValue)
{
MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
"property out of range");
nsCSSValue& storage = *static_cast<nsCSSValue*>(PropertyAt(aProperty));
storage = aValue;
SetPropertyBit(aProperty);
}
void
nsCSSExpandedDataBlock::Clear()
{
for (size_t iHigh = 0; iHigh < nsCSSPropertyIDSet::kChunkCount; ++iHigh) {
if (!mPropertiesSet.HasPropertyInChunk(iHigh))
continue;
for (size_t iLow = 0; iLow < nsCSSPropertyIDSet::kBitsInChunk; ++iLow) {
if (!mPropertiesSet.HasPropertyAt(iHigh, iLow))
continue;
nsCSSPropertyID iProp = nsCSSPropertyIDSet::CSSPropertyAt(iHigh, iLow);
ClearLonghandProperty(iProp);
}
}
AssertInitialState();
}
void
nsCSSExpandedDataBlock::ClearProperty(nsCSSPropertyID aPropID)
{
if (nsCSSProps::IsShorthand(aPropID)) {
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
p, aPropID, CSSEnabledState::eIgnoreEnabledState) {
ClearLonghandProperty(*p);
}
} else {
ClearLonghandProperty(aPropID);
}
}
void
nsCSSExpandedDataBlock::ClearLonghandProperty(nsCSSPropertyID aPropID)
{
MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID), "out of range");
ClearPropertyBit(aPropID);
ClearImportantBit(aPropID);
PropertyAt(aPropID)->Reset();
}
bool
nsCSSExpandedDataBlock::TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
nsCSSPropertyID aPropID,
CSSEnabledState aEnabledState,
bool aIsImportant,
bool aOverrideImportant,
bool aMustCallValueAppended,
css::Declaration* aDeclaration,
nsIDocument* aSheetDocument)
{
if (!nsCSSProps::IsShorthand(aPropID)) {
return DoTransferFromBlock(aFromBlock, aPropID,
aIsImportant, aOverrideImportant,
aMustCallValueAppended, aDeclaration,
aSheetDocument);
}
// We can pass CSSEnabledState::eIgnore (here, and in ClearProperty
// above) rather than a value corresponding to whether we're parsing
// a UA style sheet or certified app because we assert in nsCSSProps::
// AddRefTable that shorthand properties available in these contexts
// also have all of their subproperties available in these contexts.
bool changed = false;
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID, aEnabledState) {
changed |= DoTransferFromBlock(aFromBlock, *p,
aIsImportant, aOverrideImportant,
aMustCallValueAppended, aDeclaration,
aSheetDocument);
}
return changed;
}
bool
nsCSSExpandedDataBlock::DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
nsCSSPropertyID aPropID,
bool aIsImportant,
bool aOverrideImportant,
bool aMustCallValueAppended,
css::Declaration* aDeclaration,
nsIDocument* aSheetDocument)
{
bool changed = false;
MOZ_ASSERT(aFromBlock.HasPropertyBit(aPropID), "oops");
if (aIsImportant) {
if (!HasImportantBit(aPropID))
changed = true;
SetImportantBit(aPropID);
} else {
if (HasImportantBit(aPropID)) {
// When parsing a declaration block, an !important declaration
// is not overwritten by an ordinary declaration of the same
// property later in the block. However, CSSOM manipulations
// come through here too, and in that case we do want to
// overwrite the property.
if (!aOverrideImportant) {
aFromBlock.ClearLonghandProperty(aPropID);
return false;
}
changed = true;
ClearImportantBit(aPropID);
}
}
if (aMustCallValueAppended || !HasPropertyBit(aPropID)) {
aDeclaration->ValueAppended(aPropID);
}
if (aSheetDocument) {
UseCounter useCounter = nsCSSProps::UseCounterFor(aPropID);
if (useCounter != eUseCounter_UNKNOWN) {
aSheetDocument->SetDocumentAndPageUseCounter(useCounter);
}
}
SetPropertyBit(aPropID);
aFromBlock.ClearPropertyBit(aPropID);
/*
* Save needless copying and allocation by calling the destructor in
* the destination, copying memory directly, and then using placement
* new.
*/
changed |= MoveValue(aFromBlock.PropertyAt(aPropID), PropertyAt(aPropID));
return changed;
}
void
nsCSSExpandedDataBlock::MapRuleInfoInto(nsCSSPropertyID aPropID,
nsRuleData* aRuleData) const
{
MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID));
const nsCSSValue* src = PropertyAt(aPropID);
MOZ_ASSERT(src->GetUnit() != eCSSUnit_Null);
nsCSSPropertyID physicalProp = aPropID;
if (nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_LOGICAL)) {
EnsurePhysicalProperty(physicalProp, aRuleData);
}
nsCSSValue* dest = aRuleData->ValueFor(physicalProp);
MOZ_ASSERT(dest->GetUnit() == eCSSUnit_TokenStream &&
dest->GetTokenStreamValue()->mPropertyID == aPropID);
CSSVariableImageTable::ReplaceAll(aRuleData->mStyleContext, aPropID, [=] {
MapSinglePropertyInto(physicalProp, src, dest, aRuleData);
});
}
#ifdef DEBUG
void
nsCSSExpandedDataBlock::DoAssertInitialState()
{
mPropertiesSet.AssertIsEmpty("not initial state");
mPropertiesImportant.AssertIsEmpty("not initial state");
for (uint32_t i = 0; i < eCSSProperty_COUNT_no_shorthands; ++i) {
nsCSSPropertyID prop = nsCSSPropertyID(i);
MOZ_ASSERT(PropertyAt(prop)->GetUnit() == eCSSUnit_Null,
"not initial state");
}
}
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,268 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* style rule processor for CSS style sheets, responsible for selector
* matching and cascading
*/
#ifndef nsCSSRuleProcessor_h_
#define nsCSSRuleProcessor_h_
#include "mozilla/Attributes.h"
#include "mozilla/EventStates.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/RefCountType.h"
#include "mozilla/SheetType.h"
#include "mozilla/UniquePtr.h"
#include "nsExpirationTracker.h"
#include "nsMediaList.h"
#include "nsIStyleRuleProcessor.h"
#include "nsRuleWalker.h"
#include "nsTArray.h"
struct CascadeEnumData;
struct ElementDependentRuleProcessorData;
struct nsCSSSelector;
struct nsCSSSelectorList;
struct nsFontFaceRuleContainer;
struct RuleCascadeData;
struct TreeMatchContext;
class nsCSSKeyframesRule;
class nsCSSPageRule;
class nsCSSFontFeatureValuesRule;
class nsCSSCounterStyleRule;
namespace mozilla {
class CSSStyleSheet;
enum class CSSPseudoElementType : uint8_t;
enum class CSSPseudoClassType : uint8_t;
namespace css {
class DocumentRule;
} // namespace css
} // namespace mozilla
/**
* The CSS style rule processor provides a mechanism for sibling style
* sheets to combine their rule processing in order to allow proper
* cascading to happen.
*
* CSS style rule processors keep a live reference on all style sheets
* bound to them. The CSS style sheets keep a weak reference to all the
* processors that they are bound to (many to many). The CSS style sheet
* is told when the rule processor is going away (via DropRuleProcessor).
*/
class nsCSSRuleProcessor: public nsIStyleRuleProcessor {
public:
typedef nsTArray<RefPtr<mozilla::CSSStyleSheet>> sheet_array_type;
// aScopeElement must be non-null iff aSheetType is
// SheetType::ScopedDoc.
// aPreviousCSSRuleProcessor is the rule processor (if any) that this
// one is replacing.
nsCSSRuleProcessor(const sheet_array_type& aSheets,
mozilla::SheetType aSheetType,
mozilla::dom::Element* aScopeElement,
nsCSSRuleProcessor* aPreviousCSSRuleProcessor,
bool aIsShared = false);
nsCSSRuleProcessor(sheet_array_type&& aSheets,
mozilla::SheetType aSheetType,
mozilla::dom::Element* aScopeElement,
nsCSSRuleProcessor* aPreviousCSSRuleProcessor,
bool aIsShared = false);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsCSSRuleProcessor)
public:
nsresult ClearRuleCascades();
/*
* Returns true if the given aElement matches one of the
* selectors in aSelectorList. Note that this method will assume
* the given aElement is not a relevant link. aSelectorList must not
* include any pseudo-element selectors. aSelectorList is allowed
* to be null; in this case false will be returned.
*/
static bool SelectorListMatches(mozilla::dom::Element* aElement,
TreeMatchContext& aTreeMatchContext,
nsCSSSelectorList* aSelectorList);
/*
* Helper to get the content state for a content node. This may be
* slightly adjusted from IntrinsicState().
*/
static mozilla::EventStates GetContentState(
const mozilla::dom::Element* aElement,
bool aUsingPrivateBrowsing);
static mozilla::EventStates GetContentState(
const mozilla::dom::Element* aElement,
const TreeMatchContext& aTreeMatchContext);
static mozilla::EventStates GetContentState(
const mozilla::dom::Element* aElement);
/*
* Helper to get the content state for :visited handling for an element
*/
static mozilla::EventStates GetContentStateForVisitedHandling(
const mozilla::dom::Element* aElement,
nsRuleWalker::VisitedHandlingType aVisitedHandling,
bool aIsRelevantLink);
/*
* Helper to test whether a node is a link
*/
static bool IsLink(const mozilla::dom::Element* aElement);
/**
* Returns true if the given aElement matches aSelector.
* Like nsCSSRuleProcessor.cpp's SelectorMatches (and unlike
* SelectorMatchesTree), this does not check an entire selector list
* separated by combinators.
*
* :visited and :link will match both visited and non-visited links,
* as if aTreeMatchContext->mVisitedHandling were eLinksVisitedOrUnvisited.
*
* aSelector is restricted to not containing pseudo-elements.
*/
static bool RestrictedSelectorMatches(mozilla::dom::Element* aElement,
nsCSSSelector* aSelector,
TreeMatchContext& aTreeMatchContext);
// nsIStyleRuleProcessor
virtual void RulesMatching(ElementRuleProcessorData* aData) override;
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) override;
virtual void RulesMatching(AnonBoxRuleProcessorData* aData) override;
#ifdef MOZ_XUL
virtual void RulesMatching(XULTreeRuleProcessorData* aData) override;
#endif
virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData) override;
virtual nsRestyleHint HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) override;
virtual bool HasDocumentStateDependentStyle(StateRuleProcessorData* aData) override;
virtual nsRestyleHint
HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
mozilla::RestyleHintData& aRestyleHintDataResult)
override;
virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) override;
/**
* If this rule processor currently has a substantive media query
* result cache key, return a copy of it.
*/
mozilla::UniquePtr<nsMediaQueryResultCacheKey> CloneMQCacheKey();
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
const MOZ_MUST_OVERRIDE override;
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
const MOZ_MUST_OVERRIDE override;
// Append all the currently-active font face rules to aArray. Return
// true for success and false for failure.
bool AppendFontFaceRules(nsPresContext* aPresContext,
nsTArray<nsFontFaceRuleContainer>& aArray);
nsCSSKeyframesRule* KeyframesRuleForName(nsPresContext* aPresContext,
const nsAtom* aName);
nsCSSCounterStyleRule* CounterStyleRuleForName(nsPresContext* aPresContext,
nsAtom* aName);
bool AppendPageRules(nsPresContext* aPresContext,
nsTArray<nsCSSPageRule*>& aArray);
bool AppendFontFeatureValuesRules(nsPresContext* aPresContext,
nsTArray<nsCSSFontFeatureValuesRule*>& aArray);
void TakeDocumentRulesAndCacheKey(
nsPresContext* aPresContext,
nsTArray<mozilla::css::DocumentRule*>& aDocumentRules,
nsDocumentRuleResultCacheKey& aDocumentRuleResultCacheKey);
bool IsShared() const { return mIsShared; }
nsExpirationState* GetExpirationState() { return &mExpirationState; }
void AddStyleSetRef();
void ReleaseStyleSetRef();
void SetInRuleProcessorCache(bool aVal) {
MOZ_ASSERT(mIsShared);
mInRuleProcessorCache = aVal;
}
bool IsInRuleProcessorCache() const { return mInRuleProcessorCache; }
bool IsUsedByMultipleStyleSets() const { return mStyleSetRefCnt > 1; }
struct StateSelector {
StateSelector(mozilla::EventStates aStates, nsCSSSelector* aSelector)
: mStates(aStates),
mSelector(aSelector)
{}
mozilla::EventStates mStates;
nsCSSSelector* mSelector;
};
protected:
virtual ~nsCSSRuleProcessor();
private:
static bool CascadeSheet(mozilla::CSSStyleSheet* aSheet,
CascadeEnumData* aData);
RuleCascadeData* GetRuleCascade(nsPresContext* aPresContext);
void RefreshRuleCascade(nsPresContext* aPresContext);
nsRestyleHint HasStateDependentStyle(ElementDependentRuleProcessorData* aData,
mozilla::dom::Element* aStatefulElement,
mozilla::CSSPseudoElementType aPseudoType,
mozilla::EventStates aStateMask);
void ClearSheets();
// The sheet order here is the same as in nsStyleSet::mSheets
sheet_array_type mSheets;
// active first, then cached (most recent first)
RuleCascadeData* mRuleCascades;
// If we cleared our mRuleCascades or replaced a previous rule
// processor, this is the media query result cache key that was used
// before we lost the old rule cascades.
mozilla::UniquePtr<nsMediaQueryResultCacheKey> mPreviousCacheKey;
// The last pres context for which GetRuleCascades was called.
nsPresContext *mLastPresContext;
nsTArray<mozilla::css::DocumentRule*> mDocumentRules;
nsDocumentRuleResultCacheKey mDocumentCacheKey;
nsExpirationState mExpirationState;
MozRefCountType mStyleSetRefCnt;
// type of stylesheet using this processor
mozilla::SheetType mSheetType;
const bool mIsShared;
// Whether we need to build up mDocumentCacheKey and mDocumentRules as
// we build a RuleCascadeData. Is true only for shared rule processors
// and only before we build the first RuleCascadeData. See comment in
// RefreshRuleCascade for why.
bool mMustGatherDocumentRules;
bool mInRuleProcessorCache;
#ifdef DEBUG
bool mDocumentRulesAndCacheKeyValid;
#endif
};
#endif /* nsCSSRuleProcessor_h_ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,97 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* internal abstract interface for objects providing immutable style
* information
*/
#ifndef nsIStyleRule_h___
#define nsIStyleRule_h___
#include <stdio.h>
#include "nsCSSPropertyID.h"
#include "nsISupports.h"
class nsCSSValue;
struct nsRuleData;
// IID for the nsIStyleRule interface {f75f3f70-435d-43a6-a01b-65970489ca26}
#define NS_ISTYLE_RULE_IID \
{ 0xf75f3f70, 0x435d, 0x43a6, \
{ 0xa0, 0x1b, 0x65, 0x97, 0x04, 0x89, 0xca, 0x26 } }
/**
* An object implementing |nsIStyleRule| (henceforth, a rule) represents
* immutable stylistic information that either applies or does not apply
* to a given element. It belongs to an object or group of objects that
* implement |nsIStyleSheet| and |nsIStyleRuleProcessor| (henceforth, a
* sheet).
*
* A rule becomes relevant to the computation of style data when
* |nsIStyleRuleProcessor::RulesMatching| creates a rule node that
* points to the rule. (A rule node, |nsRuleNode|, is a node in the
* rule tree, which is a lexicographic tree indexed by rules. The path
* from the root of the rule tree to the |nsRuleNode| for a given
* |nsStyleContext| contains exactly the rules that match the element
* that the style context is for, in priority (weight, origin,
* specificity) order.)
*
* The computation of style data uses the rule tree, which calls
* |nsIStyleRule::MapRuleInfoInto| below.
*
* It is worth emphasizing that the data represented by a rule
* implementation are immutable. When the data need to be changed, a
* new rule object must be created. Failing to do this will lead to
* bugs in the handling of dynamic style changes, since the rule tree
* caches the results of |MapRuleInfoInto|.
*
* |nsIStyleRule| objects are owned by |nsRuleNode| objects (in addition
* to typically being owned by their sheet), which are in turn garbage
* collected (with the garbage collection roots being style contexts).
*/
class nsIStyleRule : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISTYLE_RULE_IID)
/**
* |nsIStyleRule::MapRuleInfoInto| is a request to copy all stylistic
* data represented by the rule that:
* + are relevant for any structs in |aRuleData->mSIDs| (style
* struct ID bits)
* + are not already filled into the data struct
* into the appropriate data struct in |aRuleData|. It is important
* that only empty data are filled in, since the rule tree is walked
* from highest priority rule to least, so that the walk can stop if
* all needed data are found. Thus overwriting non-empty data will
* break CSS cascading rules.
*/
virtual void MapRuleInfoInto(nsRuleData* aRuleData)=0;
/**
* Returns whether this style rule has any style data for inherited
* properties.
*/
virtual bool MightMapInheritedStyleData() = 0;
/**
* Gets and sets given aProperty's value to aValue.
* Returns true, if aValue is filled in this rule.
*/
virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
nsCSSValue* aValue) = 0;
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const = 0;
#endif
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleRule, NS_ISTYLE_RULE_IID)
#endif /* nsIStyleRule_h___ */

Просмотреть файл

@ -1,141 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* internal abstract interface for containers (roughly origins within
* the CSS cascade) that provide style rules matching an element or
* pseudo-element
*/
#ifndef nsIStyleRuleProcessor_h___
#define nsIStyleRuleProcessor_h___
#include "mozilla/MemoryReporting.h"
#include "nsISupports.h"
#include "nsChangeHint.h"
struct RuleProcessorData;
struct ElementRuleProcessorData;
struct PseudoElementRuleProcessorData;
struct AnonBoxRuleProcessorData;
#ifdef MOZ_XUL
struct XULTreeRuleProcessorData;
#endif
struct StateRuleProcessorData;
struct PseudoElementStateRuleProcessorData;
struct AttributeRuleProcessorData;
class nsPresContext;
// IID for the nsIStyleRuleProcessor interface
// {c1d6001e-4fcb-4c40-bce1-5eba80bfd8f3}
#define NS_ISTYLE_RULE_PROCESSOR_IID \
{ 0xc1d6001e, 0x4fcb, 0x4c40, \
{0xbc, 0xe1, 0x5e, 0xba, 0x80, 0xbf, 0xd8, 0xf3} }
/* The style rule processor interface is a mechanism to separate the matching
* of style rules from style sheet instances.
* Simple style sheets can and will act as their own processor.
* Sheets where rule ordering interlaces between multiple sheets, will need to
* share a single rule processor between them (CSS sheets do this for cascading order)
*
* @see nsIStyleRule (for significantly more detailed comments)
*/
class nsIStyleRuleProcessor : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISTYLE_RULE_PROCESSOR_IID)
// Shorthand for:
// nsCOMArray<nsIStyleRuleProcessor>::nsCOMArrayEnumFunc
typedef bool (* EnumFunc)(nsIStyleRuleProcessor*, void*);
/**
* Find the |nsIStyleRule|s matching the given content node and
* position the given |nsRuleWalker| at the |nsRuleNode| in the rule
* tree representing that ordered list of rules (with higher
* precedence being farther from the root of the lexicographic tree).
*/
virtual void RulesMatching(ElementRuleProcessorData* aData) = 0;
/**
* Just like the previous |RulesMatching|, except for a given content
* node <em>and pseudo-element</em>.
*/
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) = 0;
/**
* Just like the previous |RulesMatching|, except for a given anonymous box.
*/
virtual void RulesMatching(AnonBoxRuleProcessorData* aData) = 0;
#ifdef MOZ_XUL
/**
* Just like the previous |RulesMatching|, except for a given content
* node <em>and tree pseudo</em>.
*/
virtual void RulesMatching(XULTreeRuleProcessorData* aData) = 0;
#endif
/**
* Return whether style can depend on a change of the given document state.
*
* Document states are defined in nsIDocument.h.
*/
virtual bool
HasDocumentStateDependentStyle(StateRuleProcessorData* aData) = 0;
/**
* Return how (as described by nsRestyleHint) style can depend on a
* change of the given content state on the given content node. This
* test is used for optimization only, and may err on the side of
* reporting more dependencies than really exist.
*
* Event states are defined in mozilla/EventStates.h.
*/
virtual nsRestyleHint
HasStateDependentStyle(StateRuleProcessorData* aData) = 0;
virtual nsRestyleHint
HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) = 0;
/**
* This method will be called twice for every attribute change.
* During the first call, aData->mAttrHasChanged will be false and
* the attribute change will not have happened yet. During the
* second call, aData->mAttrHasChanged will be true and the
* change will have already happened. The bitwise OR of the two
* return values must describe the style changes that are needed due
* to the attribute change. It's up to the rule processor
* implementation to decide how to split the bits up amongst the two
* return values. For example, it could return the bits needed by
* rules that might stop matching the node from the first call and
* the bits needed by rules that might have started matching the
* node from the second call. This test is used for optimization
* only, and may err on the side of reporting more dependencies than
* really exist.
*/
virtual nsRestyleHint HasAttributeDependentStyle(
AttributeRuleProcessorData* aData,
mozilla::RestyleHintData& aRestyleHintDataResult) = 0;
/**
* Do any processing that needs to happen as a result of a change in
* the characteristics of the medium, and return whether this rule
* processor's rules have changed (e.g., because of media queries).
*/
virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) = 0;
/**
* Report the size of this style rule processor to about:memory. A
* processor may return 0.
*/
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const = 0;
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleRuleProcessor,
NS_ISTYLE_RULE_PROCESSOR_IID)
#endif /* nsIStyleRuleProcessor_h___ */

Просмотреть файл

@ -1,600 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* representation of media lists used when linking to style sheets or by
* @media rules
*/
#include "nsMediaList.h"
#include "nsCSSParser.h"
#include "nsCSSRules.h"
#include "nsMediaFeatures.h"
#include "nsRuleNode.h"
using namespace mozilla;
template <class Numeric>
int32_t DoCompare(Numeric a, Numeric b)
{
if (a == b)
return 0;
if (a < b)
return -1;
return 1;
}
bool
nsMediaExpression::Matches(nsPresContext* aPresContext,
const nsCSSValue& aActualValue) const
{
const nsCSSValue& actual = aActualValue;
const nsCSSValue& required = mValue;
// If we don't have the feature, the match fails.
if (actual.GetUnit() == eCSSUnit_Null) {
return false;
}
// If the expression had no value to match, the match succeeds,
// unless the value is an integer 0 or a zero length.
if (required.GetUnit() == eCSSUnit_Null) {
if (actual.GetUnit() == eCSSUnit_Integer)
return actual.GetIntValue() != 0;
if (actual.IsLengthUnit())
return actual.GetFloatValue() != 0;
return true;
}
NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxAllowed ||
mRange == nsMediaExpression::eEqual, "yikes");
int32_t cmp; // -1 (actual < required)
// 0 (actual == required)
// 1 (actual > required)
switch (mFeature->mValueType) {
case nsMediaFeature::eLength:
{
NS_ASSERTION(actual.IsLengthUnit(), "bad actual value");
NS_ASSERTION(required.IsLengthUnit(), "bad required value");
nscoord actualCoord = nsRuleNode::CalcLengthWithInitialFont(
aPresContext, actual);
nscoord requiredCoord = nsRuleNode::CalcLengthWithInitialFont(
aPresContext, required);
cmp = DoCompare(actualCoord, requiredCoord);
}
break;
case nsMediaFeature::eInteger:
case nsMediaFeature::eBoolInteger:
{
NS_ASSERTION(actual.GetUnit() == eCSSUnit_Integer,
"bad actual value");
NS_ASSERTION(required.GetUnit() == eCSSUnit_Integer,
"bad required value");
NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger ||
actual.GetIntValue() == 0 || actual.GetIntValue() == 1,
"bad actual bool integer value");
NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger ||
required.GetIntValue() == 0 || required.GetIntValue() == 1,
"bad required bool integer value");
cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
}
break;
case nsMediaFeature::eFloat:
{
NS_ASSERTION(actual.GetUnit() == eCSSUnit_Number,
"bad actual value");
NS_ASSERTION(required.GetUnit() == eCSSUnit_Number,
"bad required value");
cmp = DoCompare(actual.GetFloatValue(), required.GetFloatValue());
}
break;
case nsMediaFeature::eIntRatio:
{
NS_ASSERTION(actual.GetUnit() == eCSSUnit_Array &&
actual.GetArrayValue()->Count() == 2 &&
actual.GetArrayValue()->Item(0).GetUnit() ==
eCSSUnit_Integer &&
actual.GetArrayValue()->Item(1).GetUnit() ==
eCSSUnit_Integer,
"bad actual value");
NS_ASSERTION(required.GetUnit() == eCSSUnit_Array &&
required.GetArrayValue()->Count() == 2 &&
required.GetArrayValue()->Item(0).GetUnit() ==
eCSSUnit_Integer &&
required.GetArrayValue()->Item(1).GetUnit() ==
eCSSUnit_Integer,
"bad required value");
// Convert to int64_t so we can multiply without worry. Note
// that while the spec requires that both halves of |required|
// be positive, the numerator or denominator of |actual| might
// be zero (e.g., when testing 'aspect-ratio' on a 0-width or
// 0-height iframe).
int64_t actualNum = actual.GetArrayValue()->Item(0).GetIntValue(),
actualDen = actual.GetArrayValue()->Item(1).GetIntValue(),
requiredNum = required.GetArrayValue()->Item(0).GetIntValue(),
requiredDen = required.GetArrayValue()->Item(1).GetIntValue();
cmp = DoCompare(actualNum * requiredDen, requiredNum * actualDen);
}
break;
case nsMediaFeature::eResolution:
{
NS_ASSERTION(actual.GetUnit() == eCSSUnit_Inch ||
actual.GetUnit() == eCSSUnit_Pixel ||
actual.GetUnit() == eCSSUnit_Centimeter,
"bad actual value");
NS_ASSERTION(required.GetUnit() == eCSSUnit_Inch ||
required.GetUnit() == eCSSUnit_Pixel ||
required.GetUnit() == eCSSUnit_Centimeter,
"bad required value");
float actualDPPX = actual.GetFloatValue();
float overrideDPPX = aPresContext->GetOverrideDPPX();
if (overrideDPPX > 0) {
actualDPPX = overrideDPPX;
} else if (actual.GetUnit() == eCSSUnit_Centimeter) {
actualDPPX = actualDPPX * 2.54f / 96.0f;
} else if (actual.GetUnit() == eCSSUnit_Inch) {
actualDPPX = actualDPPX / 96.0f;
}
float requiredDPPX = required.GetFloatValue();
if (required.GetUnit() == eCSSUnit_Centimeter) {
requiredDPPX = requiredDPPX * 2.54f / 96.0f;
} else if (required.GetUnit() == eCSSUnit_Inch) {
requiredDPPX = requiredDPPX / 96.0f;
}
cmp = DoCompare(actualDPPX, requiredDPPX);
}
break;
case nsMediaFeature::eEnumerated:
{
NS_ASSERTION(actual.GetUnit() == eCSSUnit_Enumerated,
"bad actual value");
NS_ASSERTION(required.GetUnit() == eCSSUnit_Enumerated,
"bad required value");
NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed,
"bad range"); // we asserted above about mRange
// We don't really need DoCompare, but it doesn't hurt (and
// maybe the compiler will condense this case with eInteger).
cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
}
break;
case nsMediaFeature::eIdent:
{
NS_ASSERTION(actual.GetUnit() == eCSSUnit_AtomIdent,
"bad actual value");
NS_ASSERTION(required.GetUnit() == eCSSUnit_AtomIdent,
"bad required value");
NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed,
"bad range");
cmp = !(actual == required); // string comparison
}
break;
}
switch (mRange) {
case nsMediaExpression::eMin:
return cmp != -1;
case nsMediaExpression::eMax:
return cmp != 1;
case nsMediaExpression::eEqual:
return cmp == 0;
}
NS_NOTREACHED("unexpected mRange");
return false;
}
void
nsMediaQueryResultCacheKey::AddExpression(const nsMediaExpression* aExpression,
bool aExpressionMatches)
{
const nsMediaFeature *feature = aExpression->mFeature;
FeatureEntry *entry = nullptr;
for (uint32_t i = 0; i < mFeatureCache.Length(); ++i) {
if (mFeatureCache[i].mFeature == feature) {
entry = &mFeatureCache[i];
break;
}
}
if (!entry) {
entry = mFeatureCache.AppendElement();
if (!entry) {
return; /* out of memory */
}
entry->mFeature = feature;
}
ExpressionEntry eentry = { *aExpression, aExpressionMatches };
entry->mExpressions.AppendElement(eentry);
}
bool
nsMediaQueryResultCacheKey::Matches(nsPresContext* aPresContext) const
{
if (aPresContext->Medium() != mMedium) {
return false;
}
for (uint32_t i = 0; i < mFeatureCache.Length(); ++i) {
const FeatureEntry *entry = &mFeatureCache[i];
nsCSSValue actual;
entry->mFeature->mGetter(aPresContext->Document(), entry->mFeature, actual);
for (uint32_t j = 0; j < entry->mExpressions.Length(); ++j) {
const ExpressionEntry &eentry = entry->mExpressions[j];
if (eentry.mExpression.Matches(aPresContext, actual) !=
eentry.mExpressionMatches) {
return false;
}
}
}
return true;
}
bool
nsDocumentRuleResultCacheKey::AddMatchingRule(css::DocumentRule* aRule)
{
MOZ_ASSERT(!mFinalized);
return mMatchingRules.AppendElement(aRule);
}
void
nsDocumentRuleResultCacheKey::Finalize()
{
mMatchingRules.Sort();
#ifdef DEBUG
mFinalized = true;
#endif
}
#ifdef DEBUG
static bool
ArrayIsSorted(const nsTArray<css::DocumentRule*>& aRules)
{
for (size_t i = 1; i < aRules.Length(); i++) {
if (aRules[i - 1] > aRules[i]) {
return false;
}
}
return true;
}
#endif
bool
nsDocumentRuleResultCacheKey::Matches(
nsPresContext* aPresContext,
const nsTArray<css::DocumentRule*>& aRules) const
{
MOZ_ASSERT(mFinalized);
MOZ_ASSERT(ArrayIsSorted(mMatchingRules));
MOZ_ASSERT(ArrayIsSorted(aRules));
#ifdef DEBUG
for (css::DocumentRule* rule : mMatchingRules) {
MOZ_ASSERT(aRules.ContainsSorted(rule),
"aRules must contain all rules in mMatchingRules");
}
#endif
// First check that aPresContext matches all the rules listed in
// mMatchingRules.
for (css::DocumentRule* rule : mMatchingRules) {
if (!rule->UseForPresentation(aPresContext)) {
return false;
}
}
// Then check that all the rules in aRules that aren't also in
// mMatchingRules do not match.
// pointer to matching rules
auto pm = mMatchingRules.begin();
auto pm_end = mMatchingRules.end();
// pointer to all rules
auto pr = aRules.begin();
auto pr_end = aRules.end();
// mMatchingRules and aRules are both sorted by their pointer values,
// so we can iterate over the two lists simultaneously.
while (pr < pr_end) {
while (pm < pm_end && *pm < *pr) {
++pm;
}
if (pm >= pm_end || *pm != *pr) {
if ((*pr)->UseForPresentation(aPresContext)) {
return false;
}
}
++pr;
}
return true;
}
#ifdef DEBUG
void
nsDocumentRuleResultCacheKey::List(FILE* aOut, int32_t aIndent) const
{
for (css::DocumentRule* rule : mMatchingRules) {
nsCString str;
for (int32_t i = 0; i < aIndent; i++) {
str.AppendLiteral(" ");
}
str.AppendLiteral("{ ");
nsString condition;
rule->GetConditionText(condition);
AppendUTF16toUTF8(condition, str);
str.AppendLiteral(" }\n");
fprintf_stderr(aOut, "%s", str.get());
}
}
#endif
size_t
nsDocumentRuleResultCacheKey::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = 0;
n += mMatchingRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
return n;
}
void
nsMediaQuery::AppendToString(nsAString& aString) const
{
if (mHadUnknownExpression) {
aString.AppendLiteral("not all");
return;
}
NS_ASSERTION(!mNegated || !mHasOnly, "can't have not and only");
NS_ASSERTION(!mTypeOmitted || (!mNegated && !mHasOnly),
"can't have not or only when type is omitted");
if (!mTypeOmitted) {
if (mNegated) {
aString.AppendLiteral("not ");
} else if (mHasOnly) {
aString.AppendLiteral("only ");
}
aString.Append(nsDependentAtomString(mMediaType));
}
for (uint32_t i = 0, i_end = mExpressions.Length(); i < i_end; ++i) {
if (i > 0 || !mTypeOmitted)
aString.AppendLiteral(" and ");
aString.Append('(');
const nsMediaExpression &expr = mExpressions[i];
const nsMediaFeature *feature = expr.mFeature;
if (feature->mReqFlags & nsMediaFeature::eHasWebkitPrefix) {
aString.AppendLiteral("-webkit-");
}
if (expr.mRange == nsMediaExpression::eMin) {
aString.AppendLiteral("min-");
} else if (expr.mRange == nsMediaExpression::eMax) {
aString.AppendLiteral("max-");
}
aString.Append(nsDependentAtomString(*feature->mName));
if (expr.mValue.GetUnit() != eCSSUnit_Null) {
aString.AppendLiteral(": ");
switch (feature->mValueType) {
case nsMediaFeature::eLength:
NS_ASSERTION(expr.mValue.IsLengthUnit(), "bad unit");
// Use 'width' as a property that takes length values
// written in the normal way.
expr.mValue.AppendToString(eCSSProperty_width, aString);
break;
case nsMediaFeature::eInteger:
case nsMediaFeature::eBoolInteger:
NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Integer,
"bad unit");
// Use 'z-index' as a property that takes integer values
// written without anything extra.
expr.mValue.AppendToString(eCSSProperty_z_index, aString);
break;
case nsMediaFeature::eFloat:
{
NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Number,
"bad unit");
// Use 'line-height' as a property that takes float values
// written in the normal way.
expr.mValue.AppendToString(eCSSProperty_line_height, aString);
}
break;
case nsMediaFeature::eIntRatio:
{
NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Array,
"bad unit");
nsCSSValue::Array *array = expr.mValue.GetArrayValue();
NS_ASSERTION(array->Count() == 2, "unexpected length");
NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
"bad unit");
NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Integer,
"bad unit");
array->Item(0).AppendToString(eCSSProperty_z_index, aString);
aString.Append('/');
array->Item(1).AppendToString(eCSSProperty_z_index, aString);
}
break;
case nsMediaFeature::eResolution:
{
aString.AppendFloat(expr.mValue.GetFloatValue());
if (expr.mValue.GetUnit() == eCSSUnit_Inch) {
aString.AppendLiteral("dpi");
} else if (expr.mValue.GetUnit() == eCSSUnit_Pixel) {
aString.AppendLiteral("dppx");
} else {
NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Centimeter,
"bad unit");
aString.AppendLiteral("dpcm");
}
}
break;
case nsMediaFeature::eEnumerated:
NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Enumerated,
"bad unit");
AppendASCIItoUTF16(
nsCSSProps::ValueToKeyword(expr.mValue.GetIntValue(),
feature->mData.mKeywordTable),
aString);
break;
case nsMediaFeature::eIdent:
expr.mValue.AppendToString(eCSSProperty_DOM, aString);
break;
}
}
aString.Append(')');
}
}
nsMediaQuery*
nsMediaQuery::Clone() const
{
return new nsMediaQuery(*this);
}
bool
nsMediaQuery::Matches(nsPresContext* aPresContext,
nsMediaQueryResultCacheKey* aKey) const
{
if (mHadUnknownExpression)
return false;
bool match =
mMediaType == aPresContext->Medium() || mMediaType == nsGkAtoms::all;
for (uint32_t i = 0, i_end = mExpressions.Length(); match && i < i_end; ++i) {
const nsMediaExpression &expr = mExpressions[i];
nsCSSValue actual;
expr.mFeature->mGetter(aPresContext->Document(), expr.mFeature, actual);
match = expr.Matches(aPresContext, actual);
if (aKey) {
aKey->AddExpression(&expr, match);
}
}
return match == !mNegated;
}
nsMediaList::nsMediaList()
{
}
nsMediaList::~nsMediaList()
{
}
void
nsMediaList::GetText(nsAString& aMediaText)
{
aMediaText.Truncate();
for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
nsMediaQuery* query = mArray[i];
query->AppendToString(aMediaText);
if (i + 1 < i_end) {
aMediaText.AppendLiteral(", ");
}
}
}
// XXXbz this is so ill-defined in the spec, it's not clear quite what
// it should be doing....
void
nsMediaList::SetText(const nsAString& aMediaText)
{
nsCSSParser parser;
parser.ParseMediaList(aMediaText, nullptr, 0, this);
}
bool
nsMediaList::Matches(nsPresContext* aPresContext,
nsMediaQueryResultCacheKey* aKey) const
{
for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
if (mArray[i]->Matches(aPresContext, aKey)) {
return true;
}
}
return mArray.IsEmpty();
}
already_AddRefed<dom::MediaList>
nsMediaList::Clone()
{
RefPtr<nsMediaList> result = new nsMediaList();
result->mArray.AppendElements(mArray.Length());
for (uint32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
result->mArray[i] = mArray[i]->Clone();
MOZ_ASSERT(result->mArray[i]);
}
return result.forget();
}
void
nsMediaList::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aReturn)
{
if (aIndex < Length()) {
aFound = true;
aReturn.Truncate();
mArray[aIndex]->AppendToString(aReturn);
} else {
aFound = false;
SetDOMStringToNull(aReturn);
}
}
nsresult
nsMediaList::Delete(const nsAString& aOldMedium)
{
if (aOldMedium.IsEmpty())
return NS_ERROR_DOM_NOT_FOUND_ERR;
for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
nsMediaQuery* query = mArray[i];
nsAutoString buf;
query->AppendToString(buf);
if (buf == aOldMedium) {
mArray.RemoveElementAt(i);
return NS_OK;
}
}
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
nsresult
nsMediaList::Append(const nsAString& aNewMedium)
{
if (aNewMedium.IsEmpty())
return NS_ERROR_DOM_NOT_FOUND_ERR;
Delete(aNewMedium);
nsresult rv = NS_OK;
nsTArray<nsAutoPtr<nsMediaQuery> > buf;
mArray.SwapElements(buf);
SetText(aNewMedium);
if (mArray.Length() == 1) {
nsMediaQuery *query = mArray[0].forget();
if (!buf.AppendElement(query)) {
delete query;
rv = NS_ERROR_OUT_OF_MEMORY;
}
}
mArray.SwapElements(buf);
return rv;
}

Просмотреть файл

@ -1,294 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* representation of media lists used when linking to style sheets or by
* @media rules
*/
#ifndef nsMediaList_h_
#define nsMediaList_h_
#include "nsAutoPtr.h"
#include "nsTArray.h"
#include "nsAtom.h"
#include "nsCSSValue.h"
#include "nsStringFwd.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/MediaList.h"
class nsPresContext;
struct nsMediaFeature;
namespace mozilla {
namespace css {
class DocumentRule;
} // namespace css
} // namespace mozilla
struct nsMediaExpression {
enum Range { eMin, eMax, eEqual };
const nsMediaFeature *mFeature;
Range mRange;
nsCSSValue mValue;
// aActualValue must be obtained from mFeature->mGetter
bool Matches(nsPresContext* aPresContext,
const nsCSSValue& aActualValue) const;
bool operator==(const nsMediaExpression& aOther) const {
return mFeature == aOther.mFeature && // pointer equality fine (atom-like)
mRange == aOther.mRange &&
mValue == aOther.mValue;
}
bool operator!=(const nsMediaExpression& aOther) const {
return !(*this == aOther);
}
};
/**
* An nsMediaQueryResultCacheKey records what feature/value combinations
* a set of media query results are valid for. This allows the caller
* to quickly learn whether a prior result of media query evaluation is
* still valid (e.g., due to a window size change) without rerunning all
* of the evaluation and rebuilding the list of rules.
*
* This object may not be used after any media rules in any of the
* sheets it was given to have been modified. However, this is
* generally not a problem since ClearRuleCascades is called on the
* sheet whenever this happens, and these objects are stored inside the
* rule cascades. (FIXME: We're not actually doing this all the time.)
*
* The implementation could be further optimized in the future to store
* ranges (combinations of less-than, less-than-or-equal, greater-than,
* greater-than-or-equal, equal, not-equal, present, not-present) for
* each feature rather than simply storing the list of expressions.
* However, this requires combining any such ranges.
*/
class nsMediaQueryResultCacheKey {
public:
explicit nsMediaQueryResultCacheKey(nsAtom* aMedium)
: mMedium(aMedium)
{}
/**
* Record that aExpression was tested while building the cached set
* that this cache key is for, and that aExpressionMatches was whether
* it matched.
*/
void AddExpression(const nsMediaExpression* aExpression,
bool aExpressionMatches);
bool Matches(nsPresContext* aPresContext) const;
bool HasFeatureConditions() const {
return !mFeatureCache.IsEmpty();
}
/**
* An operator== that implements list equality, which isn't quite as
* good as set equality, but catches the trivial equality cases.
*/
bool operator==(const nsMediaQueryResultCacheKey& aOther) const {
return mMedium == aOther.mMedium &&
mFeatureCache == aOther.mFeatureCache;
}
bool operator!=(const nsMediaQueryResultCacheKey& aOther) const {
return !(*this == aOther);
}
private:
struct ExpressionEntry {
// FIXME: if we were better at maintaining invariants about clearing
// rule cascades when media lists change, this could be a |const
// nsMediaExpression*| instead.
nsMediaExpression mExpression;
bool mExpressionMatches;
bool operator==(const ExpressionEntry& aOther) const {
return mExpression == aOther.mExpression &&
mExpressionMatches == aOther.mExpressionMatches;
}
bool operator!=(const ExpressionEntry& aOther) const {
return !(*this == aOther);
}
};
struct FeatureEntry {
const nsMediaFeature *mFeature;
InfallibleTArray<ExpressionEntry> mExpressions;
bool operator==(const FeatureEntry& aOther) const {
return mFeature == aOther.mFeature &&
mExpressions == aOther.mExpressions;
}
bool operator!=(const FeatureEntry& aOther) const {
return !(*this == aOther);
}
};
RefPtr<nsAtom> mMedium;
nsTArray<FeatureEntry> mFeatureCache;
};
/**
* nsDocumentRuleResultCacheKey is analagous to nsMediaQueryResultCacheKey
* and stores the result of matching the @-moz-document rules from a set
* of style sheets. nsCSSRuleProcessor builds up an
* nsDocumentRuleResultCacheKey as it visits the @-moz-document rules
* while building its RuleCascadeData.
*
* Rather than represent the result using a list of both the matching and
* non-matching rules, we just store the matched rules. The assumption is
* that in situations where we have a large number of rules -- such as the
* thousands added by AdBlock Plus -- that only a small number will be
* matched. Thus to check if the nsDocumentRuleResultCacheKey matches a
* given nsPresContext, we also need the entire list of @-moz-document
* rules to know which rules must not match.
*/
class nsDocumentRuleResultCacheKey
{
public:
#ifdef DEBUG
nsDocumentRuleResultCacheKey()
: mFinalized(false) {}
#endif
bool AddMatchingRule(mozilla::css::DocumentRule* aRule);
bool Matches(nsPresContext* aPresContext,
const nsTArray<mozilla::css::DocumentRule*>& aRules) const;
bool operator==(const nsDocumentRuleResultCacheKey& aOther) const {
MOZ_ASSERT(mFinalized);
MOZ_ASSERT(aOther.mFinalized);
return mMatchingRules == aOther.mMatchingRules;
}
bool operator!=(const nsDocumentRuleResultCacheKey& aOther) const {
return !(*this == aOther);
}
void Swap(nsDocumentRuleResultCacheKey& aOther) {
mMatchingRules.SwapElements(aOther.mMatchingRules);
#ifdef DEBUG
std::swap(mFinalized, aOther.mFinalized);
#endif
}
void Finalize();
#ifdef DEBUG
void List(FILE* aOut = stdout, int32_t aIndex = 0) const;
#endif
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
private:
nsTArray<mozilla::css::DocumentRule*> mMatchingRules;
#ifdef DEBUG
bool mFinalized;
#endif
};
class nsMediaQuery {
public:
nsMediaQuery()
: mNegated(false)
, mHasOnly(false)
, mTypeOmitted(false)
, mHadUnknownExpression(false)
{
}
private:
// for Clone only
nsMediaQuery(const nsMediaQuery& aOther)
: mNegated(aOther.mNegated)
, mHasOnly(aOther.mHasOnly)
, mTypeOmitted(aOther.mTypeOmitted)
, mHadUnknownExpression(aOther.mHadUnknownExpression)
, mMediaType(aOther.mMediaType)
, mExpressions(aOther.mExpressions)
{
MOZ_ASSERT(mExpressions.Length() == aOther.mExpressions.Length());
}
public:
void SetNegated() { mNegated = true; }
void SetHasOnly() { mHasOnly = true; }
void SetTypeOmitted() { mTypeOmitted = true; }
void SetHadUnknownExpression() { mHadUnknownExpression = true; }
void SetType(nsAtom* aMediaType) {
NS_ASSERTION(aMediaType,
"expected non-null");
mMediaType = aMediaType;
}
// Return a new nsMediaExpression in the array for the caller to fill
// in. The caller must either fill it in completely, or call
// SetHadUnknownExpression on this nsMediaQuery.
// Returns null on out-of-memory.
nsMediaExpression* NewExpression() { return mExpressions.AppendElement(); }
void AppendToString(nsAString& aString) const;
nsMediaQuery* Clone() const;
// Does this query apply to the presentation?
// If |aKey| is non-null, add cache information to it.
bool Matches(nsPresContext* aPresContext,
nsMediaQueryResultCacheKey* aKey) const;
private:
bool mNegated;
bool mHasOnly; // only needed for serialization
bool mTypeOmitted; // only needed for serialization
bool mHadUnknownExpression;
RefPtr<nsAtom> mMediaType;
nsTArray<nsMediaExpression> mExpressions;
};
class nsMediaList final : public mozilla::dom::MediaList
{
public:
nsMediaList();
void GetText(nsAString& aMediaText) final;
void SetText(const nsAString& aMediaText) final;
bool Matches(nsPresContext* aPresContext) const final {
return Matches(aPresContext, nullptr);
}
// Does this query apply to the presentation?
// If |aKey| is non-null, add cache information to it.
bool Matches(nsPresContext* aPresContext,
nsMediaQueryResultCacheKey* aKey) const;
#ifdef DEBUG
bool IsServo() const final { return false; }
#endif
void AppendQuery(nsAutoPtr<nsMediaQuery>& aQuery) {
// Takes ownership of aQuery
mArray.AppendElement(aQuery.forget());
}
already_AddRefed<mozilla::dom::MediaList> Clone() final;
nsMediaQuery* MediumAt(int32_t aIndex) { return mArray[aIndex]; }
void Clear() { mArray.Clear(); }
// WebIDL
uint32_t Length() final { return mArray.Length(); }
void IndexedGetter(uint32_t aIndex, bool& aFound,
nsAString& aReturn) final;
protected:
~nsMediaList();
nsresult Delete(const nsAString & aOldMedium) final;
nsresult Append(const nsAString & aOldMedium) final;
InfallibleTArray<nsAutoPtr<nsMediaQuery> > mArray;
};
#endif /* !defined(nsMediaList_h_) */

Просмотреть файл

@ -1,156 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* A class that computes and caches the indices used for :nth-* pseudo-class
* matching.
*/
#include "nsNthIndexCache.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/NodeInfoInlines.h"
nsNthIndexCache::nsNthIndexCache()
{
}
nsNthIndexCache::~nsNthIndexCache()
{
}
void
nsNthIndexCache::Reset()
{
mCaches[0][0].clear();
mCaches[0][1].clear();
mCaches[1][0].clear();
mCaches[1][1].clear();
}
inline bool
nsNthIndexCache::SiblingMatchesElement(nsIContent* aSibling, Element* aElement,
bool aIsOfType)
{
return aSibling->IsElement() &&
(!aIsOfType ||
aSibling->NodeInfo()->NameAndNamespaceEquals(aElement->NodeInfo()));
}
inline bool
nsNthIndexCache::IndexDeterminedFromPreviousSibling(nsIContent* aSibling,
Element* aChild,
bool aIsOfType,
bool aIsFromEnd,
const Cache& aCache,
int32_t& aResult)
{
if (SiblingMatchesElement(aSibling, aChild, aIsOfType)) {
Cache::Ptr siblingEntry = aCache.lookup(aSibling);
if (siblingEntry) {
int32_t siblingIndex = siblingEntry->value();
NS_ASSERTION(siblingIndex != 0,
"How can a non-anonymous node have an anonymous sibling?");
if (siblingIndex > 0) {
// At this point, aResult is a count of how many elements matching
// aChild we have seen after aSibling, including aChild itself.
// |siblingIndex| is the index of aSibling.
// So if aIsFromEnd, we want |aResult = siblingIndex - aResult| and
// otherwise we want |aResult = siblingIndex + aResult|.
aResult = siblingIndex + aResult * (1 - 2 * aIsFromEnd);
return true;
}
}
++aResult;
}
return false;
}
int32_t
nsNthIndexCache::GetNthIndex(Element* aChild, bool aIsOfType,
bool aIsFromEnd, bool aCheckEdgeOnly)
{
if (aChild->IsRootOfAnonymousSubtree()) {
return 0;
}
Cache& cache = mCaches[aIsOfType][aIsFromEnd];
if (!cache.initialized() && !cache.init()) {
// Give up and just don't match.
return 0;
}
Cache::AddPtr entry = cache.lookupForAdd(aChild);
// Default the value to -2 when adding
if (!entry && !cache.add(entry, aChild, -2)) {
// No good; don't match.
return 0;
}
int32_t& slot = entry->value();
if (slot != -2 && (slot != -1 || aCheckEdgeOnly)) {
return slot;
}
int32_t result = 1;
if (aCheckEdgeOnly) {
// The caller only cares whether or not the result is 1, so we can
// stop as soon as we see any other elements that match us.
if (aIsFromEnd) {
for (nsIContent *cur = aChild->GetNextSibling();
cur;
cur = cur->GetNextSibling()) {
if (SiblingMatchesElement(cur, aChild, aIsOfType)) {
result = -1;
break;
}
}
} else {
for (nsIContent *cur = aChild->GetPreviousSibling();
cur;
cur = cur->GetPreviousSibling()) {
if (SiblingMatchesElement(cur, aChild, aIsOfType)) {
result = -1;
break;
}
}
}
} else {
// In the common case, we already have a cached index for one of
// our previous siblings, so check that first.
for (nsIContent *cur = aChild->GetPreviousSibling();
cur;
cur = cur->GetPreviousSibling()) {
if (IndexDeterminedFromPreviousSibling(cur, aChild, aIsOfType,
aIsFromEnd, cache, result)) {
slot = result;
return result;
}
}
// Now if aIsFromEnd we lose: need to actually compute our index,
// since looking at previous siblings wouldn't have told us
// anything about it. Note that it doesn't make sense to do cache
// lookups on our following siblings, since chances are the cache
// is not primed for them.
if (aIsFromEnd) {
result = 1;
for (nsIContent *cur = aChild->GetNextSibling();
cur;
cur = cur->GetNextSibling()) {
if (SiblingMatchesElement(cur, aChild, aIsOfType)) {
++result;
}
}
}
}
slot = result;
return result;
}

Просмотреть файл

@ -1,97 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
#include "nsRuleData.h"
#include "nsAttrValueInlines.h"
#include "nsCSSParser.h"
#include "nsPresContext.h"
#include "nsStyleContextInlines.h"
#include "mozilla/GeckoStyleContext.h"
#include "mozilla/Poison.h"
#include <stdint.h>
using namespace mozilla;
inline size_t
nsRuleData::GetPoisonOffset()
{
// Fill in mValueOffsets such that mValueStorage + mValueOffsets[i]
// will yield the frame poison value for all uninitialized value
// offsets.
static_assert(sizeof(uintptr_t) == sizeof(size_t),
"expect uintptr_t and size_t to be the same size");
static_assert(uintptr_t(-1) > uintptr_t(0),
"expect uintptr_t to be unsigned");
static_assert(size_t(-1) > size_t(0), "expect size_t to be unsigned");
uintptr_t framePoisonValue = mozPoisonValue();
return size_t(framePoisonValue - uintptr_t(mValueStorage)) /
sizeof(nsCSSValue);
}
nsRuleData::nsRuleData(uint32_t aSIDs,
nsCSSValue* aValueStorage,
GeckoStyleContext* aStyleContext)
: GenericSpecifiedValues(StyleBackendType::Gecko, aStyleContext->PresContext()->Document(), aSIDs)
, mStyleContext(aStyleContext)
, mPresContext(aStyleContext->PresContext())
, mValueStorage(aValueStorage)
{
#ifndef MOZ_VALGRIND
size_t framePoisonOffset = GetPoisonOffset();
for (size_t i = 0; i < nsStyleStructID_Length; ++i) {
mValueOffsets[i] = framePoisonOffset;
}
#endif
}
void
nsRuleData::SetFontFamily(const nsString& aValue)
{
nsCSSValue* family = ValueForFontFamily();
nsCSSParser parser;
parser.ParseFontFamilyListString(aValue, nullptr, 0, *family);
}
void
nsRuleData::SetTextDecorationColorOverride()
{
nsCSSValue* decoration = ValueForTextDecorationLine();
int32_t newValue = NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL;
if (decoration->GetUnit() == eCSSUnit_Enumerated) {
newValue |= decoration->GetIntValue();
}
decoration->SetIntValue(newValue, eCSSUnit_Enumerated);
}
void
nsRuleData::SetBackgroundImage(nsAttrValue& aValue)
{
nsCSSValue* backImage = ValueForBackgroundImage();
// If the value is an image, or it is a URL and we attempted a load,
// put it in the style tree.
if (aValue.Type() == nsAttrValue::eURL) {
aValue.LoadImage(mDocument);
}
if (aValue.Type() == nsAttrValue::eImage) {
nsCSSValueList* list = backImage->SetListValue();
list->mValue.SetImageValue(aValue.GetImageValue());
}
}
#ifdef DEBUG
nsRuleData::~nsRuleData()
{
#ifndef MOZ_VALGRIND
// assert nothing in mSIDs has poison value
size_t framePoisonOffset = GetPoisonOffset();
for (size_t i = 0; i < nsStyleStructID_Length; ++i) {
MOZ_ASSERT(!(mSIDs & (1 << i)) || mValueOffsets[i] != framePoisonOffset,
"value in SIDs was left with poison offset");
}
#endif
}
#endif

Просмотреть файл

@ -1,198 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* temporary (expanded) representation of property-value pairs used to
* hold data from matched rules during style data computation.
*/
#ifndef nsRuleData_h_
#define nsRuleData_h_
#include "mozilla/CSSVariableDeclarations.h"
#include "mozilla/GenericSpecifiedValues.h"
#include "mozilla/RuleNodeCacheConditions.h"
#include "mozilla/SheetType.h"
#include "nsAutoPtr.h"
#include "nsCSSProps.h"
#include "nsCSSValue.h"
#include "nsStyleStructFwd.h"
class nsPresContext;
struct nsRuleData;
namespace mozilla {
class GeckoStyleContext;
} // namespace mozilla
typedef void (*nsPostResolveFunc)(void* aStyleStruct, nsRuleData* aData);
struct nsRuleData final : mozilla::GenericSpecifiedValues
{
mozilla::RuleNodeCacheConditions mConditions;
bool mIsImportantRule;
mozilla::SheetType mLevel;
mozilla::GeckoStyleContext* const mStyleContext;
nsPresContext* const mPresContext;
// We store nsCSSValues needed to compute the data for one or more
// style structs (specified by the bitfield mSIDs). These are stored
// in a single array allocation (which our caller allocates; see
// AutoCSSValueArray) The offset of each property |prop| in
// mValueStorage is the sum of
// mValueOffsets[nsCSSProps::kSIDTable[prop]] and
// nsCSSProps::PropertyIndexInStruct(prop). The only place we gather
// more than one style struct's data at a time is
// nsRuleNode::HasAuthorSpecifiedRules; therefore some code that we
// know is not called from HasAuthorSpecifiedRules assumes that the
// mValueOffsets for the one struct in mSIDs is zero.
nsCSSValue* const mValueStorage; // our user owns this array
size_t mValueOffsets[nsStyleStructID_Length];
nsAutoPtr<mozilla::CSSVariableDeclarations> mVariables;
nsRuleData(uint32_t aSIDs,
nsCSSValue* aValueStorage,
mozilla::GeckoStyleContext* aStyleContext);
#ifdef DEBUG
~nsRuleData();
#else
~nsRuleData() {}
#endif
/**
* Return a pointer to the value object within |this| corresponding
* to property |aProperty|.
*
* This function must only be called if the given property is in
* mSIDs.
*/
nsCSSValue* ValueFor(nsCSSPropertyID aProperty)
{
MOZ_ASSERT(aProperty < eCSSProperty_COUNT_no_shorthands,
"invalid or shorthand property");
nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty];
size_t indexInStruct = nsCSSProps::PropertyIndexInStruct(aProperty);
// This should really be nsCachedStyleData::GetBitForSID, but we can't
// include that here since it includes us.
MOZ_ASSERT(mSIDs & (1 << sid),
"calling nsRuleData::ValueFor on property not in mSIDs");
MOZ_ASSERT(indexInStruct != size_t(-1), "logical property");
return mValueStorage + mValueOffsets[sid] + indexInStruct;
}
const nsCSSValue* ValueFor(nsCSSPropertyID aProperty) const
{
return const_cast<nsRuleData*>(this)->ValueFor(aProperty);
}
/**
* Getters like ValueFor(aProperty), but for each property by name
* (ValueForBackgroundColor, etc.), and more efficient than ValueFor.
* These use the names used for the property on DOM interfaces (the
* 'method' field in nsCSSPropList.h).
*
* Like ValueFor(), the caller must check that the property is within
* mSIDs.
*/
#define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_
#define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, \
kwtable_, stylestruct_, stylestructoffset_, animtype_) \
nsCSSValue* ValueFor##method_() { \
MOZ_ASSERT(mSIDs & NS_STYLE_INHERIT_BIT(stylestruct_), \
"Calling nsRuleData::ValueFor" #method_ " without " \
"NS_STYLE_INHERIT_BIT(" #stylestruct_ " in mSIDs."); \
nsStyleStructID sid = eStyleStruct_##stylestruct_; \
size_t indexInStruct = \
nsCSSProps::PropertyIndexInStruct(eCSSProperty_##id_); \
MOZ_ASSERT(indexInStruct != size_t(-1), \
"logical property"); \
return mValueStorage + mValueOffsets[sid] + indexInStruct; \
} \
const nsCSSValue* ValueFor##method_() const { \
return const_cast<nsRuleData*>(this)->ValueFor##method_(); \
}
#define CSS_PROP_LIST_EXCLUDE_LOGICAL
#include "nsCSSPropList.h"
#undef CSS_PROP_LIST_EXCLUDE_LOGICAL
#undef CSS_PROP
#undef CSS_PROP_PUBLIC_OR_PRIVATE
// GenericSpecifiedValues overrides
bool PropertyIsSet(nsCSSPropertyID aId)
{
return ValueFor(aId)->GetUnit() != eCSSUnit_Null;
}
void SetIdentStringValue(nsCSSPropertyID aId, const nsString& aValue)
{
ValueFor(aId)->SetStringValue(aValue, eCSSUnit_Ident);
}
void SetIdentAtomValue(nsCSSPropertyID aId, nsAtom* aValue)
{
RefPtr<nsAtom> atom = aValue;
ValueFor(aId)->SetAtomIdentValue(atom.forget());
}
void SetKeywordValue(nsCSSPropertyID aId, int32_t aValue)
{
ValueFor(aId)->SetIntValue(aValue, eCSSUnit_Enumerated);
}
void SetIntValue(nsCSSPropertyID aId, int32_t aValue)
{
ValueFor(aId)->SetIntValue(aValue, eCSSUnit_Integer);
}
void SetPixelValue(nsCSSPropertyID aId, float aValue)
{
ValueFor(aId)->SetFloatValue(aValue, eCSSUnit_Pixel);
}
void SetLengthValue(nsCSSPropertyID aId, nsCSSValue aValue)
{
nsCSSValue* val = ValueFor(aId);
*val = aValue;
}
void SetNumberValue(nsCSSPropertyID aId, float aValue)
{
ValueFor(aId)->SetFloatValue(aValue, eCSSUnit_Number);
}
void SetPercentValue(nsCSSPropertyID aId, float aValue)
{
ValueFor(aId)->SetPercentValue(aValue);
}
void SetAutoValue(nsCSSPropertyID aId) {
ValueFor(aId)->SetAutoValue();
}
void SetCurrentColor(nsCSSPropertyID aId)
{
ValueFor(aId)->SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
}
void SetColorValue(nsCSSPropertyID aId, nscolor aValue)
{
ValueFor(aId)->SetColorValue(aValue);
}
void SetFontFamily(const nsString& aValue);
void SetTextDecorationColorOverride();
void SetBackgroundImage(nsAttrValue& aValue);
private:
inline size_t GetPoisonOffset();
};
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,109 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* a class that walks the lexicographic tree of rule nodes as style
* rules are matched
*/
#ifndef nsRuleWalker_h_
#define nsRuleWalker_h_
#include "nsRuleNode.h"
#include "nsIStyleRule.h"
#include "Declaration.h"
#include "nsQueryObject.h"
class nsRuleWalker {
public:
nsRuleNode* CurrentNode() { return mCurrent; }
void SetCurrentNode(nsRuleNode* aNode) {
NS_ASSERTION(aNode, "Must have node here!");
mCurrent = aNode;
}
nsPresContext* PresContext() const { return mRoot->PresContext(); }
protected:
void DoForward(nsIStyleRule* aRule) {
mCurrent = mCurrent->Transition(aRule, mLevel, mImportance);
MOZ_ASSERT(mCurrent, "Transition messed up");
}
public:
void Forward(nsIStyleRule* aRule) {
NS_PRECONDITION(!RefPtr<mozilla::css::Declaration>(do_QueryObject(aRule)),
"Calling the wrong Forward() overload");
DoForward(aRule);
}
void Forward(mozilla::css::Declaration* aRule) {
DoForward(aRule);
mCheckForImportantRules =
mCheckForImportantRules && !aRule->HasImportantData();
}
// ForwardOnPossiblyCSSRule should only be used by callers that have
// an explicit list of rules they need to walk, with the list
// already containing any important rules they care about.
void ForwardOnPossiblyCSSRule(nsIStyleRule* aRule) {
DoForward(aRule);
}
void Reset() { mCurrent = mRoot; }
bool AtRoot() { return mCurrent == mRoot; }
void SetLevel(mozilla::SheetType aLevel, bool aImportance,
bool aCheckForImportantRules) {
NS_ASSERTION(!aCheckForImportantRules || !aImportance,
"Shouldn't be checking for important rules while walking "
"important rules");
mLevel = aLevel;
mImportance = aImportance;
mCheckForImportantRules = aCheckForImportantRules;
}
mozilla::SheetType GetLevel() const { return mLevel; }
bool GetImportance() const { return mImportance; }
bool GetCheckForImportantRules() const { return mCheckForImportantRules; }
bool AuthorStyleDisabled() const { return mAuthorStyleDisabled; }
// We define the visited-relevant link to be the link that is the
// nearest self-or-ancestor to the node being matched.
enum VisitedHandlingType {
// Do rule matching as though all links are unvisited.
eRelevantLinkUnvisited,
// Do rule matching as though the relevant link is visited and all
// other links are unvisited.
eRelevantLinkVisited,
// Do rule matching as though a rule should match if it would match
// given any set of visitedness states. (used by users other than
// nsRuleWalker)
eLinksVisitedOrUnvisited
};
private:
nsRuleNode* mCurrent; // Our current position. Never null.
nsRuleNode* mRoot; // The root of the tree we're walking.
mozilla::SheetType mLevel;
bool mImportance;
bool mCheckForImportantRules; // If true, check for important rules as
// we walk and set to false if we find
// one.
bool mAuthorStyleDisabled;
public:
nsRuleWalker(nsRuleNode* aRoot, bool aAuthorStyleDisabled)
: mCurrent(aRoot)
, mRoot(aRoot)
, mAuthorStyleDisabled(aAuthorStyleDisabled)
{
NS_ASSERTION(mCurrent, "Caller screwed up and gave us null node");
MOZ_COUNT_CTOR(nsRuleWalker);
}
~nsRuleWalker() { MOZ_COUNT_DTOR(nsRuleWalker); }
};
#endif /* !defined(nsRuleWalker_h_) */

Просмотреть файл

@ -18,7 +18,6 @@
#include "nsStyleStructInlines.h"
#include "nsString.h"
#include "nsPresContext.h"
#include "nsIStyleRule.h"
#include "nsCOMPtr.h"
#include "nsIPresShell.h"

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,716 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
/*
* the container for the style sheets that apply to a presentation, and
* the internal API that the style system exposes for creating (and
* potentially re-creating) style contexts
*/
#ifndef nsStyleSet_h_
#define nsStyleSet_h_
#include "mozilla/AtomArray.h"
#include "mozilla/Attributes.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/LinkedList.h"
#include "mozilla/MediaFeatureChange.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/ServoTypes.h"
#include "mozilla/SheetType.h"
#include "nsIStyleRuleProcessor.h"
#include "nsBindingManager.h"
#include "nsRuleNode.h"
#include "nsTArray.h"
#include "nsCOMArray.h"
#include "nsIStyleRule.h"
#include "nsCSSAnonBoxes.h"
class gfxFontFeatureValueSet;
class nsCSSKeyframesRule;
class nsCSSFontFeatureValuesRule;
class nsCSSPageRule;
class nsCSSCounterStyleRule;
class nsICSSPseudoComparator;
class nsRuleWalker;
struct ElementDependentRuleProcessorData;
struct nsFontFaceRuleContainer;
struct TreeMatchContext;
namespace mozilla {
class CSSStyleSheet;
enum class CSSPseudoElementType : uint8_t;
class EventStates;
namespace dom {
class ShadowRoot;
} // namespace dom
} // namespace mozilla
class nsEmptyStyleRule final : public nsIStyleRule
{
private:
~nsEmptyStyleRule() {}
public:
NS_DECL_ISUPPORTS
virtual void MapRuleInfoInto(nsRuleData* aRuleData) override;
virtual bool MightMapInheritedStyleData() override;
virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
nsCSSValue* aValue) override;
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
};
class nsInitialStyleRule final : public nsIStyleRule
{
private:
~nsInitialStyleRule() {}
public:
NS_DECL_ISUPPORTS
virtual void MapRuleInfoInto(nsRuleData* aRuleData) override;
virtual bool MightMapInheritedStyleData() override;
virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
nsCSSValue* aValue) override;
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
};
class nsDisableTextZoomStyleRule final : public nsIStyleRule
{
private:
~nsDisableTextZoomStyleRule() {}
public:
NS_DECL_ISUPPORTS
virtual void MapRuleInfoInto(nsRuleData* aRuleData) override;
virtual bool MightMapInheritedStyleData() override;
virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
nsCSSValue* aValue) override;
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
};
// The style set object is created by the document viewer and ownership is
// then handed off to the PresShell. Only the PresShell should delete a
// style set.
class nsStyleSet final
{
public:
nsStyleSet();
~nsStyleSet();
void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
void Init(nsPresContext* aPresContext);
nsRuleNode* GetRuleTree() { return mRuleTree; }
// get a style context for a non-pseudo frame.
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleFor(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aParentContext);
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleFor(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aParentContext,
mozilla::LazyComputeBehavior)
{
return ResolveStyleFor(aElement, aParentContext);
}
already_AddRefed<mozilla::GeckoStyleContext>
ResolveCleanStyleFor(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aParentContext,
mozilla::LazyComputeBehavior)
{
return ResolveStyleFor(aElement, aParentContext);
}
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleFor(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aParentContext,
TreeMatchContext& aTreeMatchContext);
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleFor(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aParentContext,
mozilla::LazyComputeBehavior aMayCompute,
TreeMatchContext& aTreeMatchContext)
{
return ResolveStyleFor(aElement, aParentContext, aTreeMatchContext);
}
// Get a style context (with the given parent) for the
// sequence of style rules in the |aRules| array.
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleForRules(mozilla::GeckoStyleContext* aParentContext,
const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules);
// Get a style context that represents aBaseContext, but as though
// it additionally matched the rules in the aRules array (in that
// order, as more specific than any other rules).
//
// One of the following must hold:
// 1. The resulting style context must be used only on a temporary
// basis, and it must never be put into the style context tree
// (and, in particular, we must never call
// ResolveStyleWithReplacement with it as the old context, which
// might happen if it is put in the style context tree), or
// 2. The additional rules must be appropriate for the transitions
// level of the cascade, which is the highest level of the cascade.
// (This is the case for one current caller, the cover rule used
// for CSS transitions.)
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleByAddingRules(mozilla::GeckoStyleContext* aBaseContext,
const nsCOMArray<nsIStyleRule> &aRules);
// Resolve style by making replacements in the list of style rules as
// described by aReplacements, but otherwise maintaining the status
// quo.
// aPseudoElement must follow the same rules as for
// ResolvePseudoElementStyle, and be null for non-pseudo-element cases
enum { // flags for aFlags
// Skip starting CSS animations that result from the style.
eSkipStartingAnimations = (1<<0),
};
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleWithReplacement(mozilla::dom::Element* aElement,
mozilla::dom::Element* aPseudoElement,
mozilla::GeckoStyleContext* aNewParentContext,
mozilla::GeckoStyleContext* aOldStyleContext,
nsRestyleHint aReplacements,
uint32_t aFlags = 0);
// Resolve style by returning a style context with the specified
// animation data removed. It is allowable to remove all animation
// data with eRestyle_AllHintsWithAnimations, or by using any other
// hints that are allowed by ResolveStyleWithReplacement.
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleByRemovingAnimation(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aStyleContext,
nsRestyleHint aWhichToRemove);
// Similar to the above, but resolving style without all animation data in
// the first place.
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleWithoutAnimation(mozilla::dom::Element* aTarget,
mozilla::GeckoStyleContext* aParentContext);
// Pseudo-element version of the above, ResolveStyleWithoutAnimation.
already_AddRefed<mozilla::GeckoStyleContext>
ResolvePseudoElementStyleWithoutAnimation(
mozilla::dom::Element* aParentElement,
mozilla::CSSPseudoElementType aType,
mozilla::GeckoStyleContext* aParentContext,
mozilla::dom::Element* aPseudoElement);
// Get a style context for a text node (which no rules will match).
//
// The returned style context will have nsCSSAnonBoxes::mozText as its pseudo.
//
// (Perhaps mozText should go away and we shouldn't even create style
// contexts for such content nodes, when text-combine-upright is not
// present. However, not doing any rule matching for them is a first step.)
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleForText(nsIContent* aTextNode, mozilla::GeckoStyleContext* aParentContext);
// Get a style context for a first-letter continuation (which no rules will
// match).
//
// The returned style context will have
// nsCSSAnonBoxes::firstLetterContinuation as its pseudo.
//
// (Perhaps nsCSSAnonBoxes::firstLetterContinuation should go away and we
// shouldn't even create style contexts for such frames. However, not doing
// any rule matching for them is a first step. And right now we do use this
// style context for some things)
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleForFirstLetterContinuation(mozilla::GeckoStyleContext* aParentContext);
// Get a style context for a placeholder frame (which no rules will match).
//
// The returned style context will have nsCSSAnonBoxes::oofPlaceholder as
// its pseudo.
//
// (Perhaps nsCSSAnonBoxes::oofPlaceholder should go away and we shouldn't
// even create style contexts for placeholders. However, not doing any rule
// matching for them is a first step.)
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleForPlaceholder();
// Get a style context for a pseudo-element. aParentElement must be
// non-null. aPseudoID is the CSSPseudoElementType for the
// pseudo-element. aPseudoElement must be non-null if the pseudo-element
// type is one that allows user action pseudo-classes after it or allows
// style attributes; otherwise, it is ignored.
already_AddRefed<mozilla::GeckoStyleContext>
ResolvePseudoElementStyle(mozilla::dom::Element* aParentElement,
mozilla::CSSPseudoElementType aType,
mozilla::GeckoStyleContext* aParentContext,
mozilla::dom::Element* aPseudoElement);
// This functions just like ResolvePseudoElementStyle except that it will
// return nullptr if there are no explicit style rules for that
// pseudo element.
already_AddRefed<mozilla::GeckoStyleContext>
ProbePseudoElementStyle(mozilla::dom::Element* aParentElement,
mozilla::CSSPseudoElementType aType,
mozilla::GeckoStyleContext* aParentContext);
already_AddRefed<mozilla::GeckoStyleContext>
ProbePseudoElementStyle(mozilla::dom::Element* aParentElement,
mozilla::CSSPseudoElementType aType,
mozilla::GeckoStyleContext* aParentContext,
TreeMatchContext& aTreeMatchContext);
/**
* Bit-flags that can be passed to GetContext in its parameter 'aFlags'.
*/
enum {
eNoFlags = 0,
eIsLink = 1 << 0,
eIsVisitedLink = 1 << 1,
eDoAnimation = 1 << 2,
// Indicates that we should skip the flex/grid item specific chunk of
// ApplyStyleFixups(). This is useful if our parent has "display: flex"
// or "display: grid" but we can tell we're not going to honor that (e.g. if
// it's the outer frame of a button widget, and we're the inline frame for
// the button's label).
eSkipParentDisplayBasedStyleFixup = 1 << 3
};
// Get a style context for an anonymous box. aPseudoTag is the pseudo-tag to
// use and must be non-null. It must be an anon box, and must be one that
// inherits style from the given aParentContext.
already_AddRefed<mozilla::GeckoStyleContext>
ResolveInheritingAnonymousBoxStyle(nsAtom* aPseudoTag,
mozilla::GeckoStyleContext* aParentContext);
// Get a style context for an anonymous box that does not inherit style from
// anything. aPseudoTag is the pseudo-tag to use and must be non-null. It
// must be an anon box, and must be a non-inheriting one.
already_AddRefed<mozilla::GeckoStyleContext>
ResolveNonInheritingAnonymousBoxStyle(nsAtom* aPseudoTag);
#ifdef MOZ_XUL
// Get a style context for a XUL tree pseudo. aPseudoTag is the
// pseudo-tag to use and must be non-null. aParentContent must be
// non-null.
already_AddRefed<mozilla::GeckoStyleContext>
ResolveXULTreePseudoStyle(mozilla::dom::Element* aParentElement,
nsICSSAnonBoxPseudo* aPseudoTag,
mozilla::GeckoStyleContext* aParentContext,
const mozilla::AtomArray& aInputWord);
#endif
// Append all the currently-active font face rules to aArray. Return
// true for success and false for failure.
bool AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray);
// Return the winning (in the cascade) @keyframes rule for the given name.
nsCSSKeyframesRule* KeyframesRuleForName(nsAtom* aName);
// Return the winning (in the cascade) @counter-style rule for the given name.
nsCSSCounterStyleRule* CounterStyleRuleForName(nsAtom* aName);
// Return gfxFontFeatureValueSet from font feature values rules.
already_AddRefed<gfxFontFeatureValueSet> BuildFontFeatureValueSet();
// Append all the currently-active font feature values rules to aArray.
// Return true for success and false for failure.
bool AppendFontFeatureValuesRules(
nsTArray<nsCSSFontFeatureValuesRule*>& aArray);
// Append all the currently-active page rules to aArray. Return
// true for success and false for failure.
bool AppendPageRules(nsTArray<nsCSSPageRule*>& aArray);
// Begin ignoring style context destruction, to avoid lots of unnecessary
// work on document teardown.
void BeginShutdown();
// Free all of the data associated with this style set.
void Shutdown();
void RuleAdded(mozilla::CSSStyleSheet& aSheet, mozilla::css::Rule&)
{
SheetChanged(aSheet);
}
void RuleRemoved(mozilla::CSSStyleSheet& aSheet, mozilla::css::Rule&)
{
SheetChanged(aSheet);
}
void RuleChanged(mozilla::CSSStyleSheet& aSheet, mozilla::css::Rule*)
{
SheetChanged(aSheet);
}
// Notes that a style sheet has changed.
void RecordStyleSheetChange(mozilla::CSSStyleSheet* aSheet,
mozilla::StyleSheet::ChangeType)
{
SheetChanged(*aSheet);
}
void SheetChanged(mozilla::CSSStyleSheet&);
// Notes that style sheets have changed in a shadow root.
void RecordShadowStyleChange(mozilla::dom::ShadowRoot& aShadowRoot);
bool StyleSheetsHaveChanged() const
{
return mStylesHaveChanged || !mChangedScopeStyleRoots.IsEmpty();
}
void InvalidateStyleForCSSRuleChanges();
// Get a new style context that lives in a different parent
// The new context will be the same as the old if the new parent is the
// same as the old parent.
// aElement should be non-null if this is a style context for an
// element or pseudo-element; in the latter case it should be the
// real element the pseudo-element is for.
already_AddRefed<mozilla::GeckoStyleContext>
ReparentStyleContext(mozilla::GeckoStyleContext* aStyleContext,
mozilla::GeckoStyleContext* aNewParentContext,
mozilla::dom::Element* aElement);
// Test if style is dependent on a document state.
bool HasDocumentStateDependentStyle(nsIContent* aContent,
mozilla::EventStates aStateMask);
// Test if style is dependent on content state
nsRestyleHint HasStateDependentStyle(mozilla::dom::Element* aElement,
mozilla::EventStates aStateMask);
nsRestyleHint HasStateDependentStyle(mozilla::dom::Element* aElement,
mozilla::CSSPseudoElementType aPseudoType,
mozilla::dom::Element* aPseudoElement,
mozilla::EventStates aStateMask);
// Test if style is dependent on the presence of an attribute.
nsRestyleHint HasAttributeDependentStyle(mozilla::dom::Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute,
int32_t aModType,
bool aAttrHasChanged,
const nsAttrValue* aOtherValue,
mozilla::RestyleHintData&
aRestyleHintDataResult);
/*
* Do any processing that needs to happen as a result of a change in
* the characteristics of the medium, and return restyle hint needed
* for the change.
*/
nsRestyleHint MediumFeaturesChanged(mozilla::MediaFeatureChangeReason);
// APIs to manipulate the style sheet lists. The sheets in each
// list are stored with the most significant sheet last.
nsresult AppendStyleSheet(mozilla::SheetType aType,
mozilla::CSSStyleSheet* aSheet);
nsresult PrependStyleSheet(mozilla::SheetType aType,
mozilla::CSSStyleSheet* aSheet);
nsresult RemoveStyleSheet(mozilla::SheetType aType,
mozilla::CSSStyleSheet* aSheet);
nsresult ReplaceSheets(mozilla::SheetType aType,
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aNewSheets);
nsresult InsertStyleSheetBefore(mozilla::SheetType aType,
mozilla::CSSStyleSheet* aNewSheet,
mozilla::CSSStyleSheet* aReferenceSheet);
// Enable/Disable entire author style level (Doc & PresHint levels)
bool GetAuthorStyleDisabled() const
{
return mAuthorStyleDisabled;
}
void SetAuthorStyleDisabled(bool aStyleDisabled);
int32_t SheetCount(mozilla::SheetType aType) const {
return mSheets[aType].Length();
}
mozilla::CSSStyleSheet* StyleSheetAt(mozilla::SheetType aType,
int32_t aIndex) const {
return mSheets[aType][aIndex];
}
void AppendAllXBLStyleSheets(nsTArray<mozilla::StyleSheet*>& aArray) const;
nsresult RemoveDocStyleSheet(mozilla::CSSStyleSheet* aSheet);
nsresult AddDocStyleSheet(mozilla::CSSStyleSheet* aSheet,
nsIDocument* aDocument);
void BeginUpdate();
nsresult EndUpdate();
// Methods for reconstructing the tree; BeginReconstruct basically moves the
// old rule tree root and style context roots out of the way,
// and EndReconstruct destroys the old rule tree when we're done
nsresult BeginReconstruct();
// Note: EndReconstruct should not be called if BeginReconstruct fails
void EndReconstruct();
bool IsInRuleTreeReconstruct() const {
return mInReconstruct;
}
void RootStyleContextAdded() {
++mRootStyleContextCount;
}
void RootStyleContextRemoved() {
MOZ_ASSERT(mRootStyleContextCount > 0);
--mRootStyleContextCount;
}
// Notify the style set that a rulenode is no longer in use, or was
// just created and is not in use yet.
static const uint32_t kGCInterval = 300;
void RuleNodeUnused(nsRuleNode* aNode, bool aMayGC) {
++mUnusedRuleNodeCount;
mUnusedRuleNodeList.insertBack(aNode);
if (aMayGC && mUnusedRuleNodeCount >= kGCInterval && !mInGC && !mInReconstruct) {
GCRuleTrees();
}
}
// Notify the style set that a rulenode that wasn't in use now is
void RuleNodeInUse(nsRuleNode* aNode) {
MOZ_ASSERT(mUnusedRuleNodeCount > 0);
--mUnusedRuleNodeCount;
aNode->removeFrom(mUnusedRuleNodeList);
}
// Returns true if a restyle of the document is needed due to cloning
// sheet inners.
bool EnsureUniqueInnerOnCSSSheets();
// Called by StyleSheet::EnsureUniqueInner to let us know it cloned
// its inner.
void SetNeedsRestyleAfterEnsureUniqueInner() {
mNeedsRestyleAfterEnsureUniqueInner = true;
}
nsIStyleRule* InitialStyleRule();
bool HasRuleProcessorUsedByMultipleStyleSets(mozilla::SheetType aSheetType);
// Tells the RestyleManager for the document using this style set
// to drop any nsCSSSelector pointers it has.
void ClearSelectors();
void SetUsesViewportUnits(bool aValue) {
mUsesViewportUnits = aValue;
}
private:
nsStyleSet(const nsStyleSet& aCopy) = delete;
nsStyleSet& operator=(const nsStyleSet& aCopy) = delete;
// Free all the rules with reference-count zero. This continues iterating
// over the free list until it is empty, which allows immediate collection
// of nodes whose reference-count drops to zero during the destruction of
// a child node. This allows the collection of entire trees at once, since
// children hold their parents alive.
void GCRuleTrees();
nsresult DirtyRuleProcessors(mozilla::SheetType aType);
// Update the rule processor list after a change to the style sheet list.
void GatherRuleProcessors(mozilla::SheetType aType);
void AddImportantRules(nsRuleNode* aCurrLevelNode,
nsRuleNode* aLastPrevLevelNode,
nsRuleWalker* aRuleWalker);
// Move aRuleWalker forward by the appropriate rule if we need to add
// a rule due to property restrictions on pseudo-elements.
void WalkRestrictionRule(mozilla::CSSPseudoElementType aPseudoType,
nsRuleWalker* aRuleWalker);
void WalkDisableTextZoomRule(mozilla::dom::Element* aElement,
nsRuleWalker* aRuleWalker);
#ifdef DEBUG
// Just like AddImportantRules except it doesn't actually add anything; it
// just asserts that there are no important rules between aCurrLevelNode and
// aLastPrevLevelNode.
void AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
nsRuleNode* aLastPrevLevelNode);
// Just like AddImportantRules except it doesn't actually add anything; it
// just asserts that there are no CSS rules between aCurrLevelNode and
// aLastPrevLevelNode. Mostly useful for the preshint level.
void AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
nsRuleNode* aLastPrevLevelNode);
#endif
// Enumerate the rules in a way that cares about the order of the
// rules.
// aElement is the element the rules are for. It might be null. aData
// is the closure to pass to aCollectorFunc. If aContent is not null,
// aData must be a RuleProcessorData*
void FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
RuleProcessorData* aData, mozilla::dom::Element* aElement,
nsRuleWalker* aRuleWalker);
// Enumerate all the rules in a way that doesn't care about the order
// of the rules and break out if the enumeration is halted.
void WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
ElementDependentRuleProcessorData* aData,
bool aWalkAllXBLStylesheets);
// Helper for ResolveStyleWithReplacement
// aPseudoElement must follow the same rules as for
// ResolvePseudoElementStyle, and be null for non-pseudo-element cases
nsRuleNode* RuleNodeWithReplacement(mozilla::dom::Element* aElement,
mozilla::dom::Element* aPseudoElement,
nsRuleNode* aOldRuleNode,
mozilla::CSSPseudoElementType aPseudoType,
nsRestyleHint aReplacements);
already_AddRefed<mozilla::GeckoStyleContext>
GetContext(mozilla::GeckoStyleContext* aParentContext,
nsRuleNode* aRuleNode,
nsRuleNode* aVisitedRuleNode,
nsAtom* aPseudoTag,
mozilla::CSSPseudoElementType aPseudoType,
mozilla::dom::Element* aElementForAnimation,
uint32_t aFlags);
enum AnimationFlag {
eWithAnimation,
eWithoutAnimation,
};
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleForInternal(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aParentContext,
TreeMatchContext& aTreeMatchContext,
AnimationFlag aAnimationFlag);
already_AddRefed<mozilla::GeckoStyleContext>
ResolvePseudoElementStyleInternal(mozilla::dom::Element* aParentElement,
mozilla::CSSPseudoElementType aType,
mozilla::GeckoStyleContext* aParentContext,
mozilla::dom::Element* aPseudoElement,
AnimationFlag aAnimationFlag);
nsPresContext* PresContext() { return mRuleTree->PresContext(); }
// Clear our cached mNonInheritingStyleContexts. We do this when we want to
// make sure those style contexts won't live too long (e.g. at ruletree
// reconstruct or shutdown time).
void ClearNonInheritingStyleContexts();
// The sheets in each array in mSheets are stored with the most significant
// sheet last.
// The arrays for ePresHintSheet, eStyleAttrSheet, eTransitionSheet,
// eAnimationSheet are always empty.
// (FIXME: We should reduce the storage needed for them.)
mozilla::EnumeratedArray<mozilla::SheetType, mozilla::SheetType::Count,
nsTArray<RefPtr<mozilla::CSSStyleSheet>>> mSheets;
mozilla::EnumeratedArray<mozilla::SheetType, mozilla::SheetType::Count,
nsCOMPtr<nsIStyleRuleProcessor>> mRuleProcessors;
RefPtr<nsBindingManager> mBindingManager;
RefPtr<nsRuleNode> mRuleTree; // This is the root of our rule tree. It is a
// lexicographic tree of matched rules that style
// contexts use to look up properties.
// List of subtrees rooted at style scope roots that need to be restyled.
// When a change to a scoped style sheet is made, we add the style scope
// root to this array rather than setting mStylesHaveChanged = true, since
// we know we don't need to restyle the whole document. However, if in the
// same update block we have already had other changes that require
// the whole document to be restyled (i.e., mStylesHaveChanged is already
// true), then we don't bother adding the scope root here.
AutoTArray<RefPtr<mozilla::dom::Element>,1> mChangedScopeStyleRoots;
uint16_t mBatching;
// Indicates that the whole document must be restyled. Changes to scoped
// style sheets are recorded in mChangedScopeStyleRoots rather than here
// in mStylesHaveChanged.
unsigned mStylesHaveChanged : 1;
unsigned mInShutdown : 1;
unsigned mInGC : 1;
unsigned mAuthorStyleDisabled: 1;
unsigned mInReconstruct : 1;
unsigned mNeedsRestyleAfterEnsureUniqueInner : 1;
// Does the associated document use viewport units (vw/vh/vmin/vmax)?
unsigned mUsesViewportUnits : 1;
unsigned mDirty : int(mozilla::SheetType::Count); // one bit per sheet type
uint32_t mRootStyleContextCount;
#ifdef DEBUG
// In debug builds, we stash a weak pointer here to the old root during
// reconstruction. During GC, we check for this pointer, and null it out
// when we encounter it. This allows us to assert that the old root (and
// thus all of its subtree) was GCed after reconstruction, which implies
// that there are no style contexts holding on to old rule nodes.
nsRuleNode* mOldRootNode;
#endif
// Track our rule nodes with zero refcount. When this hits a threshold, we
// sweep and free. Keeping unused rule nodes around for a bit allows us to
// reuse them in many cases.
mozilla::LinkedList<nsRuleNode> mUnusedRuleNodeList;
uint32_t mUnusedRuleNodeCount;
// Empty style rules to force things that restrict which properties
// apply into different branches of the rule tree.
RefPtr<nsEmptyStyleRule> mFirstLineRule, mFirstLetterRule, mPlaceholderRule;
// Style rule which sets all properties to their initial values for
// determining when context-sensitive values are in use.
RefPtr<nsInitialStyleRule> mInitialStyleRule;
// Style rule that sets the internal -x-text-zoom property on
// <svg:text> elements to disable the effect of text zooming.
RefPtr<nsDisableTextZoomStyleRule> mDisableTextZoomStyleRule;
// Stores pointers to our cached style contexts for non-inheriting anonymous
// boxes.
mozilla::EnumeratedArray<nsCSSAnonBoxes::NonInheriting,
nsCSSAnonBoxes::NonInheriting::_Count,
RefPtr<mozilla::GeckoStyleContext>> mNonInheritingStyleContexts;
};
#ifdef MOZILLA_INTERNAL_API
inline
void nsRuleNode::AddRef()
{
if (mRefCnt++ == 0) {
MOZ_ASSERT(mPresContext->StyleSet()->IsGecko(),
"ServoStyleSets should not have rule nodes");
mPresContext->StyleSet()->AsGecko()->RuleNodeInUse(this);
}
}
inline
void nsRuleNode::Release()
{
if (--mRefCnt == 0) {
MOZ_ASSERT(mPresContext->StyleSet()->IsGecko(),
"ServoStyleSets should not have rule nodes");
mPresContext->StyleSet()->AsGecko()->RuleNodeUnused(this, /* aMayGC = */ true);
}
}
#endif
#endif

Просмотреть файл

@ -583,13 +583,13 @@ def stylo_config(value, _):
option('--disable-stylo-build-bindgen',
help='Disable build-time bindgen for Stylo')
@depends(stylo_config, '--enable-stylo-build-bindgen', '--enable-compile-environment')
def building_stylo_bindgen(stylo_config, bindgen_enabled, compile_environment):
@depends('--enable-stylo-build-bindgen', '--enable-compile-environment')
def building_stylo_bindgen(bindgen_enabled, compile_environment):
if not compile_environment:
return False
if not bindgen_enabled:
return False
return stylo_config.build
return True
# We support setting up the appropriate options for Stylo's build-time
# bindings generation via setting LLVM_CONFIG or by providing explicit