зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
d838e97ff8
Коммит
f3e6656403
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче