diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js
index 3d8689226c..c255f60614 100644
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -339,7 +339,6 @@ pref("image.mem.surfacecache.max_size_kb", 131072); // 128MB
pref("image.mem.surfacecache.size_factor", 8); // 1/8 of main memory
pref("image.mem.surfacecache.discard_factor", 2); // Discard 1/2 of the surface cache at a time.
pref("image.mem.surfacecache.min_expiration_ms", 86400000); // 24h, we rely on the out of memory hook
-pref("image.onload.decode.limit", 24); /* don't decode more than 24 images eagerly */
// XXX this isn't a good check for "are touch events supported", but
// we don't really have a better one at the moment.
diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp
index 204b4f54f7..672d67ccd2 100644
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -51,15 +51,17 @@ Animation::WrapObject(JSContext* aCx, JS::Handle aGivenProto)
void
Animation::SetEffect(KeyframeEffectReadOnly* aEffect)
{
+ RefPtr kungFuDeathGrip(this);
+
if (mEffect == aEffect) {
return;
}
if (mEffect) {
- mEffect->SetParentTime(Nullable());
+ mEffect->SetAnimation(nullptr);
}
mEffect = aEffect;
if (mEffect) {
- mEffect->SetParentTime(GetCurrentTime());
+ mEffect->SetAnimation(this);
}
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
@@ -934,7 +936,6 @@ void
Animation::UpdateEffect()
{
if (mEffect) {
- mEffect->SetParentTime(GetCurrentTime());
UpdateRelevance();
}
}
@@ -1045,6 +1046,46 @@ Animation::EffectEnd() const
+ mEffect->GetComputedTiming().mActiveDuration;
}
+TimeStamp
+Animation::AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const
+{
+ // Initializes to null. Return the same object every time to benefit from
+ // return-value-optimization.
+ TimeStamp result;
+
+ // We *don't* check for mTimeline->TracksWallclockTime() here because that
+ // method only tells us if the timeline times can be converted to
+ // TimeStamps that can be compared to TimeStamp::Now() or not, *not*
+ // whether the timelines can be converted to TimeStamp values at all.
+ //
+ // Since we never compare the result of this method with TimeStamp::Now()
+ // it is ok to return values even if mTimeline->TracksWallclockTime() is
+ // false. Furthermore, we want to be able to use this method when the
+ // refresh driver is under test control (in which case TracksWallclockTime()
+ // will return false).
+ //
+ // Once we introduce timelines that are not time-based we will need to
+ // differentiate between them here and determine how to sort their events.
+ if (!mTimeline) {
+ return result;
+ }
+
+ // Check the time is convertible to a timestamp
+ if (aTime == TimeDuration::Forever() ||
+ mPlaybackRate == 0.0 ||
+ mStartTime.IsNull()) {
+ return result;
+ }
+
+ // Invert the standard relation:
+ // animation time = (timeline time - start time) * playback rate
+ TimeDuration timelineTime =
+ TimeDuration(aTime).MultDouble(1.0 / mPlaybackRate) + mStartTime.Value();
+
+ result = mTimeline->ToTimeStamp(timelineTime);
+ return result;
+}
+
nsIDocument*
Animation::GetRenderedDocument() const
{
diff --git a/dom/animation/Animation.h b/dom/animation/Animation.h
index 66aa395bb8..f0bf1929a4 100644
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -232,11 +232,11 @@ public:
bool HasInPlayEffect() const
{
- return GetEffect() && GetEffect()->IsInPlay(*this);
+ return GetEffect() && GetEffect()->IsInPlay();
}
bool HasCurrentEffect() const
{
- return GetEffect() && GetEffect()->IsCurrent(*this);
+ return GetEffect() && GetEffect()->IsCurrent();
}
bool IsInEffect() const
{
@@ -357,6 +357,7 @@ protected:
bool IsPossiblyOrphanedPendingAnimation() const;
StickyTimeDuration EffectEnd() const;
+ TimeStamp AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const;
nsIDocument* GetRenderedDocument() const;
nsPresContext* GetPresContext() const;
diff --git a/dom/animation/KeyframeEffect.cpp b/dom/animation/KeyframeEffect.cpp
index 15882164e8..3e2dce93bb 100644
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -6,10 +6,14 @@
#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
+#include "mozilla/dom/PropertyIndexedKeyframesBinding.h"
#include "mozilla/FloatingPoint.h"
+#include "mozilla/StyleAnimationValue.h"
#include "AnimationCommon.h"
+#include "nsCSSParser.h"
#include "nsCSSPropertySet.h"
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
+#include "nsCSSValue.h"
#include "nsStyleUtil.h"
namespace mozilla {
@@ -109,7 +113,8 @@ namespace dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly,
AnimationEffectReadOnly,
- mTarget)
+ mTarget,
+ mAnimation)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(KeyframeEffectReadOnly,
AnimationEffectReadOnly)
@@ -143,20 +148,27 @@ KeyframeEffectReadOnly::WrapObject(JSContext* aCx,
}
void
-KeyframeEffectReadOnly::SetParentTime(Nullable aParentTime)
-{
- mParentTime = aParentTime;
-}
-
-void
-KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming,
- Animation& aOwningAnimation)
+KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming)
{
if (mTiming == aTiming) {
return;
}
mTiming = aTiming;
- aOwningAnimation.NotifyEffectTimingUpdated();
+ if (mAnimation) {
+ mAnimation->NotifyEffectTimingUpdated();
+ }
+}
+
+Nullable
+KeyframeEffectReadOnly::GetLocalTime() const
+{
+ // Since the *animation* start time is currently always zero, the local
+ // time is equal to the parent time.
+ Nullable result;
+ if (mAnimation) {
+ result = mAnimation->GetCurrentTime();
+ }
+ return result;
}
ComputedTiming
@@ -306,9 +318,9 @@ KeyframeEffectReadOnly::ActiveDuration(const AnimationTiming& aTiming)
// https://w3c.github.io/web-animations/#in-play
bool
-KeyframeEffectReadOnly::IsInPlay(const Animation& aAnimation) const
+KeyframeEffectReadOnly::IsInPlay() const
{
- if (aAnimation.PlayState() == AnimationPlayState::Finished) {
+ if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
return false;
}
@@ -317,9 +329,9 @@ KeyframeEffectReadOnly::IsInPlay(const Animation& aAnimation) const
// https://w3c.github.io/web-animations/#current
bool
-KeyframeEffectReadOnly::IsCurrent(const Animation& aAnimation) const
+KeyframeEffectReadOnly::IsCurrent() const
{
- if (aAnimation.PlayState() == AnimationPlayState::Finished) {
+ if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
return false;
}
@@ -336,6 +348,12 @@ KeyframeEffectReadOnly::IsInEffect() const
return computedTiming.mProgress != ComputedTiming::kNullProgress;
}
+void
+KeyframeEffectReadOnly::SetAnimation(Animation* aAnimation)
+{
+ mAnimation = aAnimation;
+}
+
const AnimationProperty*
KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSProperty aProperty) const
{
@@ -495,6 +513,12 @@ KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSProperty aProperty,
}
}
+// We need to define this here since Animation is an incomplete type
+// (forward-declared) in the header.
+KeyframeEffectReadOnly::~KeyframeEffectReadOnly()
+{
+}
+
void
KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
{
@@ -503,112 +527,1193 @@ KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
}
}
-struct KeyframeValueEntry
+#ifdef DEBUG
+void
+DumpAnimationProperties(nsTArray& aAnimationProperties)
+{
+ for (auto& p : aAnimationProperties) {
+ printf("%s\n", nsCSSProps::GetStringValue(p.mProperty).get());
+ for (auto& s : p.mSegments) {
+ nsString fromValue, toValue;
+ StyleAnimationValue::UncomputeValue(p.mProperty,
+ s.mFromValue,
+ fromValue);
+ StyleAnimationValue::UncomputeValue(p.mProperty,
+ s.mToValue,
+ toValue);
+ printf(" %f..%f: %s..%s\n", s.mFromKey, s.mToKey,
+ NS_ConvertUTF16toUTF8(fromValue).get(),
+ NS_ConvertUTF16toUTF8(toValue).get());
+ }
+ }
+}
+#endif
+
+/* static */ AnimationTiming
+KeyframeEffectReadOnly::ConvertKeyframeEffectOptions(
+ const Optional& aOptions)
+{
+ AnimationTiming animationTiming;
+
+ // The spec says to treat auto durations as 0 until a later version of
+ // the spec says otherwise. Bug 1215406 is for handling a
+ // KeyframeEffectOptions object and not just an offset.
+ if (aOptions.WasPassed()) {
+ animationTiming.mIterationDuration =
+ TimeDuration::FromMilliseconds(aOptions.Value());
+ } else {
+ animationTiming.mIterationDuration = TimeDuration(0);
+ }
+ animationTiming.mIterationCount = 1.0f;
+ animationTiming.mDirection = NS_STYLE_ANIMATION_DIRECTION_NORMAL;
+ animationTiming.mFillMode = NS_STYLE_ANIMATION_FILL_MODE_NONE;
+
+ return animationTiming;
+}
+
+/**
+ * A property and StyleAnimationValue pair.
+ */
+struct KeyframeValue
+{
+ nsCSSProperty mProperty;
+ StyleAnimationValue mValue;
+};
+
+/**
+ * Represents a relative position for a value in a keyframe animation.
+ */
+enum class ValuePosition
+{
+ First, // value at 0 used for reverse filling
+ Left, // value coming in to a given offset
+ Right, // value coming out from a given offset
+ Last // value at 1 used for forward filling
+};
+
+/**
+ * A single value in a keyframe animation, used by GetFrames to produce a
+ * minimal set of Keyframe objects.
+ */
+struct OrderedKeyframeValueEntry : KeyframeValue
{
float mOffset;
- nsCSSProperty mProperty;
- nsString mValue;
const ComputedTimingFunction* mTimingFunction;
+ ValuePosition mPosition;
- bool operator==(const KeyframeValueEntry& aRhs) const
+ bool SameKeyframe(const OrderedKeyframeValueEntry& aOther) const
{
- NS_ASSERTION(mOffset != aRhs.mOffset || mProperty != aRhs.mProperty,
- "shouldn't have duplicate (offset, property) pairs");
+ return mOffset == aOther.mOffset &&
+ !!mTimingFunction == !!aOther.mTimingFunction &&
+ (!mTimingFunction || *mTimingFunction == *aOther.mTimingFunction) &&
+ mPosition == aOther.mPosition;
+ }
+
+ struct ForKeyframeGenerationComparator
+ {
+ static bool Equals(const OrderedKeyframeValueEntry& aLhs,
+ const OrderedKeyframeValueEntry& aRhs)
+ {
+ return aLhs.SameKeyframe(aRhs) &&
+ aLhs.mProperty == aRhs.mProperty;
+ }
+ static bool LessThan(const OrderedKeyframeValueEntry& aLhs,
+ const OrderedKeyframeValueEntry& aRhs)
+ {
+ // First, sort by offset.
+ if (aLhs.mOffset != aRhs.mOffset) {
+ return aLhs.mOffset < aRhs.mOffset;
+ }
+
+ // Second, by position.
+ if (aLhs.mPosition != aRhs.mPosition) {
+ return aLhs.mPosition < aRhs.mPosition;
+ }
+
+ // Third, by easing.
+ if (aLhs.mTimingFunction) {
+ if (aRhs.mTimingFunction) {
+ int32_t order = aLhs.mTimingFunction->Compare(*aRhs.mTimingFunction);
+ if (order != 0) {
+ return order < 0;
+ }
+ } else {
+ return true;
+ }
+ } else {
+ if (aRhs.mTimingFunction) {
+ return false;
+ }
+ }
+
+ // Last, by property IDL name.
+ return nsCSSProps::PropertyIDLNameSortPosition(aLhs.mProperty) <
+ nsCSSProps::PropertyIDLNameSortPosition(aRhs.mProperty);
+ }
+ };
+};
+
+/**
+ * Data for a segment in a keyframe animation of a given property
+ * whose value is a StyleAnimationValue.
+ *
+ * KeyframeValueEntry is used in BuildAnimationPropertyListFromKeyframeSequence
+ * to gather data for each individual segment described by an author-supplied
+ * an IDL sequence value so that they can be parsed into mProperties.
+ */
+struct KeyframeValueEntry : KeyframeValue
+{
+ float mOffset;
+ ComputedTimingFunction mTimingFunction;
+
+ struct PropertyOffsetComparator
+ {
+ static bool Equals(const KeyframeValueEntry& aLhs,
+ const KeyframeValueEntry& aRhs)
+ {
+ return aLhs.mProperty == aRhs.mProperty &&
+ aLhs.mOffset == aRhs.mOffset;
+ }
+ static bool LessThan(const KeyframeValueEntry& aLhs,
+ const KeyframeValueEntry& aRhs)
+ {
+ // First, sort by property IDL name.
+ int32_t order = nsCSSProps::PropertyIDLNameSortPosition(aLhs.mProperty) -
+ nsCSSProps::PropertyIDLNameSortPosition(aRhs.mProperty);
+ if (order != 0) {
+ return order < 0;
+ }
+
+ // Then, by offset.
+ return aLhs.mOffset < aRhs.mOffset;
+ }
+ };
+};
+
+/**
+ * A property-values pair obtained from the open-ended properties
+ * discovered on a Keyframe or PropertyIndexedKeyframes object.
+ *
+ * Single values (as required by Keyframe, and as also supported
+ * on PropertyIndexedKeyframes) are stored as the only element in
+ * mValues.
+ */
+struct PropertyValuesPair
+{
+ nsCSSProperty mProperty;
+ nsTArray mValues;
+
+ class PropertyPriorityComparator
+ {
+ public:
+ PropertyPriorityComparator()
+ : mSubpropertyCountInitialized(false) {}
+
+ bool Equals(const PropertyValuesPair& aLhs,
+ const PropertyValuesPair& aRhs) const
+ {
+ return aLhs.mProperty == aRhs.mProperty;
+ }
+
+ bool LessThan(const PropertyValuesPair& aLhs,
+ const PropertyValuesPair& aRhs) const
+ {
+ bool isShorthandLhs = nsCSSProps::IsShorthand(aLhs.mProperty);
+ bool isShorthandRhs = nsCSSProps::IsShorthand(aRhs.mProperty);
+
+ if (isShorthandLhs) {
+ if (isShorthandRhs) {
+ // First, sort shorthands by the number of longhands they have.
+ uint32_t subpropCountLhs = SubpropertyCount(aLhs.mProperty);
+ uint32_t subpropCountRhs = SubpropertyCount(aRhs.mProperty);
+ if (subpropCountLhs != subpropCountRhs) {
+ return subpropCountLhs < subpropCountRhs;
+ }
+ // Otherwise, sort by IDL name below.
+ } else {
+ // Put longhands before shorthands.
+ return false;
+ }
+ } else {
+ if (isShorthandRhs) {
+ // Put longhands before shorthands.
+ return true;
+ }
+ }
+ // For two longhand properties, or two shorthand with the same number
+ // of longhand components, sort by IDL name.
+ return nsCSSProps::PropertyIDLNameSortPosition(aLhs.mProperty) <
+ nsCSSProps::PropertyIDLNameSortPosition(aRhs.mProperty);
+ }
+
+ uint32_t SubpropertyCount(nsCSSProperty aProperty) const
+ {
+ if (!mSubpropertyCountInitialized) {
+ PodZero(&mSubpropertyCount);
+ mSubpropertyCountInitialized = true;
+ }
+ if (mSubpropertyCount[aProperty] == 0) {
+ uint32_t count = 0;
+ CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
+ p, aProperty, nsCSSProps::eEnabledForAllContent) {
+ ++count;
+ }
+ mSubpropertyCount[aProperty] = count;
+ }
+ return mSubpropertyCount[aProperty];
+ }
+
+ private:
+ // Cache of shorthand subproperty counts.
+ mutable RangedArray<
+ uint32_t,
+ eCSSProperty_COUNT_no_shorthands,
+ eCSSProperty_COUNT - eCSSProperty_COUNT_no_shorthands> mSubpropertyCount;
+ mutable bool mSubpropertyCountInitialized;
+ };
+};
+
+/**
+ * The result of parsing a JS object as a Keyframe dictionary
+ * and getting its property-value pairs from its open-ended
+ * properties.
+ */
+struct OffsetIndexedKeyframe
+{
+ binding_detail::FastKeyframe mKeyframeDict;
+ nsTArray mPropertyValuePairs;
+};
+
+/**
+ * Parses a CSS value from
+ * aEasing into a ComputedTimingFunction. If parsing fails, aResult will
+ * be set to 'linear'.
+ */
+static void
+ParseEasing(Element* aTarget,
+ const nsAString& aEasing,
+ ComputedTimingFunction& aResult)
+{
+ nsIDocument* doc = aTarget->OwnerDoc();
+
+ nsCSSValue value;
+ nsCSSParser parser;
+ parser.ParseLonghandProperty(eCSSProperty_animation_timing_function,
+ aEasing,
+ doc->GetDocumentURI(),
+ doc->GetDocumentURI(),
+ doc->NodePrincipal(),
+ value);
+
+ switch (value.GetUnit()) {
+ case eCSSUnit_List: {
+ const nsCSSValueList* list = value.GetListValue();
+ if (list->mNext) {
+ // don't support a list of timing functions
+ break;
+ }
+ switch (list->mValue.GetUnit()) {
+ case eCSSUnit_Enumerated:
+ case eCSSUnit_Cubic_Bezier:
+ case eCSSUnit_Steps: {
+ nsTimingFunction timingFunction;
+ nsRuleNode::ComputeTimingFunction(list->mValue, timingFunction);
+ aResult.Init(timingFunction);
+ return;
+ }
+ default:
+ MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function list "
+ "item unit");
+ break;
+ }
+ break;
+ }
+ case eCSSUnit_Null:
+ case eCSSUnit_Inherit:
+ case eCSSUnit_Initial:
+ case eCSSUnit_Unset:
+ case eCSSUnit_TokenStream:
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function unit");
+ break;
+ }
+
+ aResult.Init(nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR));
+}
+
+/**
+ * An additional property (for a property-values pair) found on a Keyframe
+ * or PropertyIndexedKeyframes object.
+ */
+struct AdditionalProperty
+{
+ nsCSSProperty mProperty;
+ size_t mJsidIndex; // Index into |ids| in GetPropertyValuesPairs.
+
+ struct PropertyComparator
+ {
+ bool Equals(const AdditionalProperty& aLhs,
+ const AdditionalProperty& aRhs) const
+ {
+ return aLhs.mProperty == aRhs.mProperty;
+ }
+ bool LessThan(const AdditionalProperty& aLhs,
+ const AdditionalProperty& aRhs) const
+ {
+ return nsCSSProps::PropertyIDLNameSortPosition(aLhs.mProperty) <
+ nsCSSProps::PropertyIDLNameSortPosition(aRhs.mProperty);
+ }
+ };
+};
+
+/**
+ * Converts aValue to DOMString and appends it to aValues.
+ */
+static bool
+AppendValueAsString(JSContext* aCx,
+ nsTArray& aValues,
+ JS::Handle aValue)
+{
+ return ConvertJSValueToString(aCx, aValue, eStringify, eStringify,
+ *aValues.AppendElement());
+}
+
+// For the aAllowList parameter of AppendStringOrStringSequence and
+// GetPropertyValuesPairs.
+enum class ListAllowance { eDisallow, eAllow };
+
+/**
+ * Converts aValue to DOMString, if aAllowLists is eDisallow, or
+ * to (DOMString or sequence) if aAllowLists is aAllow.
+ * The resulting strings are appended to aValues.
+ */
+static bool
+AppendStringOrStringSequenceToArray(JSContext* aCx,
+ JS::Handle aValue,
+ ListAllowance aAllowLists,
+ nsTArray& aValues)
+{
+ if (aAllowLists == ListAllowance::eAllow && aValue.isObject()) {
+ // The value is an object, and we want to allow lists; convert
+ // aValue to (DOMString or sequence).
+ JS::ForOfIterator iter(aCx);
+ if (!iter.init(aValue, JS::ForOfIterator::AllowNonIterable)) {
+ return false;
+ }
+ if (iter.valueIsIterable()) {
+ // If the object is iterable, convert it to sequence.
+ JS::Rooted element(aCx);
+ for (;;) {
+ bool done;
+ if (!iter.next(&element, &done)) {
+ return false;
+ }
+ if (done) {
+ break;
+ }
+ if (!AppendValueAsString(aCx, aValues, element)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ // Either the object is not iterable, or aAllowLists doesn't want
+ // a list; convert it to DOMString.
+ if (!AppendValueAsString(aCx, aValues, aValue)) {
return false;
}
- bool operator<(const KeyframeValueEntry& aRhs) const
- {
- NS_ASSERTION(mOffset != aRhs.mOffset || mProperty != aRhs.mProperty,
- "shouldn't have duplicate (offset, property) pairs");
+ return true;
+}
- // First, sort by offset.
- if (mOffset != aRhs.mOffset) {
- return mOffset < aRhs.mOffset;
- }
+/**
+ * Reads the property-values pairs from the specified JS object.
+ *
+ * @param aObject The JS object to look at.
+ * @param aAllowLists If eAllow, values will be converted to
+ * (DOMString or sequence aObject,
+ ListAllowance aAllowLists,
+ nsTArray& aResult)
+{
+ nsTArray properties;
- // Second, by timing function.
- int32_t order = mTimingFunction->Compare(*aRhs.mTimingFunction);
- if (order != 0) {
- return order < 0;
- }
-
- // Last, by property IDL name.
- return nsCSSProps::PropertyIDLNameSortPosition(mProperty) <
- nsCSSProps::PropertyIDLNameSortPosition(aRhs.mProperty);
+ // Iterate over all the properties on aObject and append an
+ // entry to properties for them.
+ //
+ // We don't compare the jsids that we encounter with those for
+ // the explicit dictionary members, since we know that none
+ // of the CSS property IDL names clash with them.
+ JS::Rooted ids(aCx, JS::IdVector(aCx));
+ if (!JS_Enumerate(aCx, aObject, &ids)) {
+ return false;
}
-};
+ for (size_t i = 0, n = ids.length(); i < n; i++) {
+ nsAutoJSString propName;
+ if (!propName.init(aCx, ids[i])) {
+ return false;
+ }
+ nsCSSProperty property =
+ nsCSSProps::LookupPropertyByIDLName(propName,
+ nsCSSProps::eEnabledForAllContent);
+ if (property != eCSSProperty_UNKNOWN &&
+ nsCSSProps::kAnimTypeTable[property] != eStyleAnimType_None) {
+ AdditionalProperty* p = properties.AppendElement();
+ p->mProperty = property;
+ p->mJsidIndex = i;
+ }
+ }
+
+ // Sort the entries by IDL name and then get each value and
+ // convert it either to a DOMString or to a
+ // (DOMString or sequence), depending on aAllowLists,
+ // and build up aResult.
+ properties.Sort(AdditionalProperty::PropertyComparator());
+
+ for (AdditionalProperty& p : properties) {
+ JS::Rooted value(aCx);
+ if (!JS_GetPropertyById(aCx, aObject, ids[p.mJsidIndex], &value)) {
+ return false;
+ }
+ PropertyValuesPair* pair = aResult.AppendElement();
+ pair->mProperty = p.mProperty;
+ if (!AppendStringOrStringSequenceToArray(aCx, value, aAllowLists,
+ pair->mValues)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Converts a JS object wrapped by the given JS::ForIfIterator to an
+ * IDL sequence and stores the resulting OffsetIndexedKeyframe
+ * objects in aResult.
+ */
+static bool
+ConvertKeyframeSequence(JSContext* aCx,
+ JS::ForOfIterator& aIterator,
+ nsTArray& aResult)
+{
+ JS::Rooted value(aCx);
+ for (;;) {
+ bool done;
+ if (!aIterator.next(&value, &done)) {
+ return false;
+ }
+ if (done) {
+ break;
+ }
+ // Each value found when iterating the object must be an object
+ // or null/undefined (which gets treated as a default {} dictionary
+ // value).
+ if (!value.isObject() && !value.isNullOrUndefined()) {
+ ThrowErrorMessage(aCx, MSG_NOT_OBJECT,
+ "Element of sequence argument");
+ return false;
+ }
+ // Convert the JS value into a Keyframe dictionary value.
+ OffsetIndexedKeyframe* keyframe = aResult.AppendElement();
+ if (!keyframe->mKeyframeDict.Init(
+ aCx, value, "Element of sequence argument")) {
+ return false;
+ }
+ // Look for additional property-values pairs on the object.
+ if (value.isObject()) {
+ JS::Rooted object(aCx, &value.toObject());
+ if (!GetPropertyValuesPairs(aCx, object,
+ ListAllowance::eDisallow,
+ keyframe->mPropertyValuePairs)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * Checks that the given keyframes are loosely ordered (each keyframe's
+ * offset that is not null is greater than or equal to the previous
+ * non-null offset) and that all values are within the range [0.0, 1.0].
+ *
+ * @return true if the keyframes' offsets are correctly ordered and
+ * within range; false otherwise.
+ */
+static bool
+HasValidOffsets(const nsTArray& aKeyframes)
+{
+ double offset = 0.0;
+ for (const OffsetIndexedKeyframe& keyframe : aKeyframes) {
+ if (!keyframe.mKeyframeDict.mOffset.IsNull()) {
+ double thisOffset = keyframe.mKeyframeDict.mOffset.Value();
+ if (thisOffset < offset || thisOffset > 1.0f) {
+ return false;
+ }
+ offset = thisOffset;
+ }
+ }
+ return true;
+}
+
+/**
+ * Fills in any null offsets for the given keyframes by applying the
+ * "distribute" spacing algorithm.
+ *
+ * http://w3c.github.io/web-animations/#distribute-keyframe-spacing-mode
+ */
+static void
+ApplyDistributeSpacing(nsTArray& aKeyframes)
+{
+ // If the first or last keyframes have an unspecified offset,
+ // fill them in with 0% and 100%. If there is only a single keyframe,
+ // then it gets 100%.
+ if (aKeyframes.LastElement().mKeyframeDict.mOffset.IsNull()) {
+ aKeyframes.LastElement().mKeyframeDict.mOffset.SetValue(1.0);
+ }
+ if (aKeyframes[0].mKeyframeDict.mOffset.IsNull()) {
+ aKeyframes[0].mKeyframeDict.mOffset.SetValue(0.0);
+ }
+
+ // Fill in remaining missing offsets.
+ size_t i = 0;
+ while (i < aKeyframes.Length() - 1) {
+ MOZ_ASSERT(!aKeyframes[i].mKeyframeDict.mOffset.IsNull());
+ double start = aKeyframes[i].mKeyframeDict.mOffset.Value();
+ size_t j = i + 1;
+ while (aKeyframes[j].mKeyframeDict.mOffset.IsNull()) {
+ ++j;
+ }
+ double end = aKeyframes[j].mKeyframeDict.mOffset.Value();
+ size_t n = j - i;
+ for (size_t k = 1; k < n; ++k) {
+ double offset = start + double(k) / n * (end - start);
+ aKeyframes[i + k].mKeyframeDict.mOffset.SetValue(offset);
+ }
+ i = j;
+ }
+}
+
+/**
+ * Splits out each property's keyframe animation segment information
+ * from the OffsetIndexedKeyframe objects into an array of KeyframeValueEntry.
+ *
+ * The easing string value in OffsetIndexedKeyframe objects is parsed
+ * into a ComputedTimingFunction value in the corresponding KeyframeValueEntry
+ * objects.
+ *
+ * @param aTarget The target of the animation.
+ * @param aKeyframes The keyframes to read.
+ * @param aResult The array to append the resulting KeyframeValueEntry
+ * objects to.
+ */
+static void
+GenerateValueEntries(Element* aTarget,
+ nsTArray& aKeyframes,
+ nsTArray& aResult,
+ ErrorResult& aRv)
+{
+ nsCSSPropertySet properties; // All properties encountered.
+ nsCSSPropertySet propertiesWithFromValue; // Those with a defined 0% value.
+ nsCSSPropertySet propertiesWithToValue; // Those with a defined 100% value.
+
+ for (OffsetIndexedKeyframe& keyframe : aKeyframes) {
+ float offset = float(keyframe.mKeyframeDict.mOffset.Value());
+ ComputedTimingFunction easing;
+ ParseEasing(aTarget, keyframe.mKeyframeDict.mEasing, easing);
+ // We ignore keyframe.mKeyframeDict.mComposite since we don't support
+ // composite modes on keyframes yet.
+
+ // keyframe.mPropertyValuePairs is currently sorted by CSS property IDL
+ // name, since that was the order we read the properties from the JS
+ // object. Re-sort the list so that longhand properties appear before
+ // shorthands, and with shorthands all appearing in increasing order of
+ // number of components. For two longhand properties, or two shorthands
+ // with the same number of components, sort by IDL name.
+ //
+ // Example orderings that result from this:
+ //
+ // margin-left, margin
+ //
+ // and:
+ //
+ // border-top-color, border-color, border-top, border
+ //
+ // This allows us to prioritize values specified by longhands (or smaller
+ // shorthand subsets) when longhands and shorthands are both specified
+ // on the one keyframe.
+ keyframe.mPropertyValuePairs.Sort(
+ PropertyValuesPair::PropertyPriorityComparator());
+
+ nsCSSPropertySet propertiesOnThisKeyframe;
+ for (const PropertyValuesPair& pair : keyframe.mPropertyValuePairs) {
+ MOZ_ASSERT(pair.mValues.Length() == 1,
+ "ConvertKeyframeSequence should have parsed single "
+ "DOMString values from the property-values pairs");
+ // Parse the property's string value and produce a KeyframeValueEntry (or
+ // more than one, for shorthands) for it.
+ nsTArray values;
+ if (StyleAnimationValue::ComputeValues(pair.mProperty,
+ nsCSSProps::eEnabledForAllContent,
+ aTarget,
+ pair.mValues[0],
+ /* aUseSVGMode */ false,
+ values)) {
+ for (auto& value : values) {
+ // If we already got a value for this property on the keyframe,
+ // skip this one.
+ if (propertiesOnThisKeyframe.HasProperty(value.mProperty)) {
+ continue;
+ }
+
+ KeyframeValueEntry* entry = aResult.AppendElement();
+ entry->mOffset = offset;
+ entry->mProperty = value.mProperty;
+ entry->mValue = value.mValue;
+ entry->mTimingFunction = easing;
+
+ if (offset == 0.0) {
+ propertiesWithFromValue.AddProperty(value.mProperty);
+ } else if (offset == 1.0) {
+ propertiesWithToValue.AddProperty(value.mProperty);
+ }
+ propertiesOnThisKeyframe.AddProperty(value.mProperty);
+ properties.AddProperty(value.mProperty);
+ }
+ }
+ }
+ }
+
+ // We don't support additive segments and so can't support missing properties
+ // using their underlying value in 0% and 100% keyframes. Throw an exception
+ // until we do support this.
+ if (!propertiesWithFromValue.Equals(properties) ||
+ !propertiesWithToValue.Equals(properties)) {
+ aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
+ return;
+ }
+}
+
+/**
+ * Builds an array of AnimationProperty objects to represent the keyframe
+ * animation segments in aEntries.
+ */
+static void
+BuildSegmentsFromValueEntries(nsTArray& aEntries,
+ nsTArray& aResult)
+{
+ if (aEntries.IsEmpty()) {
+ return;
+ }
+
+ // Sort the KeyframeValueEntry objects so that all entries for a given
+ // property are together, and the entries are sorted by offset otherwise.
+ std::stable_sort(aEntries.begin(), aEntries.end(),
+ &KeyframeValueEntry::PropertyOffsetComparator::LessThan);
+
+ MOZ_ASSERT(aEntries[0].mOffset == 0.0f);
+ MOZ_ASSERT(aEntries.LastElement().mOffset == 1.0f);
+
+ // For a given index i, we want to generate a segment from aEntries[i]
+ // to aEntries[j], if:
+ //
+ // * j > i,
+ // * aEntries[i + 1]'s offset/property is different from aEntries[i]'s, and
+ // * aEntries[j - 1]'s offset/property is different from aEntries[j]'s.
+ //
+ // That will eliminate runs of same offset/property values where there's no
+ // point generating zero length segments in the middle of the animation.
+ //
+ // Additionally we need to generate a zero length segment at offset 0 and at
+ // offset 1, if we have multiple values for a given property at that offset,
+ // since we need to retain the very first and very last value so they can
+ // be used for reverse and forward filling.
+
+ nsCSSProperty lastProperty = eCSSProperty_UNKNOWN;
+ AnimationProperty* animationProperty = nullptr;
+
+ size_t i = 0, n = aEntries.Length();
+
+ while (i + 1 < n) {
+ // Starting from i, determine the next [i, j] interval from which to
+ // generate a segment.
+ size_t j;
+ if (aEntries[i].mOffset == 0.0f && aEntries[i + 1].mOffset == 0.0f) {
+ // We need to generate an initial zero-length segment.
+ MOZ_ASSERT(aEntries[i].mProperty == aEntries[i + 1].mProperty);
+ j = i + 1;
+ while (aEntries[j + 1].mOffset == 0.0f) {
+ MOZ_ASSERT(aEntries[j].mProperty == aEntries[j + 1].mProperty);
+ ++j;
+ }
+ } else if (aEntries[i].mOffset == 1.0f) {
+ if (aEntries[i + 1].mOffset == 1.0f) {
+ // We need to generate a final zero-length segment.
+ MOZ_ASSERT(aEntries[i].mProperty == aEntries[i].mProperty);
+ j = i + 1;
+ while (j + 1 < n && aEntries[j + 1].mOffset == 1.0f) {
+ MOZ_ASSERT(aEntries[j].mProperty == aEntries[j + 1].mProperty);
+ ++j;
+ }
+ } else {
+ // New property.
+ MOZ_ASSERT(aEntries[i + 1].mOffset == 0.0f);
+ MOZ_ASSERT(aEntries[i].mProperty != aEntries[i + 1].mProperty);
+ ++i;
+ continue;
+ }
+ } else {
+ while (aEntries[i].mOffset == aEntries[i + 1].mOffset &&
+ aEntries[i].mProperty == aEntries[i + 1].mProperty) {
+ ++i;
+ }
+ j = i + 1;
+ }
+
+ // If we've moved on to a new property, create a new AnimationProperty
+ // to insert segments into.
+ if (aEntries[i].mProperty != lastProperty) {
+ MOZ_ASSERT(aEntries[i].mOffset == 0.0f);
+ animationProperty = aResult.AppendElement();
+ animationProperty->mProperty = aEntries[i].mProperty;
+ animationProperty->mWinsInCascade = true;
+ lastProperty = aEntries[i].mProperty;
+ }
+
+ // Now generate the segment.
+ AnimationPropertySegment* segment =
+ animationProperty->mSegments.AppendElement();
+ segment->mFromKey = aEntries[i].mOffset;
+ segment->mToKey = aEntries[j].mOffset;
+ segment->mFromValue = aEntries[i].mValue;
+ segment->mToValue = aEntries[j].mValue;
+ segment->mTimingFunction = aEntries[i].mTimingFunction;
+
+ i = j;
+ }
+}
+
+/**
+ * Converts a JS object to an IDL sequence and builds an
+ * array of AnimationProperty objects for the keyframe animation
+ * that it specifies.
+ *
+ * @param aTarget The target of the animation.
+ * @param aIterator An already-initialized ForOfIterator for the JS
+ * object to iterate over as a sequence.
+ * @param aResult The array into which the resulting AnimationProperty
+ * objects will be appended.
+ */
+static void
+BuildAnimationPropertyListFromKeyframeSequence(
+ JSContext* aCx,
+ Element* aTarget,
+ JS::ForOfIterator& aIterator,
+ nsTArray& aResult,
+ ErrorResult& aRv)
+{
+ // Convert the object in aIterator to sequence, producing
+ // an array of OffsetIndexedKeyframe objects.
+ nsAutoTArray keyframes;
+ if (!ConvertKeyframeSequence(aCx, aIterator, keyframes)) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return;
+ }
+
+ // If the sequence<> had zero elements, we won't generate any
+ // keyframes.
+ if (keyframes.IsEmpty()) {
+ return;
+ }
+
+ // Check that the keyframes are loosely sorted and with values all
+ // between 0% and 100%.
+ if (!HasValidOffsets(keyframes)) {
+ aRv.ThrowTypeError();
+ return;
+ }
+
+ // Fill in 0%/100% values if the first/element keyframes don't have
+ // a specified offset, and evenly space those that have a missing
+ // offset. (We don't support paced spacing yet.)
+ ApplyDistributeSpacing(keyframes);
+
+ // Convert the OffsetIndexedKeyframes into a list of KeyframeValueEntry
+ // objects.
+ nsTArray entries;
+ GenerateValueEntries(aTarget, keyframes, entries, aRv);
+ if (aRv.Failed()) {
+ return;
+ }
+
+ // Finally, build an array of AnimationProperty objects in aResult
+ // corresponding to the entries.
+ BuildSegmentsFromValueEntries(entries, aResult);
+}
+
+/**
+ * Converts a JS object to an IDL PropertyIndexedKeyframes and builds an
+ * array of AnimationProperty objects for the keyframe animation
+ * that it specifies.
+ *
+ * @param aTarget The target of the animation.
+ * @param aValue The JS object.
+ * @param aResult The array into which the resulting AnimationProperty
+ * objects will be appended.
+ */
+static void
+BuildAnimationPropertyListFromPropertyIndexedKeyframes(
+ JSContext* aCx,
+ Element* aTarget,
+ JS::Handle aValue,
+ InfallibleTArray& aResult,
+ ErrorResult& aRv)
+{
+ MOZ_ASSERT(aValue.isObject());
+
+ // Convert the object to a PropertyIndexedKeyframes dictionary to
+ // get its explicit dictionary members.
+ binding_detail::FastPropertyIndexedKeyframes keyframes;
+ if (!keyframes.Init(aCx, aValue, "PropertyIndexedKeyframes argument",
+ false)) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return;
+ }
+
+ ComputedTimingFunction easing;
+ ParseEasing(aTarget, keyframes.mEasing, easing);
+
+ // We ignore easing.mComposite since we don't support composite modes on
+ // keyframes yet.
+
+ // Get all the property--value-list pairs off the object.
+ JS::Rooted object(aCx, &aValue.toObject());
+ nsTArray propertyValuesPairs;
+ if (!GetPropertyValuesPairs(aCx, object, ListAllowance::eAllow,
+ propertyValuesPairs)) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return;
+ }
+
+ // We must keep track of which properties we've already generated
+ // an AnimationProperty since the author could have specified both a
+ // shorthand and one of its component longhands on the
+ // PropertyIndexedKeyframes.
+ nsCSSPropertySet properties;
+
+ // Create AnimationProperty objects for each PropertyValuesPair, applying
+ // the "distribute" spacing algorithm to the segments.
+ for (const PropertyValuesPair& pair : propertyValuesPairs) {
+ size_t count = pair.mValues.Length();
+ if (count == 0) {
+ // No animation values for this property.
+ continue;
+ }
+ if (count == 1) {
+ // We don't support additive segments and so can't support an
+ // animation that goes from the underlying value to this
+ // specified value. Throw an exception until we do support this.
+ aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
+ return;
+ }
+
+ // If we find an invalid value, we don't create a segment for it, but
+ // we adjust the surrounding segments so that the timing of the segments
+ // is the same as if we did support it. For example, animating with
+ // values ["red", "green", "yellow", "invalid", "blue"] will generate
+ // segments with this timing:
+ //
+ // 0.00 -> 0.25 : red -> green
+ // 0.25 -> 0.50 : green -> yellow
+ // 0.50 -> 1.00 : yellow -> blue
+ //
+ // With future spec clarifications we might decide to preserve the invalid
+ // value on the segment and make the animation code deal with the invalid
+ // value instead.
+ nsTArray fromValues;
+ float fromKey = 0.0f;
+ if (!StyleAnimationValue::ComputeValues(pair.mProperty,
+ nsCSSProps::eEnabledForAllContent,
+ aTarget,
+ pair.mValues[0],
+ /* aUseSVGMode */ false,
+ fromValues)) {
+ // We need to throw for an invalid first value, since that would imply an
+ // additive animation, which we don't support yet.
+ aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
+ return;
+ }
+
+ if (fromValues.IsEmpty()) {
+ // All longhand components of a shorthand pair.mProperty must be disabled.
+ continue;
+ }
+
+ // Create AnimationProperty objects for each property that had a
+ // value computed. When pair.mProperty is a longhand, it is just
+ // that property. When pair.mProperty is a shorthand, we'll have
+ // one property per longhand component.
+ nsTArray animationPropertyIndexes;
+ animationPropertyIndexes.SetLength(fromValues.Length());
+ for (size_t i = 0, n = fromValues.Length(); i < n; ++i) {
+ nsCSSProperty p = fromValues[i].mProperty;
+ bool found = false;
+ if (properties.HasProperty(p)) {
+ // We have already dealt with this property. Look up and
+ // overwrite the old AnimationProperty object.
+ for (size_t j = 0, m = aResult.Length(); j < m; ++j) {
+ if (aResult[j].mProperty == p) {
+ aResult[j].mSegments.Clear();
+ animationPropertyIndexes[i] = j;
+ found = true;
+ break;
+ }
+ }
+ MOZ_ASSERT(found, "properties is inconsistent with aResult");
+ }
+ if (!found) {
+ // This is the first time we've encountered this property.
+ animationPropertyIndexes[i] = aResult.Length();
+ AnimationProperty* animationProperty = aResult.AppendElement();
+ animationProperty->mProperty = p;
+ animationProperty->mWinsInCascade = true;
+ properties.AddProperty(p);
+ }
+ }
+
+ double portion = 1.0 / (count - 1);
+ for (size_t i = 0; i < count - 1; ++i) {
+ nsTArray toValues;
+ float toKey = (i + 1) * portion;
+ if (!StyleAnimationValue::ComputeValues(pair.mProperty,
+ nsCSSProps::eEnabledForAllContent,
+ aTarget,
+ pair.mValues[i + 1],
+ /* aUseSVGMode */ false,
+ toValues)) {
+ if (i + 1 == count - 1) {
+ // We need to throw for an invalid last value, since that would
+ // imply an additive animation, which we don't support yet.
+ aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
+ return;
+ }
+ // Otherwise, skip the segment.
+ continue;
+ }
+ MOZ_ASSERT(toValues.Length() == fromValues.Length(),
+ "should get the same number of properties as the last time "
+ "we called ComputeValues for pair.mProperty");
+ for (size_t j = 0, n = toValues.Length(); j < n; ++j) {
+ size_t index = animationPropertyIndexes[j];
+ AnimationPropertySegment* segment =
+ aResult[index].mSegments.AppendElement();
+ segment->mFromKey = fromKey;
+ segment->mFromValue = fromValues[j].mValue;
+ segment->mToKey = toKey;
+ segment->mToValue = toValues[j].mValue;
+ segment->mTimingFunction = easing;
+ }
+ fromValues = Move(toValues);
+ fromKey = toKey;
+ }
+ }
+}
+
+/**
+ * Converts a JS value to an IDL
+ * (PropertyIndexedKeyframes or sequence) value and builds an
+ * array of AnimationProperty objects for the keyframe animation
+ * that it specifies.
+ *
+ * @param aTarget The target of the animation, used to resolve style
+ * for a property's underlying value if needed.
+ * @param aFrames The JS value, provided as an optional IDL |object?| value,
+ * that is the keyframe list specification.
+ * @param aResult The array into which the resulting AnimationProperty
+ * objects will be appended.
+ */
+/* static */ void
+KeyframeEffectReadOnly::BuildAnimationPropertyList(
+ JSContext* aCx,
+ Element* aTarget,
+ const Optional>& aFrames,
+ InfallibleTArray& aResult,
+ ErrorResult& aRv)
+{
+ MOZ_ASSERT(aResult.IsEmpty());
+
+ // A frame list specification in the IDL is:
+ //
+ // (PropertyIndexedKeyframes or sequence or SharedKeyframeList)
+ //
+ // We don't support SharedKeyframeList yet, but we do the other two. We
+ // manually implement the parts of JS-to-IDL union conversion algorithm
+ // from the Web IDL spec, since we have to represent this an object? so
+ // we can look at the open-ended set of properties on a
+ // PropertyIndexedKeyframes or Keyframe.
+
+ if (!aFrames.WasPassed() || !aFrames.Value().get()) {
+ // The argument was omitted, or was explicitly null. In both cases,
+ // the default dictionary value for PropertyIndexedKeyframes would
+ // result in no keyframes.
+ return;
+ }
+
+ // At this point we know we have an object. We try to convert it to a
+ // sequence first, and if that fails due to not being iterable,
+ // we try to convert it to PropertyIndexedKeyframes.
+ JS::Rooted objectValue(aCx, JS::ObjectValue(*aFrames.Value()));
+ JS::ForOfIterator iter(aCx);
+ if (!iter.init(objectValue, JS::ForOfIterator::AllowNonIterable)) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return;
+ }
+
+ if (iter.valueIsIterable()) {
+ BuildAnimationPropertyListFromKeyframeSequence(aCx, aTarget, iter,
+ aResult, aRv);
+ } else {
+ BuildAnimationPropertyListFromPropertyIndexedKeyframes(aCx, aTarget,
+ objectValue, aResult,
+ aRv);
+ }
+}
+
+/* static */ already_AddRefed
+KeyframeEffectReadOnly::Constructor(
+ const GlobalObject& aGlobal,
+ Element* aTarget,
+ const Optional>& aFrames,
+ const Optional& aOptions,
+ ErrorResult& aRv)
+{
+ if (!aTarget) {
+ // We don't support null targets yet.
+ aRv.Throw(NS_ERROR_DOM_ANIM_NO_TARGET_ERR);
+ return nullptr;
+ }
+
+ AnimationTiming timing = ConvertKeyframeEffectOptions(aOptions);
+
+ InfallibleTArray animationProperties;
+ BuildAnimationPropertyList(aGlobal.Context(), aTarget, aFrames,
+ animationProperties, aRv);
+
+ if (aRv.Failed()) {
+ return nullptr;
+ }
+
+ RefPtr effect =
+ new KeyframeEffectReadOnly(aTarget->OwnerDoc(), aTarget,
+ nsCSSPseudoElements::ePseudo_NotPseudoElement,
+ timing);
+ effect->mProperties = Move(animationProperties);
+ return effect.forget();
+}
void
KeyframeEffectReadOnly::GetFrames(JSContext*& aCx,
nsTArray& aResult,
ErrorResult& aRv)
{
- // Collect tuples of the form (offset, property, value, easing) from
- // mProperties, then sort them so we can generate one ComputedKeyframe per
- // offset/easing pair. We sort secondarily by property IDL name so that we
- // have a uniform order that we set properties on the ComputedKeyframe
- // object.
- nsAutoTArray entries;
+ nsTArray entries;
+
for (const AnimationProperty& property : mProperties) {
- if (property.mSegments.IsEmpty()) {
- continue;
- }
for (size_t i = 0, n = property.mSegments.Length(); i < n; i++) {
const AnimationPropertySegment& segment = property.mSegments[i];
- KeyframeValueEntry* entry = entries.AppendElement();
- entry->mOffset = segment.mFromKey;
+
+ // We append the mFromValue for each segment. If the mToValue
+ // differs from the following segment's mFromValue, or if we're on
+ // the last segment, then we append the mToValue as well.
+ //
+ // Each value is annotated with whether it is a "first", "left", "right",
+ // or "last" value. "left" and "right" values represent the value coming
+ // in to and out of a given offset, in the middle of an animation. For
+ // most segments, the mToValue is the "left" and the following segment's
+ // mFromValue is the "right". The "first" and "last" values are the
+ // additional values assigned to offset 0 or 1 for reverse and forward
+ // filling. These annotations are used to ensure multiple values for a
+ // given property are sorted correctly and that we do not merge Keyframes
+ // with different values for the same offset.
+
+ OrderedKeyframeValueEntry* entry = entries.AppendElement();
entry->mProperty = property.mProperty;
+ entry->mValue = segment.mFromValue;
+ entry->mOffset = segment.mFromKey;
entry->mTimingFunction = &segment.mTimingFunction;
- StyleAnimationValue::UncomputeValue(property.mProperty,
- segment.mFromValue,
- entry->mValue);
+ entry->mPosition =
+ segment.mFromKey == segment.mToKey && segment.mFromKey == 0.0f ?
+ ValuePosition::First :
+ ValuePosition::Right;
+
+ if (i == n - 1 ||
+ segment.mToValue != property.mSegments[i + 1].mFromValue) {
+ entry = entries.AppendElement();
+ entry->mProperty = property.mProperty;
+ entry->mValue = segment.mToValue;
+ entry->mOffset = segment.mToKey;
+ entry->mTimingFunction = &segment.mTimingFunction;
+ entry->mPosition =
+ segment.mFromKey == segment.mToKey && segment.mToKey == 1.0f ?
+ ValuePosition::Last :
+ ValuePosition::Left;
+ }
}
- const AnimationPropertySegment& segment = property.mSegments.LastElement();
- KeyframeValueEntry* entry = entries.AppendElement();
- entry->mOffset = segment.mToKey;
- entry->mProperty = property.mProperty;
- // We don't have the an appropriate animation-timing-function value to use,
- // either from the element or from the 100% keyframe, so we just set it to
- // the animation-timing-value value used on the previous segment.
- entry->mTimingFunction = &segment.mTimingFunction;
- StyleAnimationValue::UncomputeValue(property.mProperty,
- segment.mToValue,
- entry->mValue);
}
- entries.Sort();
+
+ entries.Sort(OrderedKeyframeValueEntry::ForKeyframeGenerationComparator());
for (size_t i = 0, n = entries.Length(); i < n; ) {
+ OrderedKeyframeValueEntry* entry = &entries[i];
+ OrderedKeyframeValueEntry* previousEntry = nullptr;
+
// Create a JS object with the explicit ComputedKeyframe dictionary members.
ComputedKeyframe keyframeDict;
- keyframeDict.mOffset.SetValue(entries[i].mOffset);
- keyframeDict.mComputedOffset.Construct(entries[i].mOffset);
- keyframeDict.mEasing.Truncate();
- entries[i].mTimingFunction->AppendToString(keyframeDict.mEasing);
+ keyframeDict.mOffset.SetValue(entry->mOffset);
+ keyframeDict.mComputedOffset.Construct(entry->mOffset);
+ if (entry->mTimingFunction) {
+ // If null, leave easing as its default "linear".
+ keyframeDict.mEasing.Truncate();
+ entry->mTimingFunction->AppendToString(keyframeDict.mEasing);
+ }
keyframeDict.mComposite.SetValue(CompositeOperation::Replace);
- JS::Rooted keyframeValue(aCx);
- if (!ToJSValue(aCx, keyframeDict, &keyframeValue)) {
+ JS::Rooted keyframeJSValue(aCx);
+ if (!ToJSValue(aCx, keyframeDict, &keyframeJSValue)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
- JS::Rooted keyframe(aCx, &keyframeValue.toObject());
-
- // Set the property name/value pairs on the JS object.
+ JS::Rooted keyframe(aCx, &keyframeJSValue.toObject());
do {
- const KeyframeValueEntry& entry = entries[i];
- const char* name = nsCSSProps::PropertyIDLName(entry.mProperty);
+ const char* name = nsCSSProps::PropertyIDLName(entry->mProperty);
+ nsString stringValue;
+ StyleAnimationValue::UncomputeValue(entry->mProperty,
+ entry->mValue,
+ stringValue);
JS::Rooted value(aCx);
- if (!ToJSValue(aCx, entry.mValue, &value) ||
+ if (!ToJSValue(aCx, stringValue, &value) ||
!JS_DefineProperty(aCx, keyframe, name, value, JSPROP_ENUMERATE)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
- ++i;
- } while (i < n &&
- entries[i].mOffset == entries[i - 1].mOffset &&
- *entries[i].mTimingFunction == *entries[i - 1].mTimingFunction);
+ if (++i == n) {
+ break;
+ }
+ previousEntry = entry;
+ entry = &entries[i];
+ } while (entry->SameKeyframe(*previousEntry));
aResult.AppendElement(keyframe);
}
diff --git a/dom/animation/KeyframeEffect.h b/dom/animation/KeyframeEffect.h
index f14277c11a..41e83411f8 100644
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -195,6 +195,8 @@ struct ElementPropertyTransition;
namespace dom {
+class Animation;
+
class KeyframeEffectReadOnly : public AnimationEffectReadOnly
{
public:
@@ -217,6 +219,12 @@ public:
}
// KeyframeEffectReadOnly interface
+ static already_AddRefed
+ Constructor(const GlobalObject& aGlobal,
+ Element* aTarget,
+ const Optional>& aFrames,
+ const Optional& aOptions,
+ ErrorResult& aRv);
Element* GetTarget() const {
// Currently we never return animations from the API whose effect
// targets a pseudo-element so this should never be called when
@@ -238,32 +246,15 @@ public:
aPseudoType = mPseudoType;
}
- void SetParentTime(Nullable aParentTime);
-
const AnimationTiming& Timing() const {
return mTiming;
}
AnimationTiming& Timing() {
return mTiming;
}
+ void SetTiming(const AnimationTiming& aTiming);
- // FIXME: Drop |aOwningAnimation| once we make AnimationEffects track their
- // owning animation.
- void SetTiming(const AnimationTiming& aTiming, Animation& aOwningAnimtion);
-
- // Return the duration from the start the active interval to the point where
- // the animation begins playback. This is zero unless the animation has
- // a negative delay in which case it is the absolute value of the delay.
- // This is used for setting the elapsedTime member of CSS AnimationEvents.
- TimeDuration InitialAdvance() const {
- return std::max(TimeDuration(), mTiming.mDelay * -1);
- }
-
- Nullable GetLocalTime() const {
- // Since the *animation* start time is currently always zero, the local
- // time is equal to the parent time.
- return mParentTime;
- }
+ Nullable GetLocalTime() const;
// This function takes as input the timing parameters of an animation and
// returns the computed timing at the specified local time.
@@ -290,10 +281,12 @@ public:
static StickyTimeDuration
ActiveDuration(const AnimationTiming& aTiming);
- bool IsInPlay(const Animation& aAnimation) const;
- bool IsCurrent(const Animation& aAnimation) const;
+ bool IsInPlay() const;
+ bool IsCurrent() const;
bool IsInEffect() const;
+ void SetAnimation(Animation* aAnimation);
+
const AnimationProperty*
GetAnimationOfProperty(nsCSSProperty aProperty) const;
bool HasAnimationOfProperty(nsCSSProperty aProperty) const {
@@ -309,8 +302,8 @@ public:
}
// Updates |aStyleRule| with the animation values produced by this
- // Animation for the current time except any properties already contained
- // in |aSetProperties|.
+ // AnimationEffect for the current time except any properties already
+ // contained in |aSetProperties|.
// Any updated properties are added to |aSetProperties|.
void ComposeStyle(RefPtr& aStyleRule,
nsCSSPropertySet& aSetProperties);
@@ -318,11 +311,20 @@ public:
void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
protected:
- virtual ~KeyframeEffectReadOnly() { }
+ virtual ~KeyframeEffectReadOnly();
void ResetIsRunningOnCompositor();
+ static AnimationTiming ConvertKeyframeEffectOptions(
+ const Optional& aOptions);
+ static void BuildAnimationPropertyList(
+ JSContext* aCx,
+ Element* aTarget,
+ const Optional>& aFrames,
+ InfallibleTArray& aResult,
+ ErrorResult& aRv);
+
nsCOMPtr mTarget;
- Nullable mParentTime;
+ RefPtr mAnimation;
AnimationTiming mTiming;
nsCSSPseudoElements::Type mPseudoType;
diff --git a/dom/animation/test/css-animations/file_keyframeeffect-getframes.html b/dom/animation/test/css-animations/file_keyframeeffect-getframes.html
index c501166eec..f127dd22cf 100644
--- a/dom/animation/test/css-animations/file_keyframeeffect-getframes.html
+++ b/dom/animation/test/css-animations/file_keyframeeffect-getframes.html
@@ -24,6 +24,12 @@
to { color: white; }
}
+@keyframes anim-simple-three {
+ from { color: black; }
+ 50% { color: blue; }
+ to { color: white; }
+}
+
@keyframes anim-simple-timing {
from { color: black; animation-timing-function: linear; }
50% { color: blue; animation-timing-function: ease-in-out; }
@@ -183,10 +189,10 @@ test(function(t) {
kTimingFunctionValues.forEach(function(easing) {
var div = addDiv(t);
- div.style.animation = 'anim-simple 100s ' + easing;
+ div.style.animation = 'anim-simple-three 100s ' + easing;
var frames = getFrames(div);
- assert_equals(frames.length, 2, "number of frames");
+ assert_equals(frames.length, 3, "number of frames");
for (var i = 0; i < frames.length; i++) {
assert_equals(frames[i].easing, easing,
@@ -364,7 +370,7 @@ test(function(t) {
{ offset: 1, computedOffset: 1, easing: "ease-in", composite: "replace",
marginTop: "16px" },
{ offset: 1, computedOffset: 1, easing: "step-end", composite: "replace",
- color: "rgb(255, 255, 255)", },
+ color: "rgb(255, 255, 255)" },
];
for (var i = 0; i < frames.length; i++) {
diff --git a/dom/animation/test/mochitest.ini b/dom/animation/test/mochitest.ini
index e8d2c951e0..a7a28f5219 100644
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -71,3 +71,5 @@ support-files = mozilla/file_deferred_start.html
skip-if = (toolkit == 'gonk' && debug)
[mozilla/test_hide_and_show.html]
support-files = mozilla/file_hide_and_show.html
+[mozilla/test_partial_keyframes.html]
+support-files = mozilla/file_partial_keyframes.html
diff --git a/dom/animation/test/mozilla/file_partial_keyframes.html b/dom/animation/test/mozilla/file_partial_keyframes.html
new file mode 100644
index 0000000000..68832be7a0
--- /dev/null
+++ b/dom/animation/test/mozilla/file_partial_keyframes.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+
diff --git a/dom/animation/test/mozilla/test_partial_keyframes.html b/dom/animation/test/mozilla/test_partial_keyframes.html
new file mode 100644
index 0000000000..28eb4c5881
--- /dev/null
+++ b/dom/animation/test/mozilla/test_partial_keyframes.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/dom/base/domerr.msg b/dom/base/domerr.msg
index fa4f4ccc06..bf6e5b0379 100644
--- a/dom/base/domerr.msg
+++ b/dom/base/domerr.msg
@@ -115,6 +115,11 @@ DOM4_MSG_DEF(BtAuthFailureError, "Authentication failure", NS_ERROR_DOM_BLUETO
DOM4_MSG_DEF(BtRmtDevDownError, "Remote device down", NS_ERROR_DOM_BLUETOOTH_RMT_DEV_DOWN)
DOM4_MSG_DEF(BtAuthRejectedError, "Authentication rejected", NS_ERROR_DOM_BLUETOOTH_AUTH_REJECTED)
+/* Web Animations errors */
+
+DOM4_MSG_DEF(NotSupportedError, "Animation to or from an underlying value is not yet supported.", NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR)
+DOM4_MSG_DEF(NotSupportedError, "Animation with no target is not yet supported.", NS_ERROR_DOM_ANIM_NO_TARGET_ERR)
+
/* common global codes (from nsError.h) */
DOM_MSG_DEF(NS_OK , "Success")
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index e179176c00..e78df4ac26 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3140,7 +3140,8 @@ nsContentUtils::IsImageInCache(nsIURI* aURI, nsIDocument* aDocument)
// If something unexpected happened we return false, otherwise if props
// is set, the image is cached and we return true
nsCOMPtr props;
- nsresult rv = cache->FindEntryProperties(aURI, getter_AddRefs(props));
+ nsCOMPtr domDoc = do_QueryInterface(aDocument);
+ nsresult rv = cache->FindEntryProperties(aURI, domDoc, getter_AddRefs(props));
return (NS_SUCCEEDED(rv) && props);
}
diff --git a/dom/base/nsDOMAttributeMap.cpp b/dom/base/nsDOMAttributeMap.cpp
index 87e58627be..93e686da0d 100644
--- a/dom/base/nsDOMAttributeMap.cpp
+++ b/dom/base/nsDOMAttributeMap.cpp
@@ -557,13 +557,6 @@ nsDOMAttributeMap::Count() const
return mAttributeCache.Count();
}
-uint32_t
-nsDOMAttributeMap::Enumerate(AttrCache::EnumReadFunction aFunc,
- void *aUserArg) const
-{
- return mAttributeCache.EnumerateRead(aFunc, aUserArg);
-}
-
size_t
nsDOMAttributeMap::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
diff --git a/dom/base/nsDOMAttributeMap.h b/dom/base/nsDOMAttributeMap.h
index 6109810325..7ebe61aa13 100644
--- a/dom/base/nsDOMAttributeMap.h
+++ b/dom/base/nsDOMAttributeMap.h
@@ -128,13 +128,7 @@ public:
typedef nsRefPtrHashtable AttrCache;
- /**
- * Enumerates over the attribute nodess in the map and calls aFunc for each
- * one. If aFunc returns PL_DHASH_STOP we'll stop enumerating at that point.
- *
- * @return The number of attribute nodes that aFunc was called for.
- */
- uint32_t Enumerate(AttrCache::EnumReadFunction aFunc, void *aUserArg) const;
+ static void BlastSubtreeToPieces(nsINode *aNode);
Element* GetParentObject() const
{
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
index 672429737b..7c99937f34 100644
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3265,7 +3265,7 @@ convertSheetType(uint32_t aSheetType)
default:
NS_ASSERTION(false, "wrong type");
// we must return something although this should never happen
- return nsIDocument::SheetTypeCount;
+ return nsIDocument::AdditionalSheetTypeCount;
}
}
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index 20d2f7c24a..a2e4f3c0c6 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -69,7 +69,8 @@
#include "mozilla/dom/TreeWalker.h"
#include "nsIServiceManager.h"
-#include "nsIServiceWorkerManager.h"
+#include "mozilla/dom/workers/ServiceWorkerManager.h"
+#include "imgLoader.h"
#include "nsCanvasFrame.h"
#include "nsContentCID.h"
@@ -376,30 +377,14 @@ CustomDefinitionsTraverse(CustomElementHashKey* aKey,
return PL_DHASH_NEXT;
}
-struct CustomDefinitionTraceArgs
-{
- const TraceCallbacks& callbacks;
- void* closure;
-};
-
-static PLDHashOperator
-CustomDefinitionTrace(CustomElementHashKey *aKey,
- CustomElementDefinition *aData,
- void *aArg)
-{
- CustomDefinitionTraceArgs* traceArgs = static_cast(aArg);
- MOZ_ASSERT(aData, "Definition must not be null");
- traceArgs->callbacks.Trace(&aData->mPrototype, "mCustomDefinitions prototype",
- traceArgs->closure);
- return PL_DHASH_NEXT;
-}
-
NS_IMPL_CYCLE_COLLECTION_CLASS(Registry)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Registry)
- CustomDefinitionTraceArgs customDefinitionArgs = { aCallbacks, aClosure };
- tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionTrace,
- &customDefinitionArgs);
+ for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
+ aCallbacks.Trace(&iter.UserData()->mPrototype,
+ "mCustomDefinitions prototype",
+ aClosure);
+ }
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry)
@@ -929,57 +914,16 @@ nsExternalResourceMap::RequestResource(nsIURI* aURI,
return nullptr;
}
-struct
-nsExternalResourceEnumArgs
-{
- nsIDocument::nsSubDocEnumFunc callback;
- void *data;
-};
-
-static PLDHashOperator
-ExternalResourceEnumerator(nsIURI* aKey,
- nsExternalResourceMap::ExternalResource* aData,
- void* aClosure)
-{
- nsExternalResourceEnumArgs* args =
- static_cast(aClosure);
- bool next =
- aData->mDocument ? args->callback(aData->mDocument, args->data) : true;
- return next ? PL_DHASH_NEXT : PL_DHASH_STOP;
-}
-
void
nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback,
void* aData)
{
- nsExternalResourceEnumArgs args = { aCallback, aData };
- mMap.EnumerateRead(ExternalResourceEnumerator, &args);
-}
-
-static PLDHashOperator
-ExternalResourceTraverser(nsIURI* aKey,
- nsExternalResourceMap::ExternalResource* aData,
- void* aClosure)
-{
- nsCycleCollectionTraversalCallback *cb =
- static_cast(aClosure);
-
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
- "mExternalResourceMap.mMap entry"
- "->mDocument");
- cb->NoteXPCOMChild(aData->mDocument);
-
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
- "mExternalResourceMap.mMap entry"
- "->mViewer");
- cb->NoteXPCOMChild(aData->mViewer);
-
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
- "mExternalResourceMap.mMap entry"
- "->mLoadGroup");
- cb->NoteXPCOMChild(aData->mLoadGroup);
-
- return PL_DHASH_NEXT;
+ for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
+ nsExternalResourceMap::ExternalResource* resource = iter.UserData();
+ if (resource->mDocument && !aCallback(resource->mDocument, aData)) {
+ break;
+ }
+ }
}
void
@@ -987,7 +931,24 @@ nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) c
{
// mPendingLoads will get cleared out as the requests complete, so
// no need to worry about those here.
- mMap.EnumerateRead(ExternalResourceTraverser, aCallback);
+ for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
+ nsExternalResourceMap::ExternalResource* resource = iter.UserData();
+
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
+ "mExternalResourceMap.mMap entry"
+ "->mDocument");
+ aCallback->NoteXPCOMChild(resource->mDocument);
+
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
+ "mExternalResourceMap.mMap entry"
+ "->mViewer");
+ aCallback->NoteXPCOMChild(resource->mViewer);
+
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
+ "mExternalResourceMap.mMap entry"
+ "->mLoadGroup");
+ aCallback->NoteXPCOMChild(resource->mLoadGroup);
+ }
}
static PLDHashOperator
@@ -2099,9 +2060,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
tmp->mInUnlinkOrDeletion = false;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-static bool sPrefsInitialized = false;
-static uint32_t sOnloadDecodeLimit = 0;
-
nsresult
nsDocument::Init()
{
@@ -2109,11 +2067,6 @@ nsDocument::Init()
return NS_ERROR_ALREADY_INITIALIZED;
}
- if (!sPrefsInitialized) {
- sPrefsInitialized = true;
- Preferences::AddUintVarCache(&sOnloadDecodeLimit, "image.onload.decode.limit", 0);
- }
-
// Force initialization.
nsINode::nsSlots* slots = Slots();
@@ -2395,7 +2348,7 @@ nsDocument::RemoveDocStyleSheetsFromStyleSets()
}
void
-nsDocument::RemoveStyleSheetsFromStyleSets(nsCOMArray& aSheets, nsStyleSet::sheetType aType)
+nsDocument::RemoveStyleSheetsFromStyleSets(nsCOMArray& aSheets, SheetType aType)
{
// The stylesheets should forget us
int32_t indx = aSheets.Count();
@@ -2422,16 +2375,17 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
mozAutoDocUpdate upd(this, UPDATE_STYLE, true);
RemoveDocStyleSheetsFromStyleSets();
- RemoveStyleSheetsFromStyleSets(mOnDemandBuiltInUASheets, nsStyleSet::eAgentSheet);
- RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], nsStyleSet::eAgentSheet);
- RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], nsStyleSet::eUserSheet);
- RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet], nsStyleSet::eDocSheet);
+ RemoveStyleSheetsFromStyleSets(mOnDemandBuiltInUASheets, SheetType::Agent);
+ RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], SheetType::Agent);
+ RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], SheetType::User);
+ RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet], SheetType::Doc);
// Release all the sheets
mStyleSheets.Clear();
mOnDemandBuiltInUASheets.Clear();
- for (uint32_t i = 0; i < SheetTypeCount; ++i)
- mAdditionalSheets[i].Clear();
+ for (auto& sheets : mAdditionalSheets) {
+ sheets.Clear();
+ }
// NOTE: We don't release the catalog sheets. It doesn't really matter
// now, but it could in the future -- in which case not releasing them
@@ -2465,14 +2419,14 @@ static bool
AppendAuthorSheet(nsIStyleSheet *aSheet, void *aData)
{
nsStyleSet *styleSet = static_cast(aData);
- styleSet->AppendStyleSheet(nsStyleSet::eDocSheet, aSheet);
+ styleSet->AppendStyleSheet(SheetType::Doc, aSheet);
return true;
}
static void
AppendSheetsToStyleSet(nsStyleSet* aStyleSet,
const nsCOMArray& aSheets,
- nsStyleSet::sheetType aType)
+ SheetType aType)
{
for (int32_t i = aSheets.Count() - 1; i >= 0; --i) {
aStyleSet->AppendStyleSheet(aType, aSheets[i]);
@@ -2484,14 +2438,9 @@ void
nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
{
NS_PRECONDITION(aStyleSet, "Must have a style set");
- NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eDocSheet) == 0,
+ NS_PRECONDITION(aStyleSet->SheetCount(SheetType::Doc) == 0,
"Style set already has document sheets?");
- // We could consider moving this to nsStyleSet::Init, to match its
- // handling of the eAnimationSheet and eTransitionSheet levels.
- aStyleSet->DirtyRuleProcessors(nsStyleSet::ePresHintSheet);
- aStyleSet->DirtyRuleProcessors(nsStyleSet::eStyleAttrSheet);
-
int32_t i;
for (i = mStyleSheets.Count() - 1; i >= 0; --i) {
nsIStyleSheet* sheet = mStyleSheets[i];
@@ -2510,16 +2459,16 @@ nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
for (i = mOnDemandBuiltInUASheets.Count() - 1; i >= 0; --i) {
nsIStyleSheet* sheet = mOnDemandBuiltInUASheets[i];
if (sheet->IsApplicable()) {
- aStyleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ aStyleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
}
AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
- nsStyleSet::eAgentSheet);
+ SheetType::Agent);
AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet],
- nsStyleSet::eUserSheet);
+ SheetType::User);
AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
- nsStyleSet::eDocSheet);
+ SheetType::Doc);
}
static void
@@ -4180,7 +4129,7 @@ nsDocument::AddOnDemandBuiltInUASheet(CSSStyleSheet* aSheet)
// do not override Firefox OS/Mobile's content.css sheet. Maybe we should
// have an insertion point to match the order of
// nsDocumentViewer::CreateStyleSet though?
- shell->StyleSet()->PrependStyleSheet(nsStyleSet::eAgentSheet, aSheet);
+ shell->StyleSet()->PrependStyleSheet(SheetType::Agent, aSheet);
}
}
@@ -4412,20 +4361,20 @@ nsDocument::NotifyStyleSheetApplicableStateChanged()
}
}
-static nsStyleSet::sheetType
+static SheetType
ConvertAdditionalSheetType(nsIDocument::additionalSheetType aType)
{
switch(aType) {
case nsIDocument::eAgentSheet:
- return nsStyleSet::eAgentSheet;
+ return SheetType::Agent;
case nsIDocument::eUserSheet:
- return nsStyleSet::eUserSheet;
+ return SheetType::User;
case nsIDocument::eAuthorSheet:
- return nsStyleSet::eDocSheet;
+ return SheetType::Doc;
default:
- NS_ASSERTION(false, "wrong type");
+ MOZ_ASSERT(false, "wrong type");
// we must return something although this should never happen
- return nsStyleSet::eSheetTypeCount;
+ return SheetType::Count;
}
}
@@ -4480,7 +4429,7 @@ nsDocument::AddAdditionalStyleSheet(additionalSheetType aType, nsIStyleSheet* aS
BeginUpdate(UPDATE_STYLE);
nsCOMPtr shell = GetShell();
if (shell) {
- nsStyleSet::sheetType type = ConvertAdditionalSheetType(aType);
+ SheetType type = ConvertAdditionalSheetType(aType);
shell->StyleSet()->AppendStyleSheet(type, aSheet);
}
@@ -4508,7 +4457,7 @@ nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheet
MOZ_ASSERT(sheetRef->IsApplicable());
nsCOMPtr shell = GetShell();
if (shell) {
- nsStyleSet::sheetType type = ConvertAdditionalSheetType(aType);
+ SheetType type = ConvertAdditionalSheetType(aType);
shell->StyleSet()->RemoveStyleSheet(type, sheetRef);
}
}
@@ -7609,42 +7558,36 @@ nsIDocument::GetCompatMode(nsString& aCompatMode) const
}
}
-static void BlastSubtreeToPieces(nsINode *aNode);
-
-PLDHashOperator
-BlastFunc(nsAttrHashKey::KeyType aKey, Attr *aData, void* aUserArg)
-{
- nsCOMPtr *attr =
- static_cast*>(aUserArg);
-
- *attr = aData;
-
- NS_ASSERTION(attr->get(),
- "non-nsIAttribute somehow made it into the hashmap?!");
-
- return PL_DHASH_STOP;
-}
-
-static void
-BlastSubtreeToPieces(nsINode *aNode)
+void
+nsDOMAttributeMap::BlastSubtreeToPieces(nsINode *aNode)
{
if (aNode->IsElement()) {
Element *element = aNode->AsElement();
const nsDOMAttributeMap *map = element->GetAttributeMap();
if (map) {
nsCOMPtr attr;
- while (map->Enumerate(BlastFunc, &attr) > 0) {
+
+ // This non-standard style of iteration is presumably used because some
+ // of the code in the loop body can trigger element removal, which
+ // invalidates the iterator.
+ while (true) {
+ auto iter = map->mAttributeCache.ConstIter();
+ if (iter.Done()) {
+ break;
+ }
+ nsCOMPtr attr = iter.UserData();
+ NS_ASSERTION(attr.get(),
+ "non-nsIAttribute somehow made it into the hashmap?!");
+
BlastSubtreeToPieces(attr);
-#ifdef DEBUG
- nsresult rv =
-#endif
+ DebugOnly rv =
element->UnsetAttr(attr->NodeInfo()->NamespaceID(),
attr->NodeInfo()->NameAtom(),
false);
// XXX Should we abort here?
- NS_ASSERTION(NS_SUCCEEDED(rv), "Uhoh, UnsetAttr shouldn't fail!");
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Uh-oh, UnsetAttr shouldn't fail!");
}
}
}
@@ -7811,7 +7754,7 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
if (rv.Failed()) {
// Disconnect all nodes from their parents, since some have the old document
// as their ownerDocument and some have this as their ownerDocument.
- BlastSubtreeToPieces(adoptedNode);
+ nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
if (!sameDocument && oldDocument) {
uint32_t count = nodesWithProperties.Count();
@@ -7840,7 +7783,7 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
if (rv.Failed()) {
// Disconnect all nodes from their parents.
- BlastSubtreeToPieces(adoptedNode);
+ nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
return nullptr;
}
@@ -8869,11 +8812,6 @@ nsDocument::Destroy()
mRegistry = nullptr;
- nsCOMPtr swm = mozilla::services::GetServiceWorkerManager();
- if (swm) {
- swm->MaybeStopControlling(this);
- }
-
// XXX We really should let cycle collection do this, but that currently still
// leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
ReleaseWrapper(static_cast(this));
@@ -8885,6 +8823,19 @@ nsDocument::RemovedFromDocShell()
if (mRemovedFromDocShell)
return;
+ using mozilla::dom::workers::ServiceWorkerManager;
+ RefPtr swm = ServiceWorkerManager::GetInstance();
+ if (swm) {
+ ErrorResult error;
+ if (swm->IsControlled(this, error)) {
+ imgLoader* loader = nsContentUtils::GetImgLoaderForDocument(this);
+ if (loader) {
+ loader->ClearCacheForControlledDocument(this);
+ }
+ }
+ swm->MaybeStopControlling(this);
+ }
+
mRemovedFromDocShell = true;
EnumerateActivityObservers(NotifyActivityChanged, nullptr);
@@ -10454,12 +10405,8 @@ nsDocument::AddImage(imgIRequest* aImage)
// If this is the first insertion and we're locking images, lock this image
// too.
- if (oldCount == 0) {
- if (mLockingImages)
- rv = aImage->LockImage();
- if (NS_SUCCEEDED(rv) && (!sOnloadDecodeLimit ||
- mImageTracker.Count() < sOnloadDecodeLimit))
- rv = aImage->StartDecoding();
+ if (oldCount == 0 && mLockingImages) {
+ rv = aImage->LockImage();
}
// If this is the first insertion and we're animating images, request
@@ -10590,7 +10537,6 @@ PLDHashOperator LockEnumerator(imgIRequest* aKey,
void* userArg)
{
aKey->LockImage();
- aKey->RequestDecode();
return PL_DHASH_NEXT;
}
@@ -11640,6 +11586,19 @@ nsDocument::FullScreenStackTop()
return element;
}
+/* virtual */ nsTArray
+nsDocument::GetFullscreenStack() const
+{
+ nsTArray elements;
+ for (const nsWeakPtr& ptr : mFullScreenStack) {
+ if (nsCOMPtr elem = do_QueryReferent(ptr)) {
+ MOZ_ASSERT(elem->State().HasState(NS_EVENT_STATE_FULL_SCREEN));
+ elements.AppendElement(elem);
+ }
+ }
+ return elements;
+}
+
// Returns true if aDoc is in the focused tab in the active window.
static bool
IsInActiveTab(nsIDocument* aDoc)
diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h
index 82852ad3c1..2496b8aae8 100644
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1183,6 +1183,7 @@ public:
virtual Element* FindImageMap(const nsAString& aNormalizedMapName) override;
virtual Element* GetFullScreenElement() override;
+ virtual nsTArray GetFullscreenStack() const override;
virtual void AsyncRequestFullScreen(Element* aElement,
mozilla::dom::FullScreenOptions& aOptions) override;
virtual void RestorePreviousFullScreenState() override;
@@ -1502,7 +1503,7 @@ protected:
void RemoveDocStyleSheetsFromStyleSets();
void RemoveStyleSheetsFromStyleSets(nsCOMArray& aSheets,
- nsStyleSet::sheetType aType);
+ mozilla::SheetType aType);
void ResetStylesheetsToURI(nsIURI* aURI);
void FillStyleSet(nsStyleSet* aStyleSet);
@@ -1552,7 +1553,7 @@ protected:
nsCOMArray mStyleSheets;
nsCOMArray mOnDemandBuiltInUASheets;
- nsCOMArray mAdditionalSheets[SheetTypeCount];
+ nsCOMArray mAdditionalSheets[AdditionalSheetTypeCount];
// Array of observers
nsTObserverArray mObservers;
diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp
index 19df14811e..36cf38521f 100644
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -121,26 +121,17 @@ nsFrameMessageManager::~nsFrameMessageManager()
}
}
-static PLDHashOperator
-CycleCollectorTraverseListeners(const nsAString& aKey,
- nsAutoTObserverArray* aListeners,
- void* aCb)
-{
- nsCycleCollectionTraversalCallback* cb =
- static_cast (aCb);
- uint32_t count = aListeners->Length();
- for (uint32_t i = 0; i < count; ++i) {
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "listeners[i] mStrongListener");
- cb->NoteXPCOMChild(aListeners->ElementAt(i).mStrongListener.get());
- }
- return PL_DHASH_NEXT;
-}
-
NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager)
- tmp->mListeners.EnumerateRead(CycleCollectorTraverseListeners,
- static_cast(&cb));
+ for (auto iter = tmp->mListeners.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoTObserverArray* listeners = iter.UserData();
+ uint32_t count = listeners->Length();
+ for (uint32_t i = 0; i < count; ++i) {
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "listeners[i] mStrongListener");
+ cb.NoteXPCOMChild(listeners->ElementAt(i).mStrongListener.get());
+ }
+ }
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildManagers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
@@ -419,35 +410,6 @@ nsFrameMessageManager::RemoveMessageListener(const nsAString& aMessage,
return NS_OK;
}
-#ifdef DEBUG
-typedef struct
-{
- nsCOMPtr mCanonical;
- nsWeakPtr mWeak;
-} CanonicalCheckerParams;
-
-static PLDHashOperator
-CanonicalChecker(const nsAString& aKey,
- nsAutoTObserverArray* aListeners,
- void* aParams)
-{
- CanonicalCheckerParams* params =
- static_cast (aParams);
-
- uint32_t count = aListeners->Length();
- for (uint32_t i = 0; i < count; i++) {
- if (!aListeners->ElementAt(i).mWeakListener) {
- continue;
- }
- nsCOMPtr otherCanonical =
- do_QueryReferent(aListeners->ElementAt(i).mWeakListener);
- MOZ_ASSERT((params->mCanonical == otherCanonical) ==
- (params->mWeak == aListeners->ElementAt(i).mWeakListener));
- }
- return PL_DHASH_NEXT;
-}
-#endif
-
NS_IMETHODIMP
nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
nsIMessageListener* aListener)
@@ -461,10 +423,17 @@ nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
// this to happen; it will break e.g. RemoveWeakMessageListener. So let's
// check that we're not getting ourselves into that situation.
nsCOMPtr canonical = do_QueryInterface(aListener);
- CanonicalCheckerParams params;
- params.mCanonical = canonical;
- params.mWeak = weak;
- mListeners.EnumerateRead(CanonicalChecker, (void*)¶ms);
+ for (auto iter = mListeners.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoTObserverArray* listeners = iter.UserData();
+ uint32_t count = listeners->Length();
+ for (uint32_t i = 0; i < count; i++) {
+ nsWeakPtr weakListener = listeners->ElementAt(i).mWeakListener;
+ if (weakListener) {
+ nsCOMPtr otherCanonical = do_QueryReferent(weakListener);
+ MOZ_ASSERT((canonical == otherCanonical) == (weak == weakListener));
+ }
+ }
+ }
#endif
nsAutoTObserverArray* listeners =
@@ -1488,55 +1457,45 @@ protected:
NS_IMPL_ISUPPORTS(MessageManagerReporter, nsIMemoryReporter)
-static PLDHashOperator
-CollectMessageListenerData(const nsAString& aKey,
- nsAutoTObserverArray* aListeners,
- void* aData)
-{
- MessageManagerReferentCount* referentCount =
- static_cast(aData);
-
- uint32_t listenerCount = aListeners->Length();
- if (!listenerCount) {
- return PL_DHASH_NEXT;
- }
-
- nsString key(aKey);
- uint32_t oldCount = 0;
- referentCount->mMessageCounter.Get(key, &oldCount);
- uint32_t currentCount = oldCount + listenerCount;
- referentCount->mMessageCounter.Put(key, currentCount);
-
- // Keep track of messages that have a suspiciously large
- // number of referents (symptom of leak).
- if (currentCount == MessageManagerReporter::kSuspectReferentCount) {
- referentCount->mSuspectMessages.AppendElement(key);
- }
-
- for (uint32_t i = 0; i < listenerCount; ++i) {
- const nsMessageListenerInfo& listenerInfo =
- aListeners->ElementAt(i);
- if (listenerInfo.mWeakListener) {
- nsCOMPtr referent =
- do_QueryReferent(listenerInfo.mWeakListener);
- if (referent) {
- referentCount->mWeakAlive++;
- } else {
- referentCount->mWeakDead++;
- }
- } else {
- referentCount->mStrong++;
- }
- }
- return PL_DHASH_NEXT;
-}
-
void
MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
MessageManagerReferentCount* aReferentCount)
{
- aMessageManager->mListeners.EnumerateRead(CollectMessageListenerData,
- aReferentCount);
+ for (auto it = aMessageManager->mListeners.Iter(); !it.Done(); it.Next()) {
+ nsAutoTObserverArray* listeners =
+ it.UserData();
+ uint32_t listenerCount = listeners->Length();
+ if (listenerCount == 0) {
+ continue;
+ }
+
+ nsString key(it.Key());
+ uint32_t oldCount = 0;
+ aReferentCount->mMessageCounter.Get(key, &oldCount);
+ uint32_t currentCount = oldCount + listenerCount;
+ aReferentCount->mMessageCounter.Put(key, currentCount);
+
+ // Keep track of messages that have a suspiciously large
+ // number of referents (symptom of leak).
+ if (currentCount == MessageManagerReporter::kSuspectReferentCount) {
+ aReferentCount->mSuspectMessages.AppendElement(key);
+ }
+
+ for (uint32_t i = 0; i < listenerCount; ++i) {
+ const nsMessageListenerInfo& listenerInfo = listeners->ElementAt(i);
+ if (listenerInfo.mWeakListener) {
+ nsCOMPtr referent =
+ do_QueryReferent(listenerInfo.mWeakListener);
+ if (referent) {
+ aReferentCount->mWeakAlive++;
+ } else {
+ aReferentCount->mWeakDead++;
+ }
+ } else {
+ aReferentCount->mStrong++;
+ }
+ }
+ }
// Add referent count in child managers because the listeners
// participate in messages dispatched from parent message manager.
@@ -2186,24 +2145,20 @@ NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
return NS_OK;
}
-static PLDHashOperator
-CycleCollectorMarkListeners(const nsAString& aKey,
- nsAutoTObserverArray* aListeners,
- void* aData)
-{
- uint32_t count = aListeners->Length();
- for (uint32_t i = 0; i < count; i++) {
- if (aListeners->ElementAt(i).mStrongListener) {
- xpc_TryUnmarkWrappedGrayObject(aListeners->ElementAt(i).mStrongListener);
- }
- }
- return PL_DHASH_NEXT;
-}
-
bool
nsFrameMessageManager::MarkForCC()
{
- mListeners.EnumerateRead(CycleCollectorMarkListeners, nullptr);
+ for (auto iter = mListeners.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoTObserverArray* listeners = iter.UserData();
+ uint32_t count = listeners->Length();
+ for (uint32_t i = 0; i < count; i++) {
+ nsCOMPtr strongListener =
+ listeners->ElementAt(i).mStrongListener;
+ if (strongListener) {
+ xpc_TryUnmarkWrappedGrayObject(strongListener);
+ }
+ }
+ }
if (mRefCnt.IsPurple()) {
mRefCnt.RemovePurple();
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 248ac3956b..1ff4f25fa4 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -13403,18 +13403,6 @@ nsGlobalWindow::RemoveGamepad(uint32_t aIndex)
mGamepads.Remove(aIndex);
}
-// static
-PLDHashOperator
-nsGlobalWindow::EnumGamepadsForGet(const uint32_t& aKey, Gamepad* aData,
- void* aUserArg)
-{
- nsTArray >* array =
- static_cast >*>(aUserArg);
- array->EnsureLengthAtLeast(aData->Index() + 1);
- (*array)[aData->Index()] = aData;
- return PL_DHASH_NEXT;
-}
-
void
nsGlobalWindow::GetGamepads(nsTArray >& aGamepads)
{
@@ -13422,7 +13410,11 @@ nsGlobalWindow::GetGamepads(nsTArray >& aGamepads)
aGamepads.Clear();
// mGamepads.Count() may not be sufficient, but it's not harmful.
aGamepads.SetCapacity(mGamepads.Count());
- mGamepads.EnumerateRead(EnumGamepadsForGet, &aGamepads);
+ for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
+ Gamepad* gamepad = iter.UserData();
+ aGamepads.EnsureLengthAtLeast(gamepad->Index() + 1);
+ aGamepads[gamepad->Index()] = gamepad;
+ }
}
already_AddRefed
@@ -13452,22 +13444,15 @@ nsGlobalWindow::HasSeenGamepadInput()
return mHasSeenGamepadInput;
}
-// static
-PLDHashOperator
-nsGlobalWindow::EnumGamepadsForSync(const uint32_t& aKey, Gamepad* aData,
- void* aUserArg)
-{
- RefPtr gamepadsvc(GamepadService::GetService());
- gamepadsvc->SyncGamepadState(aKey, aData);
- return PL_DHASH_NEXT;
-}
-
void
nsGlobalWindow::SyncGamepadState()
{
MOZ_ASSERT(IsInnerWindow());
if (mHasSeenGamepadInput) {
- mGamepads.EnumerateRead(EnumGamepadsForSync, nullptr);
+ RefPtr gamepadsvc(GamepadService::GetService());
+ for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
+ gamepadsvc->SyncGamepadState(iter.Key(), iter.UserData());
+ }
}
}
#endif // MOZ_GAMEPAD
@@ -13510,9 +13495,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow,
tmp->mMessageManager.get())->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
}
-
- tmp->mGroupMessageManagers.EnumerateRead(DisconnectGroupMessageManager, nullptr);
- tmp->mGroupMessageManagers.Clear();
+ tmp->DisconnectAndClearGroupMessageManagers();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGroupMessageManagers)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h
index cadaa2e46d..98b82013d5 100644
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -765,12 +765,6 @@ public:
void SetHasSeenGamepadInput(bool aHasSeen);
bool HasSeenGamepadInput();
void SyncGamepadState();
- static PLDHashOperator EnumGamepadsForSync(const uint32_t& aKey,
- mozilla::dom::Gamepad* aData,
- void* aUserArg);
- static PLDHashOperator EnumGamepadsForGet(const uint32_t& aKey,
- mozilla::dom::Gamepad* aData,
- void* aUserArg);
#endif
// Inner windows only.
@@ -1882,15 +1876,15 @@ public:
static already_AddRefed Create(nsGlobalWindow *aOuterWindow);
- static PLDHashOperator
- DisconnectGroupMessageManager(const nsAString& aKey,
- nsIMessageBroadcaster* aMM,
- void* aUserArg)
+ void DisconnectAndClearGroupMessageManagers()
{
- if (aMM) {
- static_cast(aMM)->Disconnect();
+ for (auto iter = mGroupMessageManagers.Iter(); !iter.Done(); iter.Next()) {
+ nsIMessageBroadcaster* mm = iter.UserData();
+ if (mm) {
+ static_cast(mm)->Disconnect();
+ }
}
- return PL_DHASH_NEXT;
+ mGroupMessageManagers.Clear();
}
protected:
@@ -1907,8 +1901,7 @@ protected:
MOZ_ASSERT(mCleanMessageManager,
"chrome windows may always disconnect the msg manager");
- mGroupMessageManagers.EnumerateRead(DisconnectGroupMessageManager, nullptr);
- mGroupMessageManagers.Clear();
+ DisconnectAndClearGroupMessageManagers();
if (mMessageManager) {
static_cast(
diff --git a/dom/base/nsHostObjectProtocolHandler.cpp b/dom/base/nsHostObjectProtocolHandler.cpp
index ea52e6ed28..d5e4843fb6 100644
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -66,15 +66,125 @@ class BlobURLsReporter final : public nsIMemoryReporter
NS_IMETHOD CollectReports(nsIHandleReportCallback* aCallback,
nsISupports* aData, bool aAnonymize) override
{
- EnumArg env;
- env.mCallback = aCallback;
- env.mData = aData;
- env.mAnonymize = aAnonymize;
-
- if (gDataTable) {
- gDataTable->EnumerateRead(CountCallback, &env);
- gDataTable->EnumerateRead(ReportCallback, &env);
+ if (!gDataTable) {
+ return NS_OK;
}
+
+ nsDataHashtable, uint32_t> refCounts;
+
+ // Determine number of URLs per blob, to handle the case where it's > 1.
+ for (auto iter = gDataTable->Iter(); !iter.Done(); iter.Next()) {
+ nsCOMPtr blob =
+ do_QueryInterface(iter.UserData()->mObject);
+ if (blob) {
+ refCounts.Put(blob, refCounts.Get(blob) + 1);
+ }
+ }
+
+ for (auto iter = gDataTable->Iter(); !iter.Done(); iter.Next()) {
+ nsCStringHashKey::KeyType key = iter.Key();
+ DataInfo* info = iter.UserData();
+
+ nsCOMPtr tmp = do_QueryInterface(info->mObject);
+ RefPtr blob =
+ static_cast(tmp.get());
+
+ if (blob) {
+ NS_NAMED_LITERAL_CSTRING(desc,
+ "A blob URL allocated with URL.createObjectURL; the referenced "
+ "blob cannot be freed until all URLs for it have been explicitly "
+ "invalidated with URL.revokeObjectURL.");
+ nsAutoCString path, url, owner, specialDesc;
+ nsCOMPtr principalURI;
+ uint64_t size = 0;
+ uint32_t refCount = 1;
+ DebugOnly blobWasCounted;
+
+ blobWasCounted = refCounts.Get(blob, &refCount);
+ MOZ_ASSERT(blobWasCounted);
+ MOZ_ASSERT(refCount > 0);
+
+ bool isMemoryFile = blob->IsMemoryFile();
+
+ if (isMemoryFile) {
+ ErrorResult rv;
+ size = blob->GetSize(rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ rv.SuppressException();
+ size = 0;
+ }
+ }
+
+ path = isMemoryFile ? "memory-blob-urls/" : "file-blob-urls/";
+ BuildPath(path, key, info, aAnonymize);
+
+ if (refCount > 1) {
+ nsAutoCString addrStr;
+
+ addrStr = "0x";
+ addrStr.AppendInt((uint64_t)(nsIDOMBlob*)blob, 16);
+
+ path += " ";
+ path.AppendInt(refCount);
+ path += "@";
+ path += addrStr;
+
+ specialDesc = desc;
+ specialDesc += "\n\nNOTE: This blob (address ";
+ specialDesc += addrStr;
+ specialDesc += ") has ";
+ specialDesc.AppendInt(refCount);
+ specialDesc += " URLs.";
+ if (isMemoryFile) {
+ specialDesc += " Its size is divided ";
+ specialDesc += refCount > 2 ? "among" : "between";
+ specialDesc += " them in this report.";
+ }
+ }
+
+ const nsACString& descString = specialDesc.IsEmpty()
+ ? static_cast(desc)
+ : static_cast(specialDesc);
+ if (isMemoryFile) {
+ aCallback->Callback(EmptyCString(),
+ path,
+ KIND_OTHER,
+ UNITS_BYTES,
+ size / refCount,
+ descString,
+ aData);
+ } else {
+ aCallback->Callback(EmptyCString(),
+ path,
+ KIND_OTHER,
+ UNITS_COUNT,
+ 1,
+ descString,
+ aData);
+ }
+ } else {
+ // Just report the path for the DOMMediaStream or MediaSource.
+ nsCOMPtr
+ ms(do_QueryInterface(info->mObject));
+ nsAutoCString path;
+ path = ms ? "media-source-urls/" : "dom-media-stream-urls/";
+ BuildPath(path, key, info, aAnonymize);
+
+ NS_NAMED_LITERAL_CSTRING(desc,
+ "An object URL allocated with URL.createObjectURL; the referenced "
+ "data cannot be freed until all URLs for it have been explicitly "
+ "invalidated with URL.revokeObjectURL.");
+
+ aCallback->Callback(EmptyCString(),
+ path,
+ KIND_OTHER,
+ UNITS_COUNT,
+ 1,
+ desc,
+ aData);
+ }
+ }
+
return NS_OK;
}
@@ -143,138 +253,41 @@ class BlobURLsReporter final : public nsIMemoryReporter
private:
~BlobURLsReporter() {}
- struct EnumArg {
- nsIHandleReportCallback* mCallback;
- nsISupports* mData;
- bool mAnonymize;
- nsDataHashtable, uint32_t> mRefCounts;
- };
-
- // Determine number of URLs per blob, to handle the case where it's > 1.
- static PLDHashOperator CountCallback(nsCStringHashKey::KeyType aKey,
- DataInfo* aInfo,
- void* aUserArg)
+ static void BuildPath(nsAutoCString& path,
+ nsCStringHashKey::KeyType aKey,
+ DataInfo* aInfo,
+ bool anonymize)
{
- EnumArg* envp = static_cast(aUserArg);
- nsCOMPtr blob;
-
- blob = do_QueryInterface(aInfo->mObject);
- if (blob) {
- envp->mRefCounts.Put(blob, envp->mRefCounts.Get(blob) + 1);
+ nsCOMPtr principalURI;
+ nsAutoCString url, owner;
+ if (NS_SUCCEEDED(aInfo->mPrincipal->GetURI(getter_AddRefs(principalURI))) &&
+ principalURI != nullptr &&
+ NS_SUCCEEDED(principalURI->GetSpec(owner)) &&
+ !owner.IsEmpty()) {
+ owner.ReplaceChar('/', '\\');
+ path += "owner(";
+ if (anonymize) {
+ path += "";
+ } else {
+ path += owner;
+ }
+ path += ")";
+ } else {
+ path += "owner unknown";
}
- return PL_DHASH_NEXT;
- }
-
- static PLDHashOperator ReportCallback(nsCStringHashKey::KeyType aKey,
- DataInfo* aInfo,
- void* aUserArg)
- {
- EnumArg* envp = static_cast(aUserArg);
- nsCOMPtr tmp = do_QueryInterface(aInfo->mObject);
- RefPtr blob = static_cast(tmp.get());
-
- if (blob) {
- NS_NAMED_LITERAL_CSTRING
- (desc, "A blob URL allocated with URL.createObjectURL; the referenced "
- "blob cannot be freed until all URLs for it have been explicitly "
- "invalidated with URL.revokeObjectURL.");
- nsAutoCString path, url, owner, specialDesc;
- nsCOMPtr principalURI;
- uint64_t size = 0;
- uint32_t refCount = 1;
- DebugOnly blobWasCounted;
-
- blobWasCounted = envp->mRefCounts.Get(blob, &refCount);
- MOZ_ASSERT(blobWasCounted);
- MOZ_ASSERT(refCount > 0);
-
- bool isMemoryFile = blob->IsMemoryFile();
-
- if (isMemoryFile) {
- ErrorResult rv;
- size = blob->GetSize(rv);
- if (NS_WARN_IF(rv.Failed())) {
- rv.SuppressException();
- size = 0;
- }
- }
-
- path = isMemoryFile ? "memory-blob-urls/" : "file-blob-urls/";
- if (NS_SUCCEEDED(aInfo->mPrincipal->GetURI(getter_AddRefs(principalURI))) &&
- principalURI != nullptr &&
- NS_SUCCEEDED(principalURI->GetSpec(owner)) &&
- !owner.IsEmpty()) {
- owner.ReplaceChar('/', '\\');
- path += "owner(";
- if (envp->mAnonymize) {
- path += "";
- } else {
- path += owner;
- }
- path += ")";
- } else {
- path += "owner unknown";
- }
- path += "/";
- if (envp->mAnonymize) {
- path += "";
- } else {
- path += aInfo->mStack;
- }
- url = aKey;
- url.ReplaceChar('/', '\\');
- if (envp->mAnonymize) {
- path += "";
- } else {
- path += url;
- }
- if (refCount > 1) {
- nsAutoCString addrStr;
-
- addrStr = "0x";
- addrStr.AppendInt((uint64_t)(nsIDOMBlob*)blob, 16);
-
- path += " ";
- path.AppendInt(refCount);
- path += "@";
- path += addrStr;
-
- specialDesc = desc;
- specialDesc += "\n\nNOTE: This blob (address ";
- specialDesc += addrStr;
- specialDesc += ") has ";
- specialDesc.AppendInt(refCount);
- specialDesc += " URLs.";
- if (isMemoryFile) {
- specialDesc += " Its size is divided ";
- specialDesc += refCount > 2 ? "among" : "between";
- specialDesc += " them in this report.";
- }
- }
-
- const nsACString& descString = specialDesc.IsEmpty()
- ? static_cast(desc)
- : static_cast(specialDesc);
- if (isMemoryFile) {
- envp->mCallback->Callback(EmptyCString(),
- path,
- KIND_OTHER,
- UNITS_BYTES,
- size / refCount,
- descString,
- envp->mData);
- }
- else {
- envp->mCallback->Callback(EmptyCString(),
- path,
- KIND_OTHER,
- UNITS_COUNT,
- 1,
- descString,
- envp->mData);
- }
+ path += "/";
+ if (anonymize) {
+ path += "";
+ } else {
+ path += aInfo->mStack;
+ }
+ url = aKey;
+ url.ReplaceChar('/', '\\');
+ if (anonymize) {
+ path += "";
+ } else {
+ path += url;
}
- return PL_DHASH_NEXT;
}
};
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index 598aee0067..fa70b1dedf 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -160,8 +160,8 @@ struct FullScreenOptions {
} // namespace mozilla
#define NS_IDOCUMENT_IID \
-{ 0x72391609, 0x673d, 0x4bec, \
- { 0xbd, 0x75, 0x64, 0xbf, 0x1f, 0x6a, 0x6b, 0x5e } }
+{ 0x5f51e18c, 0x9e0e, 0x4dc0, \
+ { 0x9f, 0x08, 0x7a, 0x32, 0x65, 0x52, 0xea, 0x11 } }
// Enum for requesting a particular type of document when creating a doc
enum DocumentFlavor {
@@ -957,7 +957,7 @@ public:
eAgentSheet,
eUserSheet,
eAuthorSheet,
- SheetTypeCount
+ AdditionalSheetTypeCount
};
virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI) = 0;
@@ -1105,6 +1105,11 @@ public:
*/
virtual Element* GetFullScreenElement() = 0;
+ /**
+ * Returns all elements in the fullscreen stack in the insertion order.
+ */
+ virtual nsTArray GetFullscreenStack() const = 0;
+
/**
* Asynchronously requests that the document make aElement the fullscreen
* element, and move into fullscreen mode. The current fullscreen element
diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp
index ffd0c5af18..c3ea89d716 100644
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -793,37 +793,6 @@ CheckForGhostWindowsEnumerator(nsISupports *aKey, TimeStamp& aTimeStamp,
return PL_DHASH_NEXT;
}
-struct GetNonDetachedWindowDomainsEnumeratorData
-{
- nsTHashtable *nonDetachedDomains;
- nsIEffectiveTLDService *tldService;
-};
-
-static PLDHashOperator
-GetNonDetachedWindowDomainsEnumerator(const uint64_t& aId, nsGlobalWindow* aWindow,
- void* aClosure)
-{
- GetNonDetachedWindowDomainsEnumeratorData *data =
- static_cast(aClosure);
-
- // Null outer window implies null top, but calling GetTop() when there's no
- // outer window causes us to spew debug warnings.
- if (!aWindow->GetOuterWindow() || !aWindow->GetTopInternal()) {
- // This window is detached, so we don't care about its domain.
- return PL_DHASH_NEXT;
- }
-
- nsCOMPtr uri = GetWindowURI(aWindow);
-
- nsAutoCString domain;
- if (uri) {
- data->tldService->GetBaseDomain(uri, 0, domain);
- }
-
- data->nonDetachedDomains->PutEntry(domain);
- return PL_DHASH_NEXT;
-}
-
/**
* Iterate over mDetachedWindows and update it to reflect the current state of
* the world. In particular:
@@ -865,10 +834,22 @@ nsWindowMemoryReporter::CheckForGhostWindows(
nsTHashtable nonDetachedWindowDomains;
// Populate nonDetachedWindowDomains.
- GetNonDetachedWindowDomainsEnumeratorData nonDetachedEnumData =
- { &nonDetachedWindowDomains, tldService };
- windowsById->EnumerateRead(GetNonDetachedWindowDomainsEnumerator,
- &nonDetachedEnumData);
+ for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
+ // Null outer window implies null top, but calling GetTop() when there's no
+ // outer window causes us to spew debug warnings.
+ nsGlobalWindow* window = iter.UserData();
+ if (!window->GetOuterWindow() || !window->GetTopInternal()) {
+ // This window is detached, so we don't care about its domain.
+ continue;
+ }
+
+ nsCOMPtr uri = GetWindowURI(window);
+ nsAutoCString domain;
+ if (uri) {
+ tldService->GetBaseDomain(uri, 0, domain);
+ }
+ nonDetachedWindowDomains.PutEntry(domain);
+ }
// Update mDetachedWindows and write the ghost window IDs into aOutGhostIDs,
// if it's not null.
diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg
index c05d684bf5..c60d164623 100644
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -82,3 +82,4 @@ MSG_DEF(MSG_NO_ACTIVE_WORKER, 1, JSEXN_TYPEERR, "No active worker for scope {0}.
MSG_DEF(MSG_NOTIFICATION_PERMISSION_DENIED, 0, JSEXN_TYPEERR, "Permission to show Notification denied.")
MSG_DEF(MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER, 0, JSEXN_TYPEERR, "Notification constructor cannot be used in ServiceWorkerGlobalScope. Use registration.showNotification() instead.")
MSG_DEF(MSG_INVALID_SCOPE, 2, JSEXN_TYPEERR, "Invalid scope trying to resolve {0} with base URL {1}.")
+MSG_DEF(MSG_INVALID_KEYFRAME_OFFSETS, 0, JSEXN_TYPEERR, "Keyframes with specified offsets must be in order and all be in the range [0, 1].")
diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp
index c443dbd0bf..80ac49e204 100644
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -158,6 +158,7 @@ CreateException(JSContext* aCx, nsresult aRv, const nsACString& aMessage)
case NS_ERROR_MODULE_DOM_INDEXEDDB:
case NS_ERROR_MODULE_DOM_FILEHANDLE:
case NS_ERROR_MODULE_DOM_BLUETOOTH:
+ case NS_ERROR_MODULE_DOM_ANIM:
if (aMessage.IsEmpty()) {
return DOMException::Create(aRv);
}
diff --git a/dom/events/test/chrome.ini b/dom/events/test/chrome.ini
index a42b9e612d..d92539399c 100644
--- a/dom/events/test/chrome.ini
+++ b/dom/events/test/chrome.ini
@@ -21,4 +21,7 @@ support-files =
[test_bug617528.xul]
[test_bug679494.xul]
[test_bug930374-chrome.html]
+[test_bug1128787-1.html]
+[test_bug1128787-2.html]
+[test_bug1128787-3.html]
[test_eventctors.xul]
diff --git a/dom/events/test/test_bug1128787-1.html b/dom/events/test/test_bug1128787-1.html
new file mode 100644
index 0000000000..947bace386
--- /dev/null
+++ b/dom/events/test/test_bug1128787-1.html
@@ -0,0 +1,54 @@
+
+
+
+
+
+ Test for Bug 1128787
+
+
+
+
+
+
+Mozilla Bug 1128787
+
+
+
+
+
+
+
+
+
+
diff --git a/dom/events/test/test_bug1128787-2.html b/dom/events/test/test_bug1128787-2.html
new file mode 100644
index 0000000000..3e2a6cadaa
--- /dev/null
+++ b/dom/events/test/test_bug1128787-2.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+ Test for Bug 1128787
+
+
+
+
+
+
+Mozilla Bug 1128787
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dom/events/test/test_bug1128787-3.html b/dom/events/test/test_bug1128787-3.html
new file mode 100644
index 0000000000..a7b86cdb67
--- /dev/null
+++ b/dom/events/test/test_bug1128787-3.html
@@ -0,0 +1,54 @@
+
+
+
+
+
+ Test for Bug 1128787
+
+
+
+
+
+
+Mozilla Bug 1128787
+
+
+
+
+
+
+
+
+
+
diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp
index e016742ed9..2347432ef3 100644
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -110,6 +110,10 @@
#include "nsCharsetSource.h"
#include "nsIStringBundle.h"
#include "nsDOMClassInfo.h"
+#include "nsFocusManager.h"
+#include "nsIFrame.h"
+#include "nsIContent.h"
+#include "nsLayoutStylesheetCache.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -143,26 +147,6 @@ static bool ConvertToMidasInternalCommand(const nsAString & inCommandID,
// ==================================================================
// =
// ==================================================================
-static nsresult
-RemoveFromAgentSheets(nsCOMArray &aAgentSheets, const nsAString& url)
-{
- nsCOMPtr uri;
- nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
- NS_ENSURE_SUCCESS(rv, rv);
-
- for (int32_t i = aAgentSheets.Count() - 1; i >= 0; --i) {
- nsIStyleSheet* sheet = aAgentSheets[i];
- nsIURI* sheetURI = sheet->GetSheetURI();
-
- bool equals = false;
- uri->Equals(sheetURI, &equals);
- if (equals) {
- aAgentSheets.RemoveObjectAt(i);
- }
- }
-
- return NS_OK;
-}
nsresult
NS_NewHTMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData)
@@ -1424,6 +1408,9 @@ nsHTMLDocument::Open(JSContext* cx,
const nsAString& aReplace,
ErrorResult& rv)
{
+ // Implements the "When called with two arguments (or fewer)" steps here:
+ // https://html.spec.whatwg.org/multipage/webappapis.html#opening-the-input-stream
+
NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast(this)),
"XOW should have caught this!");
if (!IsHTMLDocument() || mDisableDocWrite || !IsMasterDocument()) {
@@ -1564,7 +1551,7 @@ nsHTMLDocument::Open(JSContext* cx,
}
// The open occurred after the document finished loading.
- // So we reset the document and create a new one.
+ // So we reset the document and then reinitialize it.
nsCOMPtr channel;
nsCOMPtr group = do_QueryReferent(mDocumentLoadGroup);
rv = NS_NewChannel(getter_AddRefs(channel),
@@ -1640,8 +1627,9 @@ nsHTMLDocument::Open(JSContext* cx,
}
#endif
- // Should this pass true for aForceReuseInnerWindow?
- rv = window->SetNewDocument(this, nullptr, false);
+ // Per spec, we pass false here so that a new Window is created.
+ rv = window->SetNewDocument(this, nullptr,
+ /* aForceReuseInnerWindow */ false);
if (rv.Failed()) {
return nullptr;
}
@@ -2657,9 +2645,9 @@ nsHTMLDocument::TearingDownEditor(nsIEditor *aEditor)
nsCOMArray agentSheets;
presShell->GetAgentStyleSheets(agentSheets);
- RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
+ agentSheets.RemoveObject(nsLayoutStylesheetCache::ContentEditableSheet());
if (oldState == eDesignMode)
- RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css"));
+ agentSheets.RemoveObject(nsLayoutStylesheetCache::DesignModeSheet());
presShell->SetAgentStyleSheets(agentSheets);
@@ -2716,7 +2704,7 @@ nsHTMLDocument::EditingStateChanged()
}
if (mEditingState == eSettingUp || mEditingState == eTearingDown) {
- // XXX We shouldn't recurse.
+ // XXX We shouldn't recurse
return NS_OK;
}
@@ -2780,12 +2768,84 @@ nsHTMLDocument::EditingStateChanged()
bool makeWindowEditable = mEditingState == eOff;
bool updateState = false;
bool spellRecheckAll = false;
+ bool putOffToRemoveScriptBlockerUntilModifyingEditingState = false;
nsCOMPtr editor;
{
EditingState oldState = mEditingState;
nsAutoEditingState push(this, eSettingUp);
+ nsCOMPtr presShell = GetShell();
+ NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
+
+ // Before making this window editable, we need to modify UA style sheet
+ // because new style may change whether focused element will be focusable
+ // or not.
+ nsCOMArray agentSheets;
+ rv = presShell->GetAgentStyleSheets(agentSheets);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ CSSStyleSheet* contentEditableSheet =
+ nsLayoutStylesheetCache::ContentEditableSheet();
+
+ bool result;
+
+ if (!agentSheets.Contains(contentEditableSheet)) {
+ bool result = agentSheets.AppendObject(contentEditableSheet);
+ NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
+ }
+
+ // Should we update the editable state of all the nodes in the document? We
+ // need to do this when the designMode value changes, as that overrides
+ // specific states on the elements.
+ if (designMode) {
+ // designMode is being turned on (overrides contentEditable).
+ CSSStyleSheet* designModeSheet =
+ nsLayoutStylesheetCache::DesignModeSheet();
+ if (!agentSheets.Contains(designModeSheet)) {
+ result = agentSheets.AppendObject(designModeSheet);
+ NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
+ }
+
+ updateState = true;
+ spellRecheckAll = oldState == eContentEditable;
+ }
+ else if (oldState == eDesignMode) {
+ // designMode is being turned off (contentEditable is still on).
+ agentSheets.RemoveObject(nsLayoutStylesheetCache::DesignModeSheet());
+ updateState = true;
+ }
+
+ rv = presShell->SetAgentStyleSheets(agentSheets);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ presShell->ReconstructStyleData();
+
+ // Adjust focused element with new style but blur event shouldn't be fired
+ // until mEditingState is modified with newState.
+ nsAutoScriptBlocker scriptBlocker;
+ if (designMode) {
+ nsCOMPtr focusedWindow;
+ nsIContent* focusedContent =
+ nsFocusManager::GetFocusedDescendant(window, false,
+ getter_AddRefs(focusedWindow));
+ if (focusedContent) {
+ nsIFrame* focusedFrame = focusedContent->GetPrimaryFrame();
+ bool clearFocus = focusedFrame ? !focusedFrame->IsFocusable() :
+ !focusedContent->IsFocusable();
+ if (clearFocus) {
+ nsFocusManager* fm = nsFocusManager::GetFocusManager();
+ if (fm) {
+ fm->ClearFocus(window);
+ // If we need to dispatch blur event, we should put off after
+ // modifying mEditingState since blur event handler may change
+ // designMode state again.
+ putOffToRemoveScriptBlockerUntilModifyingEditingState = true;
+ }
+ }
+ }
+ }
+
if (makeWindowEditable) {
// Editing is being turned on (through designMode or contentEditable)
// Turn on editor.
@@ -2801,61 +2861,26 @@ nsHTMLDocument::EditingStateChanged()
if (!editor)
return NS_ERROR_FAILURE;
- nsCOMPtr presShell = GetShell();
- NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
-
// If we're entering the design mode, put the selection at the beginning of
// the document for compatibility reasons.
if (designMode && oldState == eOff) {
editor->BeginningOfDocument();
}
- nsCOMArray agentSheets;
- rv = presShell->GetAgentStyleSheets(agentSheets);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsCOMPtr uri;
- rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
- NS_ENSURE_SUCCESS(rv, rv);
-
- RefPtr sheet;
- rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
- NS_ENSURE_TRUE(sheet, rv);
-
- bool result = agentSheets.AppendObject(sheet);
- NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
-
- // Should we update the editable state of all the nodes in the document? We
- // need to do this when the designMode value changes, as that overrides
- // specific states on the elements.
- if (designMode) {
- // designMode is being turned on (overrides contentEditable).
- rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/designmode.css"));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
- NS_ENSURE_TRUE(sheet, rv);
-
- result = agentSheets.AppendObject(sheet);
- NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
-
- updateState = true;
- spellRecheckAll = oldState == eContentEditable;
+ if (putOffToRemoveScriptBlockerUntilModifyingEditingState) {
+ nsContentUtils::AddScriptBlocker();
}
- else if (oldState == eDesignMode) {
- // designMode is being turned off (contentEditable is still on).
- RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css"));
-
- updateState = true;
- }
-
- rv = presShell->SetAgentStyleSheets(agentSheets);
- NS_ENSURE_SUCCESS(rv, rv);
-
- presShell->ReconstructStyleData();
}
mEditingState = newState;
+ if (putOffToRemoveScriptBlockerUntilModifyingEditingState) {
+ nsContentUtils::RemoveScriptBlocker();
+ // If mEditingState is overwritten by another call and already disabled
+ // the editing, we shouldn't keep making window editable.
+ if (mEditingState == eOff) {
+ return NS_OK;
+ }
+ }
if (makeWindowEditable) {
// Set the editor to not insert br's on return when in p
@@ -3519,6 +3544,24 @@ nsHTMLDocument::QueryCommandSupported(const nsAString & commandID,
bool
nsHTMLDocument::QueryCommandSupported(const nsAString& commandID)
{
+ // Gecko technically supports all the clipboard commands including
+ // cut/copy/paste, but non-privileged content will be unable to call
+ // paste, and depending on the pref "dom.allow_cut_copy", cut and copy
+ // may also be disallowed to be called from non-privileged content.
+ // For that reason, we report the support status of corresponding
+ // command accordingly.
+ if (!nsContentUtils::IsCallerChrome()) {
+ if (commandID.LowerCaseEqualsLiteral("paste")) {
+ return false;
+ }
+ if (nsContentUtils::IsCutCopyRestricted()) {
+ if (commandID.LowerCaseEqualsLiteral("cut") ||
+ commandID.LowerCaseEqualsLiteral("copy")) {
+ return false;
+ }
+ }
+ }
+
// commandID is supported if it can be converted to a Midas command
nsAutoCString cmdToDispatch;
return ConvertToMidasInternalCommand(commandID, cmdToDispatch);
diff --git a/dom/html/test/file_fullscreen-ancestor-stacking-context.html b/dom/html/test/file_fullscreen-ancestor-stacking-context.html
deleted file mode 100644
index d0b7658c4e..0000000000
--- a/dom/html/test/file_fullscreen-ancestor-stacking-context.html
+++ /dev/null
@@ -1,134 +0,0 @@
-
-
-
-
- Test for Bug 1056203
-
-
-
-Mozilla Bug 1056203
-
-
-
-
-
-
-
-
-
diff --git a/dom/html/test/file_fullscreen-top-layer.html b/dom/html/test/file_fullscreen-top-layer.html
new file mode 100644
index 0000000000..9d3e9ef594
--- /dev/null
+++ b/dom/html/test/file_fullscreen-top-layer.html
@@ -0,0 +1,176 @@
+
+
+
+
+ Test for Bug 1126230
+
+
+
+
+
+
+
+Mozilla Bug 1126230
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini
index 80c2ee397b..2abf6f6f17 100644
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -46,7 +46,6 @@ support-files =
file_bug893537.html
file_formSubmission_img.jpg
file_formSubmission_text.txt
- file_fullscreen-ancestor-stacking-context.html
file_fullscreen-api-keys.html
file_fullscreen-api.html
file_fullscreen-denied-inner.html
@@ -63,6 +62,7 @@ support-files =
file_fullscreen-scrollbar.html
file_fullscreen-selector.html
file_fullscreen-svg-element.html
+ file_fullscreen-top-layer.html
file_fullscreen-utils.js
file_iframe_sandbox_a_if1.html
file_iframe_sandbox_a_if10.html
diff --git a/dom/html/test/test_fullscreen-api.html b/dom/html/test/test_fullscreen-api.html
index be257e6240..a94f737cd4 100644
--- a/dom/html/test/test_fullscreen-api.html
+++ b/dom/html/test/test_fullscreen-api.html
@@ -28,7 +28,6 @@ SimpleTest.requestFlakyTimeout("untriaged");
// run in an iframe, which by default will not have the allowfullscreen
// attribute set, so full-screen won't work.
var gTestWindows = [
- "file_fullscreen-ancestor-stacking-context.html",
"file_fullscreen-multiple.html",
"file_fullscreen-rollback.html",
"file_fullscreen-esc-context-menu.html",
@@ -41,7 +40,8 @@ var gTestWindows = [
"file_fullscreen-svg-element.html",
"file_fullscreen-navigation.html",
"file_fullscreen-scrollbar.html",
- "file_fullscreen-selector.html"
+ "file_fullscreen-selector.html",
+ "file_fullscreen-top-layer.html"
];
var testWindow = null;
diff --git a/dom/tests/mochitest/general/mochitest.ini b/dom/tests/mochitest/general/mochitest.ini
index 29b7618bd9..df48f92c12 100644
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -110,6 +110,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
skip-if = buildapp == 'b2g' || buildapp == 'mulet'
[test_bug1012662_editor.html]
[test_bug1012662_noeditor.html]
+[test_bug1170911.html]
[test_storagePermissionsAccept.html]
skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
[test_storagePermissionsRejectForeign.html]
diff --git a/dom/tests/mochitest/general/test_bug1170911.html b/dom/tests/mochitest/general/test_bug1170911.html
new file mode 100644
index 0000000000..e739a0f32b
--- /dev/null
+++ b/dom/tests/mochitest/general/test_bug1170911.html
@@ -0,0 +1,90 @@
+
+
+
+
+ Test for Bug 1170911
+
+
+
+
+
+
+Mozilla Bug 1170911
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dom/webidl/KeyframeEffect.webidl b/dom/webidl/KeyframeEffect.webidl
index d7c2ef75df..c9c76c5364 100644
--- a/dom/webidl/KeyframeEffect.webidl
+++ b/dom/webidl/KeyframeEffect.webidl
@@ -10,8 +10,29 @@
* liability, trademark and document use rules apply.
*/
+// For the constructor:
+//
+// 1. We use Element? for the first argument since we don't support Animatable
+// for pseudo-elements yet.
+//
+// 2. We use object? instead of
+//
+// (PropertyIndexedKeyframes or sequence or SharedKeyframeList)
+//
+// for the second argument so that we can get the property-value pairs from
+// the PropertyIndexedKeyframes or Keyframe objects. We also don't support
+// SharedKeyframeList yet.
+//
+// 3. We use unrestricted double instead of
+//
+// (unrestricted double or KeyframeEffectOptions)
+//
+// since we don't support KeyframeEffectOptions yet.
[HeaderFile="mozilla/dom/KeyframeEffect.h",
- Func="nsDocument::IsWebAnimationsEnabled"]
+ Func="nsDocument::IsWebAnimationsEnabled",
+ Constructor(Element? target,
+ optional object? frames,
+ optional unrestricted double options)]
interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
readonly attribute Element? target;
// Not yet implemented:
diff --git a/dom/webidl/PropertyIndexedKeyframes.webidl b/dom/webidl/PropertyIndexedKeyframes.webidl
new file mode 100644
index 0000000000..9f4f8e514c
--- /dev/null
+++ b/dom/webidl/PropertyIndexedKeyframes.webidl
@@ -0,0 +1,18 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 origin of this IDL file is
+ * https://w3c.github.io/web-animations/#the-propertyindexedkeyframe-dictionary
+ *
+ * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+// No other .webidl files references this dictionary, but we use it for
+// manual JS->IDL conversions in KeyframeEffectReadOnly's implementation.
+dictionary PropertyIndexedKeyframes {
+ DOMString easing = "linear";
+ CompositeOperation? composite = null;
+};
diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
index 136a312de3..66854e0e9d 100644
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -384,6 +384,7 @@ WEBIDL_FILES = [
'ProfileTimelineMarker.webidl',
'Promise.webidl',
'PromiseDebugging.webidl',
+ 'PropertyIndexedKeyframes.webidl',
'RadioNodeList.webidl',
'Range.webidl',
'Rect.webidl',
diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp
index f22bc24746..e0b0082512 100644
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -3067,7 +3067,6 @@ bool
ServiceWorkerManager::IsControlled(nsIDocument* aDoc, ErrorResult& aRv)
{
MOZ_ASSERT(aDoc);
- MOZ_ASSERT(!nsContentUtils::IsInPrivateBrowsing(aDoc));
RefPtr registration;
nsresult rv = GetDocumentRegistration(aDoc, getter_AddRefs(registration));
@@ -3077,6 +3076,7 @@ ServiceWorkerManager::IsControlled(nsIDocument* aDoc, ErrorResult& aRv)
return false;
}
+ MOZ_ASSERT_IF(!!registration, !nsContentUtils::IsInPrivateBrowsing(aDoc));
return !!registration;
}
diff --git a/dom/workers/test/serviceworkers/fetch/imagecache/image-20px.png b/dom/workers/test/serviceworkers/fetch/imagecache/image-20px.png
new file mode 100644
index 0000000000..ae6a8a6b88
Binary files /dev/null and b/dom/workers/test/serviceworkers/fetch/imagecache/image-20px.png differ
diff --git a/dom/workers/test/serviceworkers/fetch/imagecache/image-40px.png b/dom/workers/test/serviceworkers/fetch/imagecache/image-40px.png
new file mode 100644
index 0000000000..fe391dc8a2
Binary files /dev/null and b/dom/workers/test/serviceworkers/fetch/imagecache/image-40px.png differ
diff --git a/dom/workers/test/serviceworkers/fetch/imagecache/imagecache_test.js b/dom/workers/test/serviceworkers/fetch/imagecache/imagecache_test.js
new file mode 100644
index 0000000000..598d8213f3
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/imagecache/imagecache_test.js
@@ -0,0 +1,15 @@
+function synthesizeImage() {
+ return clients.matchAll().then(clients => {
+ var url = "image-40px.png";
+ clients.forEach(client => {
+ client.postMessage(url);
+ });
+ return fetch(url);
+ });
+}
+
+self.addEventListener("fetch", function(event) {
+ if (event.request.url.indexOf("image-20px.png") >= 0) {
+ event.respondWith(synthesizeImage());
+ }
+});
diff --git a/dom/workers/test/serviceworkers/fetch/imagecache/index.html b/dom/workers/test/serviceworkers/fetch/imagecache/index.html
new file mode 100644
index 0000000000..93b30f1842
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/imagecache/index.html
@@ -0,0 +1,20 @@
+
+
+
diff --git a/dom/workers/test/serviceworkers/fetch/imagecache/postmortem.html b/dom/workers/test/serviceworkers/fetch/imagecache/postmortem.html
new file mode 100644
index 0000000000..72a650d26c
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/imagecache/postmortem.html
@@ -0,0 +1,9 @@
+
+
+
diff --git a/dom/workers/test/serviceworkers/fetch/imagecache/register.html b/dom/workers/test/serviceworkers/fetch/imagecache/register.html
new file mode 100644
index 0000000000..f6d1eb382f
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/imagecache/register.html
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/dom/workers/test/serviceworkers/fetch/imagecache/unregister.html b/dom/workers/test/serviceworkers/fetch/imagecache/unregister.html
new file mode 100644
index 0000000000..1f13508fa7
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/imagecache/unregister.html
@@ -0,0 +1,12 @@
+
+
diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini
index baa737cd1b..0bc58268ad 100644
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -59,6 +59,13 @@ support-files =
fetch/https/clonedresponse/register.html
fetch/https/clonedresponse/unregister.html
fetch/https/clonedresponse/https_test.js
+ fetch/imagecache/image-20px.png
+ fetch/imagecache/image-40px.png
+ fetch/imagecache/imagecache_test.js
+ fetch/imagecache/index.html
+ fetch/imagecache/postmortem.html
+ fetch/imagecache/register.html
+ fetch/imagecache/unregister.html
fetch/interrupt.sjs
fetch/origin/index.sjs
fetch/origin/index-to-https.sjs
@@ -265,3 +272,4 @@ skip-if = toolkit == "android" || toolkit == "gonk"
[test_file_blob_upload.html]
[test_hsts_upgrade_intercept.html]
skip-if = e10s # Bug 1214305
+[test_imagecache.html]
diff --git a/dom/workers/test/serviceworkers/test_imagecache.html b/dom/workers/test/serviceworkers/test_imagecache.html
new file mode 100644
index 0000000000..319b4edcfd
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_imagecache.html
@@ -0,0 +1,56 @@
+
+
+
+
+ Bug 1202085 - Test that images from different controllers don't cached together
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dom/xbl/nsXBLPrototypeResources.cpp b/dom/xbl/nsXBLPrototypeResources.cpp
index f3146b2166..cd1cb192d1 100644
--- a/dom/xbl/nsXBLPrototypeResources.cpp
+++ b/dom/xbl/nsXBLPrototypeResources.cpp
@@ -143,7 +143,7 @@ void
nsXBLPrototypeResources::GatherRuleProcessor()
{
mRuleProcessor = new nsCSSRuleProcessor(mStyleSheetList,
- nsStyleSet::eDocSheet,
+ SheetType::Doc,
nullptr,
mRuleProcessor);
}
diff --git a/editor/libeditor/crashtests/1128787.html b/editor/libeditor/crashtests/1128787.html
new file mode 100644
index 0000000000..fc6bff0972
--- /dev/null
+++ b/editor/libeditor/crashtests/1128787.html
@@ -0,0 +1,17 @@
+
+
+
+Bug 1128787
+
+
+
+
+
+
diff --git a/editor/libeditor/crashtests/crashtests.list b/editor/libeditor/crashtests/crashtests.list
index 03b93903e5..03bf9d7ca9 100644
--- a/editor/libeditor/crashtests/crashtests.list
+++ b/editor/libeditor/crashtests/crashtests.list
@@ -59,4 +59,5 @@ load 772282.html
load 776323.html
needs-focus load 793866.html
load 1057677.html
+needs-focus load 1128787.html
load 1134545.html
diff --git a/image/ImageCacheKey.cpp b/image/ImageCacheKey.cpp
index f47b3fafe5..a19a11c900 100644
--- a/image/ImageCacheKey.cpp
+++ b/image/ImageCacheKey.cpp
@@ -10,6 +10,10 @@
#include "ImageURL.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsString.h"
+#include "mozilla/dom/workers/ServiceWorkerManager.h"
+#include "nsIDOMDocument.h"
+#include "nsIDocument.h"
+#include "nsPrintfCString.h"
namespace mozilla {
@@ -42,8 +46,9 @@ BlobSerial(ImageURL* aURI)
return Nothing();
}
-ImageCacheKey::ImageCacheKey(nsIURI* aURI)
+ImageCacheKey::ImageCacheKey(nsIURI* aURI, nsIDOMDocument* aDocument)
: mURI(new ImageURL(aURI))
+ , mControlledDocument(GetControlledDocumentToken(aDocument))
, mIsChrome(URISchemeIs(mURI, "chrome"))
{
MOZ_ASSERT(NS_IsMainThread());
@@ -52,11 +57,12 @@ ImageCacheKey::ImageCacheKey(nsIURI* aURI)
mBlobSerial = BlobSerial(mURI);
}
- mHash = ComputeHash(mURI, mBlobSerial);
+ mHash = ComputeHash(mURI, mBlobSerial, mControlledDocument);
}
-ImageCacheKey::ImageCacheKey(ImageURL* aURI)
+ImageCacheKey::ImageCacheKey(ImageURL* aURI, nsIDOMDocument* aDocument)
: mURI(aURI)
+ , mControlledDocument(GetControlledDocumentToken(aDocument))
, mIsChrome(URISchemeIs(mURI, "chrome"))
{
MOZ_ASSERT(aURI);
@@ -65,12 +71,13 @@ ImageCacheKey::ImageCacheKey(ImageURL* aURI)
mBlobSerial = BlobSerial(mURI);
}
- mHash = ComputeHash(mURI, mBlobSerial);
+ mHash = ComputeHash(mURI, mBlobSerial, mControlledDocument);
}
ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther)
: mURI(aOther.mURI)
, mBlobSerial(aOther.mBlobSerial)
+ , mControlledDocument(aOther.mControlledDocument)
, mHash(aOther.mHash)
, mIsChrome(aOther.mIsChrome)
{ }
@@ -78,6 +85,7 @@ ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther)
ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
: mURI(Move(aOther.mURI))
, mBlobSerial(Move(aOther.mBlobSerial))
+ , mControlledDocument(aOther.mControlledDocument)
, mHash(aOther.mHash)
, mIsChrome(aOther.mIsChrome)
{ }
@@ -85,6 +93,10 @@ ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
bool
ImageCacheKey::operator==(const ImageCacheKey& aOther) const
{
+ // Don't share the image cache between a controlled document and anything else.
+ if (mControlledDocument != aOther.mControlledDocument) {
+ return false;
+ }
if (mBlobSerial || aOther.mBlobSerial) {
// If at least one of us has a blob serial, just compare the blob serial and
// the ref portion of the URIs.
@@ -104,11 +116,13 @@ ImageCacheKey::Spec() const
/* static */ uint32_t
ImageCacheKey::ComputeHash(ImageURL* aURI,
- const Maybe& aBlobSerial)
+ const Maybe& aBlobSerial,
+ void* aControlledDocument)
{
// Since we frequently call Hash() several times in a row on the same
// ImageCacheKey, as an optimization we compute our hash once and store it.
+ nsPrintfCString ptr("%p", aControlledDocument);
if (aBlobSerial) {
// For blob URIs, we hash the serial number of the underlying blob, so that
// different blob URIs which point to the same blob share a cache entry. We
@@ -117,13 +131,32 @@ ImageCacheKey::ComputeHash(ImageURL* aURI,
// if the source data is the same.
nsAutoCString ref;
aURI->GetRef(ref);
- return HashGeneric(*aBlobSerial, HashString(ref));
+ return HashGeneric(*aBlobSerial, HashString(ref + ptr));
}
// For non-blob URIs, we hash the URI spec.
nsAutoCString spec;
aURI->GetSpec(spec);
- return HashString(spec);
+ return HashString(spec + ptr);
+}
+
+/* static */ void*
+ImageCacheKey::GetControlledDocumentToken(nsIDOMDocument* aDocument)
+{
+ // For non-controlled documents, we just return null. For controlled
+ // documents, we cast the pointer into a void* to avoid dereferencing
+ // it (since we only use it for comparisons), and return it.
+ void* pointer = nullptr;
+ using dom::workers::ServiceWorkerManager;
+ RefPtr swm = ServiceWorkerManager::GetInstance();
+ nsCOMPtr doc = do_QueryInterface(aDocument);
+ if (doc && swm) {
+ ErrorResult rv;
+ if (swm->IsControlled(doc, rv)) {
+ pointer = doc;
+ }
+ }
+ return pointer;
}
} // namespace image
diff --git a/image/ImageCacheKey.h b/image/ImageCacheKey.h
index e2dc36c99c..919bff6d91 100644
--- a/image/ImageCacheKey.h
+++ b/image/ImageCacheKey.h
@@ -12,6 +12,7 @@
#include "mozilla/Maybe.h"
+class nsIDOMDocument;
class nsIURI;
namespace mozilla {
@@ -24,12 +25,14 @@ class ImageURL;
*
* We key the cache on the initial URI (before any redirects), with some
* canonicalization applied. See ComputeHash() for the details.
+ * Controlled documents do not share their cache entries with
+ * non-controlled documents, or other controlled documents.
*/
class ImageCacheKey final
{
public:
- explicit ImageCacheKey(nsIURI* aURI);
- explicit ImageCacheKey(ImageURL* aURI);
+ ImageCacheKey(nsIURI* aURI, nsIDOMDocument* aDocument);
+ ImageCacheKey(ImageURL* aURI, nsIDOMDocument* aDocument);
ImageCacheKey(const ImageCacheKey& aOther);
ImageCacheKey(ImageCacheKey&& aOther);
@@ -43,12 +46,19 @@ public:
/// Is this cache entry for a chrome image?
bool IsChrome() const { return mIsChrome; }
+ /// A token indicating which service worker controlled document this entry
+ /// belongs to, if any.
+ void* ControlledDocument() const { return mControlledDocument; }
+
private:
static uint32_t ComputeHash(ImageURL* aURI,
- const Maybe& aBlobSerial);
+ const Maybe& aBlobSerial,
+ void* aControlledDocument);
+ static void* GetControlledDocumentToken(nsIDOMDocument* aDocument);
RefPtr mURI;
Maybe mBlobSerial;
+ void* mControlledDocument;
uint32_t mHash;
bool mIsChrome;
};
diff --git a/image/imgICache.idl b/image/imgICache.idl
index 1efa2d456f..abfe0d0909 100644
--- a/image/imgICache.idl
+++ b/image/imgICache.idl
@@ -6,9 +6,11 @@
#include "nsISupports.idl"
-interface nsIURI;
interface imgIRequest;
+interface nsIDocument;
+interface nsIDOMDocument;
interface nsIProperties;
+interface nsIURI;
/**
* imgICache interface
@@ -17,7 +19,7 @@ interface nsIProperties;
* @version 0.1
* @see imagelib2
*/
-[scriptable, builtinclass, uuid(b06e0fa5-d6e2-4fa3-8fc0-7775aed96522)]
+[scriptable, builtinclass, uuid(bfdf23ff-378e-402e-8a6c-840f0c82b6c3)]
interface imgICache : nsISupports
{
/**
@@ -28,15 +30,6 @@ interface imgICache : nsISupports
*/
void clearCache(in boolean chrome);
- /**
- * Evict images from the cache.
- *
- * @param uri The URI to remove.
- * @throws NS_ERROR_NOT_AVAILABLE if \a uri was unable to be removed from
- * the cache.
- */
- void removeEntry(in nsIURI uri);
-
/**
* Find Properties
* Used to get properties such as 'type' and 'content-disposition'
@@ -49,9 +42,10 @@ interface imgICache : nsISupports
* Hopefully this will be removed with bug 805119
*
* @param uri The URI to look up.
+ * @param doc Optional pointer to the document that the cache entry belongs to.
* @returns NULL if the URL was not found in the cache
*/
- nsIProperties findEntryProperties(in nsIURI uri);
+ nsIProperties findEntryProperties(in nsIURI uri, [optional] in nsIDOMDocument doc);
/**
* Make this cache instance respect private browsing notifications. This
@@ -59,4 +53,11 @@ interface imgICache : nsISupports
* last-pb-context-exited notification is observed.
*/
void respectPrivacyNotifications();
+
+ /**
+ * Clear the image cache for a document. Controlled documents are responsible
+ * for doing this manually when they get destroyed.
+ */
+ [noscript, notxpcom]
+ void clearCacheForControlledDocument(in nsIDocument doc);
};
diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp
index 439ec9687b..4358be7a89 100644
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -52,6 +52,7 @@
#include "nsIHttpChannelInternal.h"
#include "nsILoadContext.h"
#include "nsILoadGroupChild.h"
+#include "nsIDOMDocument.h"
using namespace mozilla;
using namespace mozilla::image;
@@ -1403,21 +1404,13 @@ imgLoader::ClearCache(bool chrome)
}
NS_IMETHODIMP
-imgLoader::RemoveEntry(nsIURI* aURI)
-{
- if (aURI && RemoveFromCache(ImageCacheKey(aURI))) {
- return NS_OK;
- }
-
- return NS_ERROR_NOT_AVAILABLE;
-}
-
-NS_IMETHODIMP
-imgLoader::FindEntryProperties(nsIURI* uri, nsIProperties** _retval)
+imgLoader::FindEntryProperties(nsIURI* uri,
+ nsIDOMDocument* doc,
+ nsIProperties** _retval)
{
*_retval = nullptr;
- ImageCacheKey key(uri);
+ ImageCacheKey key(uri, doc);
imgCacheTable& cache = GetCache(key);
RefPtr entry;
@@ -1436,6 +1429,25 @@ imgLoader::FindEntryProperties(nsIURI* uri, nsIProperties** _retval)
return NS_OK;
}
+NS_IMETHODIMP_(void)
+imgLoader::ClearCacheForControlledDocument(nsIDocument* aDoc)
+{
+ MOZ_ASSERT(aDoc);
+ nsAutoTArray, 128> entriesToBeRemoved;
+ imgCacheTable& cache = GetCache(false);
+ for (auto iter = cache.Iter(); !iter.Done(); iter.Next()) {
+ auto& key = iter.Key();
+ if (key.ControlledDocument() == aDoc) {
+ entriesToBeRemoved.AppendElement(iter.Data());
+ }
+ }
+ for (auto& entry : entriesToBeRemoved) {
+ if (!RemoveFromCache(entry)) {
+ NS_WARNING("Couldn't remove an entry from the cache in ClearCacheForControlledDocument()\n");
+ }
+ }
+}
+
void
imgLoader::Shutdown()
{
@@ -2187,7 +2199,8 @@ imgLoader::LoadImage(nsIURI* aURI,
// XXX For now ignore aCacheKey. We will need it in the future
// for correctly dealing with image load requests that are a result
// of post data.
- ImageCacheKey key(aURI);
+ nsCOMPtr doc = do_QueryInterface(aCX);
+ ImageCacheKey key(aURI, doc);
imgCacheTable& cache = GetCache(key);
if (cache.Get(key, getter_AddRefs(entry)) && entry) {
@@ -2416,7 +2429,8 @@ imgLoader::LoadImageWithChannel(nsIChannel* channel,
nsCOMPtr uri;
channel->GetURI(getter_AddRefs(uri));
- ImageCacheKey key(uri);
+ nsCOMPtr doc = do_QueryInterface(aCX);
+ ImageCacheKey key(uri, doc);
nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
channel->GetLoadFlags(&requestFlags);
@@ -2510,7 +2524,7 @@ imgLoader::LoadImageWithChannel(nsIChannel* channel,
// constructed above with the *current URI* and not the *original URI*. I'm
// pretty sure this is a bug, and it's preventing us from ever getting a
// cache hit in LoadImageWithChannel when redirects are involved.
- ImageCacheKey originalURIKey(originalURI);
+ ImageCacheKey originalURIKey(originalURI, doc);
// Default to doing a principal check because we don't know who
// started that load and whether their principal ended up being
diff --git a/image/imgRequest.cpp b/image/imgRequest.cpp
index 916d8d30f8..52c8d58611 100644
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -500,7 +500,7 @@ imgRequest::RemoveFromCache()
if (mCacheEntry) {
mLoader->RemoveFromCache(mCacheEntry);
} else {
- mLoader->RemoveFromCache(ImageCacheKey(mURI));
+ mLoader->RemoveFromCache(mCacheKey);
}
}
diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp
index 74c4844760..e88e89f18f 100644
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -4051,7 +4051,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
for (nsStyleStructID sid = nsStyleStructID(0);
sid < nsStyleStructID_Length;
sid = nsStyleStructID(sid + 1)) {
- if (oldContext->HasCachedInheritedStyleData(sid) &&
+ if (oldContext->HasCachedDependentStyleData(sid) &&
!(samePointerStructs & nsCachedStyleData::GetBitForSID(sid))) {
LOG_RESTYLE_CONTINUE("there are different struct pointers");
result = eRestyleResult_Continue;
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index b3452621dd..c6621f50c1 100644
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -748,6 +748,11 @@ public:
nsAbsoluteItems mFixedItems;
nsAbsoluteItems mAbsoluteItems;
nsAbsoluteItems mFloatedItems;
+ // Items in the top layer are always fixed positioned children of the
+ // viewport frame. It differs from mFixedItems that the items here
+ // should not be caught by any other fixed-pos containing block like
+ // frames with transform or filter.
+ nsAbsoluteItems mTopLayerItems;
nsCOMPtr mFrameState;
// These bits will be added to the state bits of any frame we construct
@@ -781,11 +786,12 @@ public:
// Constructor
// Use the passed-in history state.
- nsFrameConstructorState(nsIPresShell* aPresShell,
- nsContainerFrame* aFixedContainingBlock,
- nsContainerFrame* aAbsoluteContainingBlock,
- nsContainerFrame* aFloatContainingBlock,
- nsILayoutHistoryState* aHistoryState);
+ nsFrameConstructorState(
+ nsIPresShell* aPresShell,
+ nsContainerFrame* aFixedContainingBlock,
+ nsContainerFrame* aAbsoluteContainingBlock,
+ nsContainerFrame* aFloatContainingBlock,
+ already_AddRefed aHistoryState);
// Get the history state from the pres context's pres shell.
nsFrameConstructorState(nsIPresShell* aPresShell,
nsContainerFrame* aFixedContainingBlock,
@@ -918,6 +924,20 @@ protected:
void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
ChildListID aChildListID);
+ /**
+ * GetOutOfFlowFrameItems selects the out-of-flow frame list the new
+ * frame should be added to. If the frame shouldn't be added to any
+ * out-of-flow list, it returns nullptr. The corresponding type of
+ * placeholder is also returned via the aPlaceholderType parameter
+ * if this method doesn't return nullptr. The caller should check
+ * whether the returned list really has a containing block.
+ */
+ nsAbsoluteItems* GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
+ bool aCanBePositioned,
+ bool aCanBeFloated,
+ bool aIsOutOfFlowPopup,
+ nsFrameState* aPlaceholderType);
+
// Our list of all pending bindings. When we're done, we need to call
// AddToAttachedQueue on all of them, in order.
LinkedList mPendingBindings;
@@ -925,11 +945,12 @@ protected:
PendingBinding* mCurrentPendingBindingInsertionPoint;
};
-nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
- nsContainerFrame* aFixedContainingBlock,
- nsContainerFrame* aAbsoluteContainingBlock,
- nsContainerFrame* aFloatContainingBlock,
- nsILayoutHistoryState* aHistoryState)
+nsFrameConstructorState::nsFrameConstructorState(
+ nsIPresShell* aPresShell,
+ nsContainerFrame* aFixedContainingBlock,
+ nsContainerFrame* aAbsoluteContainingBlock,
+ nsContainerFrame* aFloatContainingBlock,
+ already_AddRefed aHistoryState)
: mPresContext(aPresShell->GetPresContext()),
mPresShell(aPresShell),
mFrameManager(aPresShell->FrameManager()),
@@ -939,6 +960,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShe
mFixedItems(aFixedContainingBlock),
mAbsoluteItems(aAbsoluteContainingBlock),
mFloatedItems(aFloatContainingBlock),
+ mTopLayerItems(do_QueryFrame(mFrameManager->GetRootFrame())),
// See PushAbsoluteContaningBlock below
mFrameState(aHistoryState),
mAdditionalStateBits(nsFrameState(0)),
@@ -965,48 +987,18 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
nsContainerFrame* aFixedContainingBlock,
nsContainerFrame* aAbsoluteContainingBlock,
nsContainerFrame* aFloatContainingBlock)
- : mPresContext(aPresShell->GetPresContext()),
- mPresShell(aPresShell),
- mFrameManager(aPresShell->FrameManager()),
-#ifdef MOZ_XUL
- mPopupItems(nullptr),
-#endif
- mFixedItems(aFixedContainingBlock),
- mAbsoluteItems(aAbsoluteContainingBlock),
- mFloatedItems(aFloatContainingBlock),
- // See PushAbsoluteContaningBlock below
- mAdditionalStateBits(nsFrameState(0)),
- // If the fixed-pos containing block is equal to the abs-pos containing
- // block, use the abs-pos containing block's abs-pos list for fixed-pos
- // frames.
- mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
- mHavePendingPopupgroup(false),
- mCreatingExtraFrames(false),
- mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited,
- aPresShell->GetDocument()),
- mCurrentPendingBindingInsertionPoint(nullptr)
+ : nsFrameConstructorState(aPresShell, aFixedContainingBlock,
+ aAbsoluteContainingBlock,
+ aFloatContainingBlock,
+ aPresShell->GetDocument()->GetLayoutHistoryState())
{
-#ifdef MOZ_XUL
- nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
- if (rootBox) {
- mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
- }
-#endif
- MOZ_COUNT_CTOR(nsFrameConstructorState);
- mFrameState = aPresShell->GetDocument()->GetLayoutHistoryState();
}
nsFrameConstructorState::~nsFrameConstructorState()
{
- // Frame order comparison functions only work properly when the placeholders
- // have been inserted into the frame tree. So for example if we have a new float
- // containing the placeholder for a new abs-pos frame, and we process the abs-pos
- // insertion first, then we won't be able to find the right place to insert in
- // in the abs-pos list. So put floats in first, because they can contain placeholders
- // for abs-pos and fixed-pos items whose containing blocks are outside the floats.
- // Then put abs-pos frames in, because they can contain placeholders for fixed-pos
- // items whose containing block is outside the abs-pos frames.
MOZ_COUNT_DTOR(nsFrameConstructorState);
+ // Items in the top layer are fixed positioned children of the viewport frame.
+ ProcessFrameInsertions(mTopLayerItems, nsIFrame::kFixedList);
ProcessFrameInsertions(mFloatedItems, nsIFrame::kFloatList);
ProcessFrameInsertions(mAbsoluteItems, nsIFrame::kAbsoluteList);
ProcessFrameInsertions(mFixedItems, nsIFrame::kFixedList);
@@ -1122,6 +1114,15 @@ nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
return mFloatedItems.containingBlock;
}
+ if (aStyleDisplay->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
+ MOZ_ASSERT(aStyleDisplay->mTopLayer == NS_STYLE_TOP_LAYER_TOP,
+ "-moz-top-layer should be either none or top");
+ MOZ_ASSERT(mTopLayerItems.containingBlock, "No root frame?");
+ MOZ_ASSERT(aStyleDisplay->IsAbsolutelyPositionedStyle(),
+ "Top layer items should always be absolutely positioned");
+ return mTopLayerItems.containingBlock;
+ }
+
if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
mAbsoluteItems.containingBlock) {
return mAbsoluteItems.containingBlock;
@@ -1135,6 +1136,43 @@ nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
return aContentParentFrame;
}
+nsAbsoluteItems*
+nsFrameConstructorState::GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
+ bool aCanBePositioned,
+ bool aCanBeFloated,
+ bool aIsOutOfFlowPopup,
+ nsFrameState* aPlaceholderType)
+{
+#ifdef MOZ_XUL
+ if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) {
+ MOZ_ASSERT(mPopupItems.containingBlock, "Must have a popup set frame!");
+ *aPlaceholderType = PLACEHOLDER_FOR_POPUP;
+ return &mPopupItems;
+ }
+#endif // MOZ_XUL
+ if (aCanBeFloated && aNewFrame->IsFloating()) {
+ *aPlaceholderType = PLACEHOLDER_FOR_FLOAT;
+ return &mFloatedItems;
+ }
+
+ if (aCanBePositioned) {
+ const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
+ if (disp->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
+ *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
+ return &mTopLayerItems;
+ }
+ if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE) {
+ *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS;
+ return &mAbsoluteItems;
+ }
+ if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
+ *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
+ return &GetFixedItems();
+ }
+ }
+ return nullptr;
+}
+
void
nsFrameConstructorState::AddChild(nsIFrame* aNewFrame,
nsFrameItems& aFrameItems,
@@ -1149,53 +1187,25 @@ nsFrameConstructorState::AddChild(nsIFrame* aNewFrame,
{
NS_PRECONDITION(!aNewFrame->GetNextSibling(), "Shouldn't happen");
- const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
+ nsFrameState placeholderType;
+ nsAbsoluteItems* outOfFlowFrameItems =
+ GetOutOfFlowFrameItems(aNewFrame, aCanBePositioned, aCanBeFloated,
+ aIsOutOfFlowPopup, &placeholderType);
// The comments in GetGeometricParent regarding root table frames
- // all apply here, unfortunately.
-
- bool needPlaceholder = false;
- nsFrameState placeholderType;
- nsFrameItems* frameItems = &aFrameItems;
-#ifdef MOZ_XUL
- if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) {
- NS_ASSERTION(aNewFrame->GetParent() == mPopupItems.containingBlock,
- "Popup whose parent is not the popup containing block?");
- NS_ASSERTION(mPopupItems.containingBlock, "Must have a popup set frame!");
- needPlaceholder = true;
- frameItems = &mPopupItems;
- placeholderType = PLACEHOLDER_FOR_POPUP;
- }
- else
-#endif // MOZ_XUL
- if (aCanBeFloated && aNewFrame->IsFloating() &&
- mFloatedItems.containingBlock) {
- NS_ASSERTION(aNewFrame->GetParent() == mFloatedItems.containingBlock,
- "Float whose parent is not the float containing block?");
- needPlaceholder = true;
- frameItems = &mFloatedItems;
- placeholderType = PLACEHOLDER_FOR_FLOAT;
- }
- else if (aCanBePositioned) {
- if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
- mAbsoluteItems.containingBlock) {
- NS_ASSERTION(aNewFrame->GetParent() == mAbsoluteItems.containingBlock,
- "Abs pos whose parent is not the abs pos containing block?");
- needPlaceholder = true;
- frameItems = &mAbsoluteItems;
- placeholderType = PLACEHOLDER_FOR_ABSPOS;
- }
- if (disp->mPosition == NS_STYLE_POSITION_FIXED &&
- GetFixedItems().containingBlock) {
- NS_ASSERTION(aNewFrame->GetParent() == GetFixedItems().containingBlock,
- "Fixed pos whose parent is not the fixed pos containing block?");
- needPlaceholder = true;
- frameItems = &GetFixedItems();
- placeholderType = PLACEHOLDER_FOR_FIXEDPOS;
- }
+ // all apply here, unfortunately. Thus, we need to check whether
+ // the returned frame items really has containing block.
+ nsFrameItems* frameItems;
+ if (outOfFlowFrameItems && outOfFlowFrameItems->containingBlock) {
+ MOZ_ASSERT(aNewFrame->GetParent() == outOfFlowFrameItems->containingBlock,
+ "Parent of the frame is not the containing block?");
+ frameItems = outOfFlowFrameItems;
+ } else {
+ frameItems = &aFrameItems;
+ placeholderType = nsFrameState(0);
}
- if (needPlaceholder) {
+ if (placeholderType) {
NS_ASSERTION(frameItems != &aFrameItems,
"Putting frame in-flow _and_ want a placeholder?");
nsIFrame* placeholderFrame =
@@ -1233,7 +1243,8 @@ nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
aChildListID == nsIFrame::kFloatList) || \
(&aFrameItems == &mAbsoluteItems && \
aChildListID == nsIFrame::kAbsoluteList) || \
- (&aFrameItems == &mFixedItems && \
+ ((&aFrameItems == &mFixedItems || \
+ &aFrameItems == &mTopLayerItems) && \
aChildListID == nsIFrame::kFixedList)
#ifdef MOZ_XUL
NS_PRECONDITION(NS_NONXUL_LIST_TEST ||
@@ -1274,6 +1285,11 @@ nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
} else {
containingBlock->SetInitialChildList(aChildListID, aFrameItems);
}
+ } else if (aChildListID == nsIFrame::kFixedList ||
+ aChildListID == nsIFrame::kAbsoluteList) {
+ // The order is not important for abs-pos/fixed-pos frame list, just
+ // append the frame items to the list directly.
+ mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
} else {
// Note that whether the frame construction context is doing an append or
// not is not helpful here, since it could be appending to some frame in
@@ -2329,7 +2345,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
nsFrameConstructorState state(mPresShell,
GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
nullptr,
- nullptr, aFrameState);
+ nullptr, do_AddRef(Move(aFrameState)));
// Initialize the ancestor filter with null for now; we'll push
// aDocElement once we finish resolving style for it.
state.mTreeMatchContext.InitAncestors(nullptr);
@@ -7684,7 +7700,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
GetFloatContainingBlock(insertion.mParentFrame),
- aFrameState);
+ do_AddRef(Move(aFrameState)));
state.mTreeMatchContext.InitAncestors(aContainer ?
aContainer->AsElement() :
nullptr);
@@ -11421,7 +11437,7 @@ nsCSSFrameConstructor::CreateListBoxContent(nsPresContext* aPresContext,
nsFrameConstructorState state(mPresShell, GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
GetFloatContainingBlock(aParentFrame),
- mTempFrameTreeState);
+ do_AddRef(mTempFrameTreeState.get()));
// If we ever initialize the ancestor filter on |state|, make sure
// to push the right parent!
diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h
index 83e20aa2f9..58b1c063b4 100644
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -864,6 +864,13 @@ public:
NS_DECLARE_FRAME_PROPERTY(OutOfFlowDisplayDataProperty,
DeleteValue)
+
+ static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame)
+ {
+ return static_cast(
+ aFrame->Properties().Get(OutOfFlowDisplayDataProperty()));
+ }
+
NS_DECLARE_FRAME_PROPERTY(Preserve3DDirtyRectProperty, DeleteValue)
nsPresContext* CurrentPresContext() {
diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp
index 011e2084d3..62f0c19206 100644
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2251,7 +2251,7 @@ static bool
AppendAgentSheet(nsIStyleSheet *aSheet, void *aData)
{
nsStyleSet *styleSet = static_cast(aData);
- styleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet);
+ styleSet->AppendStyleSheet(SheetType::Agent, aSheet);
return true;
}
@@ -2259,7 +2259,7 @@ static bool
PrependUserSheet(nsIStyleSheet *aSheet, void *aData)
{
nsStyleSet *styleSet = static_cast(aData);
- styleSet->PrependStyleSheet(nsStyleSet::eUserSheet, aSheet);
+ styleSet->PrependStyleSheet(SheetType::User, aSheet);
return true;
}
@@ -2302,7 +2302,7 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
}
if (sheet)
- styleSet->AppendStyleSheet(nsStyleSet::eUserSheet, sheet);
+ styleSet->AppendStyleSheet(SheetType::User, sheet);
// Append chrome sheets (scrollbars + forms).
bool shouldOverride = false;
@@ -2338,7 +2338,7 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
cssLoader->LoadSheetSync(uri, getter_AddRefs(csssheet));
if (!csssheet) continue;
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, csssheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, csssheet);
shouldOverride = true;
}
free(str);
@@ -2349,15 +2349,10 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
if (!shouldOverride) {
sheet = nsLayoutStylesheetCache::ScrollbarsSheet();
if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
}
- sheet = nsLayoutStylesheetCache::FullScreenOverrideSheet();
- if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, sheet);
- }
-
if (!aDocument->IsSVGDocument()) {
// !!! IMPORTANT - KEEP THIS BLOCK IN SYNC WITH
// !!! SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded.
@@ -2370,12 +2365,12 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
sheet = nsLayoutStylesheetCache::NumberControlSheet();
if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
sheet = nsLayoutStylesheetCache::FormsSheet();
if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
if (aDocument->LoadsFullXULStyleSheetUpFront()) {
@@ -2383,7 +2378,7 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
// up-front here.
sheet = nsLayoutStylesheetCache::XULSheet();
if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
}
@@ -2391,25 +2386,25 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
if (sheet) {
// Load the minimal XUL rules for scrollbars and a few other XUL things
// that non-XUL (typically HTML) documents commonly use.
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
sheet = nsLayoutStylesheetCache::CounterStylesSheet();
if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
if (nsLayoutUtils::ShouldUseNoScriptSheet(aDocument)) {
sheet = nsLayoutStylesheetCache::NoScriptSheet();
if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
}
if (nsLayoutUtils::ShouldUseNoFramesSheet(aDocument)) {
sheet = nsLayoutStylesheetCache::NoFramesSheet();
if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
}
@@ -2418,16 +2413,16 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument,
sheet = nsLayoutStylesheetCache::HTMLSheet();
if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet,
+ styleSet->PrependStyleSheet(SheetType::Agent,
nsLayoutStylesheetCache::UASheet());
} else {
// SVG documents may have scrollbars and need the scrollbar styling.
sheet = nsLayoutStylesheetCache::MinimalXULSheet();
if (sheet) {
- styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
}
diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp
index a9d4c8fb80..57e76535a0 100644
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1348,11 +1348,11 @@ nsPresContext::CompatibilityModeChanged()
if (needsQuirkSheet) {
// quirk.css needs to come after html.css; we just keep it at the end.
DebugOnly rv =
- styleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->AppendStyleSheet(SheetType::Agent, sheet);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to insert quirk.css");
} else {
DebugOnly rv =
- styleSet->RemoveStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ styleSet->RemoveStyleSheet(SheetType::Agent, sheet);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to remove quirk.css");
}
diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp
index 276e0fb25a..19ee6b6cf3 100644
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -168,6 +168,7 @@
#include "mozilla/Telemetry.h"
#include "nsCanvasFrame.h"
#include "nsIImageLoadingContent.h"
+#include "nsImageFrame.h"
#include "nsIScreen.h"
#include "nsIScreenManager.h"
#include "nsPlaceholderFrame.h"
@@ -1407,7 +1408,7 @@ PresShell::UpdatePreferenceStyles()
RemovePreferenceStyles();
- mStyleSet->AppendStyleSheet(nsStyleSet::eUserSheet, newPrefSheet);
+ mStyleSet->AppendStyleSheet(SheetType::User, newPrefSheet);
mPrefStyleSheet = newPrefSheet;
mStyleSet->EndUpdate();
@@ -1417,7 +1418,7 @@ void
PresShell::RemovePreferenceStyles()
{
if (mPrefStyleSheet) {
- mStyleSet->RemoveStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet);
+ mStyleSet->RemoveStyleSheet(SheetType::User, mPrefStyleSheet);
mPrefStyleSheet = nullptr;
}
}
@@ -1441,13 +1442,13 @@ PresShell::AddUserSheet(nsISupports* aSheet)
// Iterate forwards when removing so the searches for RemoveStyleSheet are as
// short as possible.
for (i = 0; i < userSheets.Count(); ++i) {
- mStyleSet->RemoveStyleSheet(nsStyleSet::eUserSheet, userSheets[i]);
+ mStyleSet->RemoveStyleSheet(SheetType::User, userSheets[i]);
}
// Now iterate backwards, so that the order of userSheets will be the same as
// the order of sheets from it in the style set.
for (i = userSheets.Count() - 1; i >= 0; --i) {
- mStyleSet->PrependStyleSheet(nsStyleSet::eUserSheet, userSheets[i]);
+ mStyleSet->PrependStyleSheet(SheetType::User, userSheets[i]);
}
mStyleSet->EndUpdate();
@@ -1465,7 +1466,7 @@ PresShell::AddAgentSheet(nsISupports* aSheet)
return;
}
- mStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
+ mStyleSet->AppendStyleSheet(SheetType::Agent, sheet);
ReconstructStyleData();
}
@@ -1481,16 +1482,16 @@ PresShell::AddAuthorSheet(nsISupports* aSheet)
// added with the StyleSheetService.
nsIStyleSheet* firstAuthorSheet = mDocument->FirstAdditionalAuthorSheet();
if (firstAuthorSheet) {
- mStyleSet->InsertStyleSheetBefore(nsStyleSet::eDocSheet, sheet, firstAuthorSheet);
+ mStyleSet->InsertStyleSheetBefore(SheetType::Doc, sheet, firstAuthorSheet);
} else {
- mStyleSet->AppendStyleSheet(nsStyleSet::eDocSheet, sheet);
+ mStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
}
ReconstructStyleData();
}
void
-PresShell::RemoveSheet(nsStyleSet::sheetType aType, nsISupports* aSheet)
+PresShell::RemoveSheet(SheetType aType, nsISupports* aSheet)
{
nsCOMPtr sheet = do_QueryInterface(aSheet);
if (!sheet) {
@@ -4071,12 +4072,10 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
if (aFlush.mFlushAnimations &&
!mPresContext->StyleUpdateForAllAnimationsIsUpToDate()) {
if (mPresContext->AnimationManager()) {
- mPresContext->AnimationManager()->
- FlushAnimations(CommonAnimationManager::Cannot_Throttle);
+ mPresContext->AnimationManager()->FlushAnimations();
}
if (mPresContext->TransitionManager()) {
- mPresContext->TransitionManager()->
- FlushAnimations(CommonAnimationManager::Cannot_Throttle);
+ mPresContext->TransitionManager()->FlushAnimations();
}
mPresContext->TickLastStyleUpdateForAllAnimations();
}
@@ -8685,10 +8684,10 @@ nsresult
PresShell::GetAgentStyleSheets(nsCOMArray& aSheets)
{
aSheets.Clear();
- int32_t sheetCount = mStyleSet->SheetCount(nsStyleSet::eAgentSheet);
+ int32_t sheetCount = mStyleSet->SheetCount(SheetType::Agent);
for (int32_t i = 0; i < sheetCount; ++i) {
- nsIStyleSheet *sheet = mStyleSet->StyleSheetAt(nsStyleSet::eAgentSheet, i);
+ nsIStyleSheet *sheet = mStyleSet->StyleSheetAt(SheetType::Agent, i);
if (!aSheets.AppendObject(sheet))
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -8699,19 +8698,19 @@ PresShell::GetAgentStyleSheets(nsCOMArray& aSheets)
nsresult
PresShell::SetAgentStyleSheets(const nsCOMArray& aSheets)
{
- return mStyleSet->ReplaceSheets(nsStyleSet::eAgentSheet, aSheets);
+ return mStyleSet->ReplaceSheets(SheetType::Agent, aSheets);
}
nsresult
PresShell::AddOverrideStyleSheet(nsIStyleSheet *aSheet)
{
- return mStyleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
+ return mStyleSet->PrependStyleSheet(SheetType::Override, aSheet);
}
nsresult
PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet)
{
- return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
+ return mStyleSet->RemoveStyleSheet(SheetType::Override, aSheet);
}
static void
@@ -9402,6 +9401,11 @@ PresShell::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
+ if (mIsDestroying) {
+ NS_WARNING("our observers should have been unregistered by now");
+ return NS_OK;
+ }
+
#ifdef MOZ_XUL
if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) {
nsIFrame *rootFrame = mFrameConstructor->GetRootFrame();
@@ -9456,17 +9460,17 @@ PresShell::Observe(nsISupports* aSubject,
}
if (!nsCRT::strcmp(aTopic, "agent-sheet-removed") && mStyleSet) {
- RemoveSheet(nsStyleSet::eAgentSheet, aSubject);
+ RemoveSheet(SheetType::Agent, aSubject);
return NS_OK;
}
if (!nsCRT::strcmp(aTopic, "user-sheet-removed") && mStyleSet) {
- RemoveSheet(nsStyleSet::eUserSheet, aSubject);
+ RemoveSheet(SheetType::User, aSubject);
return NS_OK;
}
if (!nsCRT::strcmp(aTopic, "author-sheet-removed") && mStyleSet) {
- RemoveSheet(nsStyleSet::eDocSheet, aSubject);
+ RemoveSheet(SheetType::Doc, aSubject);
return NS_OK;
}
@@ -9809,35 +9813,35 @@ PresShell::CloneStyleSet(nsStyleSet* aSet)
{
nsStyleSet *clone = new nsStyleSet();
- int32_t i, n = aSet->SheetCount(nsStyleSet::eOverrideSheet);
+ int32_t i, n = aSet->SheetCount(SheetType::Override);
for (i = 0; i < n; i++) {
- nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eOverrideSheet, i);
+ nsIStyleSheet* ss = aSet->StyleSheetAt(SheetType::Override, i);
if (ss)
- clone->AppendStyleSheet(nsStyleSet::eOverrideSheet, ss);
+ clone->AppendStyleSheet(SheetType::Override, ss);
}
// The document expects to insert document stylesheets itself
#if 0
- n = aSet->SheetCount(nsStyleSet::eDocSheet);
+ n = aSet->SheetCount(SheetType::Doc);
for (i = 0; i < n; i++) {
- nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eDocSheet, i);
+ nsIStyleSheet* ss = aSet->StyleSheetAt(SheetType::Doc, i);
if (ss)
clone->AddDocStyleSheet(ss, mDocument);
}
#endif
- n = aSet->SheetCount(nsStyleSet::eUserSheet);
+ n = aSet->SheetCount(SheetType::User);
for (i = 0; i < n; i++) {
- nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eUserSheet, i);
+ nsIStyleSheet* ss = aSet->StyleSheetAt(SheetType::User, i);
if (ss)
- clone->AppendStyleSheet(nsStyleSet::eUserSheet, ss);
+ clone->AppendStyleSheet(SheetType::User, ss);
}
- n = aSet->SheetCount(nsStyleSet::eAgentSheet);
+ n = aSet->SheetCount(SheetType::Agent);
for (i = 0; i < n; i++) {
- nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eAgentSheet, i);
+ nsIStyleSheet* ss = aSet->StyleSheetAt(SheetType::Agent, i);
if (ss)
- clone->AppendStyleSheet(nsStyleSet::eAgentSheet, ss);
+ clone->AppendStyleSheet(SheetType::Agent, ss);
}
return clone;
}
@@ -9966,9 +9970,9 @@ PresShell::ListStyleContexts(nsIFrame *aRootFrame, FILE *out, int32_t aIndent)
void
PresShell::ListStyleSheets(FILE *out, int32_t aIndent)
{
- int32_t sheetCount = mStyleSet->SheetCount(nsStyleSet::eDocSheet);
+ int32_t sheetCount = mStyleSet->SheetCount(SheetType::Doc);
for (int32_t i = 0; i < sheetCount; ++i) {
- mStyleSet->StyleSheetAt(nsStyleSet::eDocSheet, i)->List(out, aIndent);
+ mStyleSet->StyleSheetAt(SheetType::Doc, i)->List(out, aIndent);
fputs("\n", out);
}
}
@@ -10721,7 +10725,23 @@ nsresult
PresShell::UpdateImageLockingState()
{
// We're locked if we're both thawed and active.
- return mDocument->SetImageLockingState(!mFrozen && mIsActive);
+ bool locked = !mFrozen && mIsActive;
+
+ nsresult rv = mDocument->SetImageLockingState(locked);
+
+ if (locked) {
+ // Request decodes for visible images; we want to start decoding as
+ // quickly as possible when we get foregrounded to minimize flashing.
+ for (auto iter = mVisibleImages.Iter(); !iter.Done(); iter.Next()) {
+ nsCOMPtr content = do_QueryInterface(iter.Get()->GetKey());
+ nsImageFrame* imageFrame = do_QueryFrame(content->GetPrimaryFrame());
+ if (imageFrame) {
+ imageFrame->MaybeDecodeForPredictedSize();
+ }
+ }
+ }
+
+ return rv;
}
PresShell*
@@ -10949,16 +10969,16 @@ nsresult
nsIPresShell::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
bool* aRetVal)
{
- nsStyleSet::sheetType type;
+ SheetType type;
switch (aSheetType) {
case nsIStyleSheetService::AGENT_SHEET:
- type = nsStyleSet::eAgentSheet;
+ type = SheetType::Agent;
break;
case nsIStyleSheetService::USER_SHEET:
- type = nsStyleSet::eUserSheet;
+ type = SheetType::User;
break;
case nsIStyleSheetService::AUTHOR_SHEET:
- type = nsStyleSet::eDocSheet;
+ type = SheetType::Doc;
break;
default:
MOZ_ASSERT(false, "unexpected aSheetType value");
diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h
index 052f1a90f2..d099d25bd3 100644
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -564,7 +564,7 @@ protected:
void AddUserSheet(nsISupports* aSheet);
void AddAgentSheet(nsISupports* aSheet);
void AddAuthorSheet(nsISupports* aSheet);
- void RemoveSheet(nsStyleSet::sheetType aType, nsISupports* aSheet);
+ void RemoveSheet(mozilla::SheetType aType, nsISupports* aSheet);
// Hide a view if it is a popup
void HideViewIfPopup(nsView* aView);
diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp
index c4ad2ff787..e4f266f34b 100644
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1486,44 +1486,32 @@ TakeFrameRequestCallbacksFrom(nsIDocument* aDocument,
aDocument->TakeFrameRequestCallbacks(aTarget.LastElement().mCallbacks);
}
-namespace {
- enum class AnimationEventType {
- CSSAnimations,
- CSSTransitions
- };
-
- struct DispatchAnimationEventParams {
- AnimationEventType mEventType;
- nsRefreshDriver* mRefreshDriver;
- };
-}
-
static bool
DispatchAnimationEventsOnSubDocuments(nsIDocument* aDocument,
- void* aParams)
+ void* aRefreshDriver)
{
- MOZ_ASSERT(aParams, "Animation event parameters should be set");
- auto params = static_cast(aParams);
-
nsIPresShell* shell = aDocument->GetShell();
if (!shell) {
return true;
}
nsPresContext* context = shell->GetPresContext();
- if (!context || context->RefreshDriver() != params->mRefreshDriver) {
+ if (!context || context->RefreshDriver() != aRefreshDriver) {
return true;
}
nsCOMPtr kungFuDeathGrip(aDocument);
- if (params->mEventType == AnimationEventType::CSSAnimations) {
- context->AnimationManager()->DispatchEvents();
- } else {
- context->TransitionManager()->DispatchEvents();
- }
+ context->TransitionManager()->SortEvents();
+ context->AnimationManager()->SortEvents();
+
+ // Dispatch transition events first since transitions conceptually sit
+ // below animations in terms of compositing order.
+ context->TransitionManager()->DispatchEvents();
+ context->AnimationManager()->DispatchEvents();
+
aDocument->EnumerateSubDocuments(DispatchAnimationEventsOnSubDocuments,
- aParams);
+ aRefreshDriver);
return true;
}
@@ -1535,19 +1523,7 @@ nsRefreshDriver::DispatchAnimationEvents()
return;
}
- nsIDocument* doc = mPresContext->Document();
-
- // Dispatch transition events first since transitions conceptually sit
- // below animations in terms of compositing order.
- DispatchAnimationEventParams params { AnimationEventType::CSSTransitions,
- this };
- DispatchAnimationEventsOnSubDocuments(doc, ¶ms);
- if (!mPresContext) {
- return;
- }
-
- params.mEventType = AnimationEventType::CSSAnimations;
- DispatchAnimationEventsOnSubDocuments(doc, ¶ms);
+ DispatchAnimationEventsOnSubDocuments(mPresContext->Document(), this);
}
void
diff --git a/layout/generic/WritingModes.h b/layout/generic/WritingModes.h
index 410d9ffb2c..36abe007dc 100644
--- a/layout/generic/WritingModes.h
+++ b/layout/generic/WritingModes.h
@@ -456,10 +456,19 @@ public:
explicit WritingMode(nsStyleContext* aStyleContext)
{
NS_ASSERTION(aStyleContext, "we need an nsStyleContext here");
+ InitFromStyleVisibility(aStyleContext->StyleVisibility());
+ }
- const nsStyleVisibility* styleVisibility = aStyleContext->StyleVisibility();
+ explicit WritingMode(const nsStyleVisibility* aStyleVisibility)
+ {
+ NS_ASSERTION(aStyleVisibility, "we need an nsStyleVisibility here");
+ InitFromStyleVisibility(aStyleVisibility);
+ }
- switch (styleVisibility->mWritingMode) {
+private:
+ void InitFromStyleVisibility(const nsStyleVisibility* aStyleVisibility)
+ {
+ switch (aStyleVisibility->mWritingMode) {
case NS_STYLE_WRITING_MODE_HORIZONTAL_TB:
mWritingMode = 0;
break;
@@ -469,7 +478,7 @@ public:
mWritingMode = eBlockFlowMask |
eLineOrientMask |
eOrientationMask;
- uint8_t textOrientation = aStyleContext->StyleVisibility()->mTextOrientation;
+ uint8_t textOrientation = aStyleVisibility->mTextOrientation;
if (textOrientation == NS_STYLE_TEXT_ORIENTATION_SIDEWAYS) {
mWritingMode |= eSidewaysMask;
}
@@ -479,7 +488,7 @@ public:
case NS_STYLE_WRITING_MODE_VERTICAL_RL:
{
mWritingMode = eOrientationMask;
- uint8_t textOrientation = aStyleContext->StyleVisibility()->mTextOrientation;
+ uint8_t textOrientation = aStyleVisibility->mTextOrientation;
if (textOrientation == NS_STYLE_TEXT_ORIENTATION_SIDEWAYS) {
mWritingMode |= eSidewaysMask;
}
@@ -504,23 +513,34 @@ public:
break;
}
- if (NS_STYLE_DIRECTION_RTL == styleVisibility->mDirection) {
+ if (NS_STYLE_DIRECTION_RTL == aStyleVisibility->mDirection) {
mWritingMode ^= eInlineFlowMask | eBidiMask;
}
}
+public:
- // For unicode-bidi: plaintext, reset the direction of the writing mode from
- // the bidi paragraph level of the content
-
- //XXX change uint8_t to UBiDiLevel after bug 924851
+ /**
+ * This function performs fixup for elements with 'unicode-bidi: plaintext',
+ * where inline directionality is derived from the Unicode bidi categories
+ * of the element's content, and not the CSS 'direction' property.
+ *
+ * The WritingMode constructor will have already incorporated the 'direction'
+ * property into our flag bits, so such elements need to use this method
+ * (after resolving the bidi level of their content) to update the direction
+ * bits as needed.
+ *
+ * If it turns out that our bidi direction already matches what plaintext
+ * resolution determined, there's nothing to do here. If it didn't (i.e. if
+ * the rtl-ness doesn't match), then we correct the direction by flipping the
+ * same bits that get flipped in the constructor's CSS 'direction'-based
+ * chunk.
+ *
+ * XXX change uint8_t to UBiDiLevel after bug 924851
+ */
void SetDirectionFromBidiLevel(uint8_t level)
{
- if (IS_LEVEL_RTL(level)) {
- // set RTL
- mWritingMode |= eBidiMask;
- } else {
- // set LTR
- mWritingMode &= ~eBidiMask;
+ if (IS_LEVEL_RTL(level) == IsBidiLTR()) {
+ mWritingMode ^= eBidiMask | eInlineFlowMask;
}
}
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index ea98a5d30e..c8fd417ddc 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2325,9 +2325,12 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// dirty rect in child-relative coordinates
nsRect dirty = aDirtyRect - child->GetOffsetTo(this);
+ const nsStyleDisplay* disp;
nsIAtom* childType = child->GetType();
nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
- if (childType == nsGkAtoms::placeholderFrame) {
+ if (childType != nsGkAtoms::placeholderFrame) {
+ disp = child->StyleDisplay();
+ } else {
nsPlaceholderFrame* placeholder = static_cast(child);
child = placeholder->GetOutOfFlowFrame();
NS_ASSERTION(child, "No out of flow frame?");
@@ -2337,6 +2340,16 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
if (!child || nsLayoutUtils::IsPopup(child) ||
(child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT))
return;
+ MOZ_ASSERT(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW);
+ disp = child->StyleDisplay();
+ // If the out-of-flow frame is in the top layer, the viewport frame
+ // will paint it. Skip it here. Note that, only out-of-flow frames
+ // with this property should be skipped, because non-HTML elements
+ // may stop their children from being out-of-flow. Those frames
+ // should still be handled in the normal in-flow path.
+ if (disp->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
+ return;
+ }
// Make sure that any attempt to use childType below is disappointed. We
// could call GetType again but since we don't currently need it, let's
// avoid the virtual call.
@@ -2344,8 +2357,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
return;
- savedOutOfFlowData = static_cast
- (child->Properties().Get(nsDisplayListBuilder::OutOfFlowDisplayDataProperty()));
+ savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(child);
if (savedOutOfFlowData) {
dirty = savedOutOfFlowData->mDirtyRect;
} else {
@@ -2415,7 +2427,6 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// Child is composited if it's transformed, partially transparent, or has
// SVG effects or a blend mode..
- const nsStyleDisplay* disp = child->StyleDisplay();
const nsStylePosition* pos = child->StylePosition();
bool isVisuallyAtomic = child->HasOpacity()
|| child->IsTransformed()
diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h
index 44e640bb6b..7154f9c973 100644
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -231,6 +231,7 @@ protected:
protected:
friend class nsImageListener;
friend class nsImageLoadingContent;
+ friend class PresShell;
nsresult OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
nsresult OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect);
diff --git a/layout/generic/nsViewportFrame.cpp b/layout/generic/nsViewportFrame.cpp
index a0e73a2f4c..e51066c043 100644
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -14,6 +14,7 @@
#include "nsSubDocumentFrame.h"
#include "nsAbsoluteContainingBlock.h"
#include "GeckoProfiler.h"
+#include "nsIMozBrowserFrame.h"
using namespace mozilla;
@@ -51,14 +52,89 @@ ViewportFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
PROFILER_LABEL("ViewportFrame", "BuildDisplayList",
js::ProfileEntry::Category::GRAPHICS);
- nsIFrame* kid = mFrames.FirstChild();
- if (!kid)
- return;
+ if (nsIFrame* kid = mFrames.FirstChild()) {
+ // make the kid's BorderBackground our own. This ensures that the canvas
+ // frame's background becomes our own background and therefore appears
+ // below negative z-index elements.
+ BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
+ }
- // make the kid's BorderBackground our own. This ensures that the canvas
- // frame's background becomes our own background and therefore appears
- // below negative z-index elements.
- BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
+ nsDisplayList topLayerList;
+ BuildDisplayListForTopLayer(aBuilder, &topLayerList);
+ if (!topLayerList.IsEmpty()) {
+ // Wrap the whole top layer in a single item with maximum z-index,
+ // and append it at the very end, so that it stays at the topmost.
+ nsDisplayWrapList* wrapList =
+ new (aBuilder) nsDisplayWrapList(aBuilder, this, &topLayerList);
+ wrapList->SetOverrideZIndex(
+ std::numeric_limitsZIndex())>::max());
+ aLists.PositionedDescendants()->AppendNewToTop(wrapList);
+ }
+}
+
+#ifdef DEBUG
+/**
+ * Returns whether we are going to put an element in the top layer for
+ * fullscreen. This function should matches the CSS rule in ua.css.
+ */
+static bool
+ShouldInTopLayerForFullscreen(Element* aElement)
+{
+ if (!aElement->GetParent()) {
+ return false;
+ }
+ nsCOMPtr browserFrame = do_QueryInterface(aElement);
+ if (browserFrame && browserFrame->GetReallyIsBrowserOrApp()) {
+ return false;
+ }
+ return true;
+}
+#endif // DEBUG
+
+void
+ViewportFrame::BuildDisplayListForTopLayer(nsDisplayListBuilder* aBuilder,
+ nsDisplayList* aList)
+{
+ nsIDocument* doc = PresContext()->Document();
+ nsTArray fullscreenStack = doc->GetFullscreenStack();
+ for (Element* elem : fullscreenStack) {
+ if (nsIFrame* frame = elem->GetPrimaryFrame()) {
+ // There are two cases where an element in fullscreen is not in
+ // the top layer:
+ // 1. When building display list for purpose other than painting,
+ // it is possible that there is inconsistency between the style
+ // info and the content tree.
+ // 2. This is an element which we are not going to put in the top
+ // layer for fullscreen. See ShouldInTopLayerForFullscreen().
+ // In both cases, we want to skip the frame here and paint it in
+ // the normal path.
+ if (frame->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_NONE) {
+ MOZ_ASSERT(!aBuilder->IsForPainting() ||
+ !ShouldInTopLayerForFullscreen(elem));
+ continue;
+ }
+ MOZ_ASSERT(ShouldInTopLayerForFullscreen(elem));
+ // Inner SVG, MathML elements, as well as children of some XUL
+ // elements are not allowed to be out-of-flow. They should not
+ // be handled as top layer element here.
+ if (!(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+ MOZ_ASSERT(!elem->GetParent()->IsHTMLElement(), "HTML element "
+ "should always be out-of-flow if in the top layer");
+ continue;
+ }
+ MOZ_ASSERT(frame->GetParent() == this);
+
+ nsRect dirty;
+ nsDisplayListBuilder::OutOfFlowDisplayData*
+ savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(frame);
+ if (savedOutOfFlowData) {
+ dirty = savedOutOfFlowData->mDirtyRect;
+ }
+ nsDisplayList list;
+ frame->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
+ aList->AppendToTop(&list);
+ }
+ }
}
#ifdef DEBUG
diff --git a/layout/generic/nsViewportFrame.h b/layout/generic/nsViewportFrame.h
index ad7739363b..13b5950454 100644
--- a/layout/generic/nsViewportFrame.h
+++ b/layout/generic/nsViewportFrame.h
@@ -63,6 +63,9 @@ public:
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists) override;
+ void BuildDisplayListForTopLayer(nsDisplayListBuilder* aBuilder,
+ nsDisplayList* aList);
+
virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
virtual void Reflow(nsPresContext* aPresContext,
diff --git a/layout/inspector/inDOMUtils.cpp b/layout/inspector/inDOMUtils.cpp
index 9aa4a6f358..d9e6edd1df 100644
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -83,11 +83,11 @@ inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
nsIPresShell* presShell = document->GetShell();
if (presShell) {
nsStyleSet* styleSet = presShell->StyleSet();
- nsStyleSet::sheetType sheetType = nsStyleSet::eAgentSheet;
+ SheetType sheetType = SheetType::Agent;
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
}
- sheetType = nsStyleSet::eUserSheet;
+ sheetType = SheetType::User;
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
}
@@ -511,14 +511,14 @@ inDOMUtils::GetCSSPropertyNames(uint32_t aFlags, uint32_t* aCount,
char16_t** props =
static_cast(moz_xmalloc(maxCount * sizeof(char16_t*)));
-#define DO_PROP(_prop) \
- PR_BEGIN_MACRO \
- nsCSSProperty cssProp = nsCSSProperty(_prop); \
- if (nsCSSProps::IsEnabled(cssProp)) { \
- props[propCount] = \
- ToNewUnicode(nsDependentCString(kCSSRawProperties[_prop])); \
- ++propCount; \
- } \
+#define DO_PROP(_prop) \
+ PR_BEGIN_MACRO \
+ nsCSSProperty cssProp = nsCSSProperty(_prop); \
+ if (nsCSSProps::IsEnabled(cssProp, nsCSSProps::eEnabledForAllContent)) { \
+ props[propCount] = \
+ ToNewUnicode(nsDependentCString(kCSSRawProperties[_prop])); \
+ ++propCount; \
+ } \
PR_END_MACRO
// prop is the property id we're considering; propCount is how many properties
@@ -1259,7 +1259,7 @@ inDOMUtils::ParseStyleSheet(nsIDOMCSSStyleSheet *aSheet,
RefPtr sheet = do_QueryObject(aSheet);
NS_ENSURE_ARG_POINTER(sheet);
- return sheet->ParseSheet(aInput);
+ return sheet->ReparseSheet(aInput);
}
NS_IMETHODIMP
diff --git a/layout/inspector/tests/bug1202095-2.css b/layout/inspector/tests/bug1202095-2.css
new file mode 100644
index 0000000000..a484814ebf
--- /dev/null
+++ b/layout/inspector/tests/bug1202095-2.css
@@ -0,0 +1,7 @@
+/*
+ * Bug 1202095 - parseStyleSheet should not re-load @imports
+ */
+
+body {
+ color: chartreuse;
+}
diff --git a/layout/inspector/tests/bug1202095.css b/layout/inspector/tests/bug1202095.css
new file mode 100644
index 0000000000..fa8ef0feb6
--- /dev/null
+++ b/layout/inspector/tests/bug1202095.css
@@ -0,0 +1,7 @@
+/*
+ * Bug 1202095 - parseStyleSheet should not re-load @imports
+ */
+
+body {
+ background-color: purple;
+}
diff --git a/layout/inspector/tests/mochitest.ini b/layout/inspector/tests/mochitest.ini
index 6507fbbe07..4dd9acdd3a 100644
--- a/layout/inspector/tests/mochitest.ini
+++ b/layout/inspector/tests/mochitest.ini
@@ -1,5 +1,7 @@
[DEFAULT]
support-files =
+ bug1202095.css
+ bug1202095-2.css
bug856317.css
file_bug522601.html
@@ -21,4 +23,6 @@ support-files =
[test_get_all_style_sheets.html]
[test_is_valid_css_color.html]
[test_isinheritableproperty.html]
+[test_parseStyleSheet.html]
+[test_parseStyleSheetImport.html]
[test_selectormatcheselement.html]
diff --git a/layout/inspector/tests/test_parseStyleSheet.html b/layout/inspector/tests/test_parseStyleSheet.html
new file mode 100644
index 0000000000..f7ddf6e9e5
--- /dev/null
+++ b/layout/inspector/tests/test_parseStyleSheet.html
@@ -0,0 +1,34 @@
+
+
+
+
+ Test for Bug 1195978
+
+
+
+
+
+
+
+
diff --git a/layout/inspector/tests/test_parseStyleSheetImport.html b/layout/inspector/tests/test_parseStyleSheetImport.html
new file mode 100644
index 0000000000..73fef2d51a
--- /dev/null
+++ b/layout/inspector/tests/test_parseStyleSheetImport.html
@@ -0,0 +1,83 @@
+
+
+
+
+ Test for Bug 1202095
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/bugs/1209603-1-ref.html b/layout/reftests/bugs/1209603-1-ref.html
new file mode 100644
index 0000000000..a2eacedbc6
--- /dev/null
+++ b/layout/reftests/bugs/1209603-1-ref.html
@@ -0,0 +1,13 @@
+
+Testcase, bug 1209603
+
+
+Should be 40px font size.
+
+Should be 20px font size.
diff --git a/layout/reftests/bugs/1209603-1.html b/layout/reftests/bugs/1209603-1.html
new file mode 100644
index 0000000000..5bbc45ee40
--- /dev/null
+++ b/layout/reftests/bugs/1209603-1.html
@@ -0,0 +1,50 @@
+
+Testcase, bug 1209603
+
+
+Should be 40px font size.
+
+
+
+
+Should be 20px font size.
+
+
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list
index 5e57d2d18d..8f6dc4ccb5 100644
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1933,3 +1933,4 @@ fuzzy(1,74) fuzzy-if(gtkWidget,6,79) == 1174332-1.html 1174332-1-ref.html
== 1179078-1.html 1179078-1-ref.html
== 1179288-1.html 1179288-1-ref.html
== 1190635-1.html 1190635-1-ref.html
+== 1209603-1.html 1209603-1-ref.html
diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list
index eb83a772e9..9787587b57 100644
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -310,6 +310,10 @@ pref(layout.css.text-align-unsafe-value.enabled,true) == text-align-unsafe.html
!= control-chars-02.html control-chars-02-notref.html
== control-chars-03a.html control-chars-03-ref.html
== control-chars-03b.html control-chars-03-ref.html
+pref(layout.css.control-characters.visible,true) != control-chars-04a.html control-chars-04-notref.html
+pref(layout.css.control-characters.visible,true) != control-chars-04b.html control-chars-04-notref.html
+pref(layout.css.control-characters.visible,true) != control-chars-04c.html control-chars-04-notref.html
+pref(layout.css.control-characters.visible,true) != control-chars-04d.html control-chars-04-notref.html
# font fallback for when not supported in the primary font family - bug 970891
HTTP(..) == space-font-1.html space-font-1-ref.html
diff --git a/layout/style/AnimationCommon.cpp b/layout/style/AnimationCommon.cpp
index 1105623b6a..789e58ab38 100644
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -362,7 +362,7 @@ CommonAnimationManager::GetAnimations(dom::Element *aElement,
}
void
-CommonAnimationManager::FlushAnimations(FlushFlags aFlags)
+CommonAnimationManager::FlushAnimations()
{
TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
for (AnimationCollection* collection = mElementCollections.getFirst();
@@ -371,15 +371,13 @@ CommonAnimationManager::FlushAnimations(FlushFlags aFlags)
continue;
}
- if (aFlags == Cannot_Throttle) {
- collection->RequestRestyle(AnimationCollection::RestyleType::Standard);
- }
+ MOZ_ASSERT(collection->mElement->GetComposedDoc() ==
+ mPresContext->Document(),
+ "Should not have a transition/animation collection for an "
+ "element that is not part of the document tree");
- nsAutoAnimationMutationBatch mb(collection->mElement->OwnerDoc());
- collection->Tick();
+ collection->RequestRestyle(AnimationCollection::RestyleType::Standard);
}
-
- MaybeStartOrStopObservingRefreshDriver();
}
nsIStyleRule*
@@ -911,10 +909,6 @@ AnimationCollection::RequestRestyle(RestyleType aRestyleType)
return;
}
- MOZ_ASSERT(mElement->GetCrossShadowCurrentDoc() == presContext->Document(),
- "Element::UnbindFromTree should have destroyed the element "
- "transition/animations object");
-
// Steps for Restyle::Layer:
if (aRestyleType == RestyleType::Layer) {
@@ -995,7 +989,7 @@ AnimationCollection::HasCurrentAnimationsForProperties(
const Animation& anim = *mAnimations[animIdx];
const KeyframeEffectReadOnly* effect = anim.GetEffect();
if (effect &&
- effect->IsCurrent(anim) &&
+ effect->IsCurrent() &&
effect->HasAnimationOfProperties(aProperties, aPropertyCount)) {
return true;
}
diff --git a/layout/style/AnimationCommon.h b/layout/style/AnimationCommon.h
index d183d37847..f7544fc1a8 100644
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -6,12 +6,14 @@
#ifndef mozilla_css_AnimationCommon_h
#define mozilla_css_AnimationCommon_h
+#include // For
#include "nsIStyleRuleProcessor.h"
#include "nsIStyleRule.h"
#include "nsRefreshDriver.h"
#include "nsChangeHint.h"
#include "nsCSSProperty.h"
#include "nsDisplayList.h" // For nsDisplayItem::Type
+#include "mozilla/AnimationComparator.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/LinkedList.h"
#include "mozilla/MemoryReporting.h"
@@ -96,11 +98,9 @@ public:
return false;
}
- enum FlushFlags {
- Can_Throttle,
- Cannot_Throttle
- };
- void FlushAnimations(FlushFlags aFlags);
+ // Requests a standard restyle on each managed AnimationCollection that has
+ // an out-of-date mStyleRuleRefreshTime.
+ void FlushAnimations();
nsIStyleRule* GetAnimationRule(dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType);
@@ -507,23 +507,49 @@ template
class DelayedEventDispatcher
{
public:
+ DelayedEventDispatcher() : mIsSorted(true) { }
+
void QueueEvent(EventInfo&& aEventInfo)
{
- mPendingEvents.AppendElement(mozilla::Forward(aEventInfo));
+ mPendingEvents.AppendElement(Forward(aEventInfo));
+ mIsSorted = false;
+ }
+
+ // This is exposed as a separate method so that when we are dispatching
+ // *both* transition events and animation events we can sort both lists
+ // once using the current state of the document before beginning any
+ // dispatch.
+ void SortEvents()
+ {
+ if (mIsSorted) {
+ return;
+ }
+
+ // FIXME: Replace with mPendingEvents.StableSort when bug 1147091 is
+ // fixed.
+ std::stable_sort(mPendingEvents.begin(), mPendingEvents.end(),
+ EventInfoLessThan());
+ mIsSorted = true;
}
// Takes a reference to the owning manager's pres context so it can
// detect if the pres context is destroyed while dispatching one of
// the events.
+ //
+ // This will call SortEvents automatically if it has not already been
+ // called.
void DispatchEvents(nsPresContext* const & aPresContext)
{
if (!aPresContext || mPendingEvents.IsEmpty()) {
return;
}
+ SortEvents();
+
EventArray events;
mPendingEvents.SwapElements(events);
- // FIXME: Sort events here in timeline order, then document order
+ // mIsSorted will be set to true by SortEvents above, and we leave it
+ // that way since mPendingEvents is now empty
for (EventInfo& info : events) {
EventDispatcher::Dispatch(info.mElement, aPresContext, &info.mEvent);
@@ -533,7 +559,11 @@ public:
}
}
- void ClearEventQueue() { mPendingEvents.Clear(); }
+ void ClearEventQueue()
+ {
+ mPendingEvents.Clear();
+ mIsSorted = true;
+ }
bool HasQueuedEvents() const { return !mPendingEvents.IsEmpty(); }
// Methods for supporting cycle-collection
@@ -542,14 +572,34 @@ public:
{
for (EventInfo& info : mPendingEvents) {
ImplCycleCollectionTraverse(*aCallback, info.mElement, aName);
+ ImplCycleCollectionTraverse(*aCallback, info.mAnimation, aName);
}
}
- void Unlink() { mPendingEvents.Clear(); }
+ void Unlink() { ClearEventQueue(); }
protected:
- typedef nsTArray EventArray;
+ class EventInfoLessThan
+ {
+ public:
+ bool operator()(const EventInfo& a, const EventInfo& b) const
+ {
+ if (a.mTimeStamp != b.mTimeStamp) {
+ // Null timestamps sort first
+ if (a.mTimeStamp.IsNull() || b.mTimeStamp.IsNull()) {
+ return a.mTimeStamp.IsNull();
+ } else {
+ return a.mTimeStamp < b.mTimeStamp;
+ }
+ }
+ AnimationPtrComparator> comparator;
+ return comparator.LessThan(a.mAnimation, b.mAnimation);
+ }
+ };
+
+ typedef nsTArray EventArray;
EventArray mPendingEvents;
+ bool mIsSorted;
};
template
diff --git a/layout/style/CSSStyleSheet.cpp b/layout/style/CSSStyleSheet.cpp
index e213997ef2..b95a4c5b4f 100644
--- a/layout/style/CSSStyleSheet.cpp
+++ b/layout/style/CSSStyleSheet.cpp
@@ -47,6 +47,7 @@
#include "nsComponentManagerUtils.h"
#include "nsNullPrincipal.h"
#include "mozilla/RuleProcessorCache.h"
+#include "nsIStyleSheetLinkingElement.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -2267,7 +2268,7 @@ CSSStyleSheet::StyleSheetLoaded(CSSStyleSheet* aSheet,
}
nsresult
-CSSStyleSheet::ParseSheet(const nsAString& aInput)
+CSSStyleSheet::ReparseSheet(const nsAString& aInput)
{
// Not doing this if the sheet is not complete!
if (!mInner->mComplete) {
@@ -2289,21 +2290,37 @@ CSSStyleSheet::ParseSheet(const nsAString& aInput)
WillDirty();
// detach existing rules (including child sheets via import rules)
+ css::LoaderReusableStyleSheets reusableSheets;
int ruleCount;
while ((ruleCount = mInner->mOrderedRules.Count()) != 0) {
RefPtr rule = mInner->mOrderedRules.ObjectAt(ruleCount - 1);
mInner->mOrderedRules.RemoveObjectAt(ruleCount - 1);
rule->SetStyleSheet(nullptr);
+ if (rule->GetType() == css::Rule::IMPORT_RULE) {
+ nsCOMPtr importRule(do_QueryInterface(rule));
+ NS_ASSERTION(importRule, "GetType lied");
+
+ nsCOMPtr childSheet;
+ importRule->GetStyleSheet(getter_AddRefs(childSheet));
+
+ RefPtr cssSheet = do_QueryObject(childSheet);
+ if (cssSheet && cssSheet->GetOriginalURI()) {
+ reusableSheets.AddReusableSheet(cssSheet);
+ }
+ }
if (mDocument) {
mDocument->StyleRuleRemoved(this, rule);
}
}
// nuke child sheets list and current namespace map
- for (CSSStyleSheet* child = mInner->mFirstChild; child; child = child->mNext) {
+ for (CSSStyleSheet* child = mInner->mFirstChild; child; ) {
NS_ASSERTION(child->mParent == this, "Child sheet is not parented to this!");
+ CSSStyleSheet* next = child->mNext;
child->mParent = nullptr;
child->mDocument = nullptr;
+ child->mNext = nullptr;
+ child = next;
}
mInner->mFirstChild = nullptr;
mInner->mNameSpaceMap = nullptr;
@@ -2311,9 +2328,18 @@ CSSStyleSheet::ParseSheet(const nsAString& aInput)
// allow unsafe rules if the style sheet's principal is the system principal
bool allowUnsafeRules = nsContentUtils::IsSystemPrincipal(mInner->mPrincipal);
+ uint32_t lineNumber = 1;
+ if (mOwningNode) {
+ nsCOMPtr link = do_QueryInterface(mOwningNode);
+ if (link) {
+ lineNumber = link->GetLineNumber();
+ }
+ }
+
nsCSSParser parser(loader, this);
nsresult rv = parser.ParseSheet(aInput, mInner->mSheetURI, mInner->mBaseURI,
- mInner->mPrincipal, 1, allowUnsafeRules);
+ mInner->mPrincipal, lineNumber,
+ allowUnsafeRules, &reusableSheets);
DidDirty(); // we are always 'dirty' here since we always remove rules first
NS_ENSURE_SUCCESS(rv, rv);
diff --git a/layout/style/CSSStyleSheet.h b/layout/style/CSSStyleSheet.h
index 7e1ba545c2..4bccac1f2d 100644
--- a/layout/style/CSSStyleSheet.h
+++ b/layout/style/CSSStyleSheet.h
@@ -242,7 +242,7 @@ public:
bool UseForPresentation(nsPresContext* aPresContext,
nsMediaQueryResultCacheKey& aKey) const;
- nsresult ParseSheet(const nsAString& aInput);
+ nsresult ReparseSheet(const nsAString& aInput);
void SetInRuleProcessorCache() { mInRuleProcessorCache = true; }
diff --git a/layout/style/Declaration.cpp b/layout/style/Declaration.cpp
index 5b7cbfbcbb..153a60ee72 100644
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -22,7 +22,6 @@ namespace css {
Declaration::Declaration()
: mImmutable(false)
{
- MOZ_COUNT_CTOR(mozilla::css::Declaration);
}
Declaration::Declaration(const Declaration& aCopy)
@@ -39,12 +38,10 @@ Declaration::Declaration(const Declaration& aCopy)
nullptr),
mImmutable(false)
{
- MOZ_COUNT_CTOR(mozilla::css::Declaration);
}
Declaration::~Declaration()
{
- MOZ_COUNT_DTOR(mozilla::css::Declaration);
}
void
@@ -1250,7 +1247,7 @@ Declaration::ToString(nsAString& aString) const
continue;
}
- if (!nsCSSProps::IsEnabled(property)) {
+ if (!nsCSSProps::IsEnabled(property, nsCSSProps::eEnabledForAllContent)) {
continue;
}
bool doneProperty = false;
@@ -1379,15 +1376,17 @@ Declaration::InitializeEmpty()
mData = nsCSSCompressedDataBlock::CreateEmptyBlock();
}
-Declaration*
+already_AddRefed
Declaration::EnsureMutable()
{
MOZ_ASSERT(mData, "should only be called when not expanded");
+ RefPtr result;
if (!IsMutable()) {
- return new Declaration(*this);
+ result = new Declaration(*this);
} else {
- return this;
+ result = this;
}
+ return result.forget();
}
size_t
diff --git a/layout/style/Declaration.h b/layout/style/Declaration.h
index 0f7ae3f2a9..d90e52d2fa 100644
--- a/layout/style/Declaration.h
+++ b/layout/style/Declaration.h
@@ -49,8 +49,12 @@ public:
Declaration(const Declaration& aCopy);
+ NS_INLINE_DECL_REFCOUNTING(Declaration)
+
+private:
~Declaration();
+public:
/**
* |ValueAppended| must be called to maintain this declaration's
* |mOrder| whenever a property is parsed into an expanded data block
@@ -243,7 +247,7 @@ public:
/**
* Copy |this|, if necessary to ensure that it can be modified.
*/
- Declaration* EnsureMutable();
+ already_AddRefed EnsureMutable();
/**
* Crash if |this| cannot be modified.
diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp
index c80410b640..5b4adacd19 100644
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -173,8 +173,8 @@ FontFaceSet::ParseFontShorthandForMatching(
ErrorResult& aRv)
{
// Parse aFont as a 'font' property value.
- Declaration declaration;
- declaration.InitializeEmpty();
+ RefPtr declaration = new Declaration;
+ declaration->InitializeEmpty();
bool changed = false;
nsCSSParser parser;
@@ -183,23 +183,23 @@ FontFaceSet::ParseFontShorthandForMatching(
mDocument->GetDocumentURI(),
mDocument->GetDocumentURI(),
mDocument->NodePrincipal(),
- &declaration,
+ declaration,
&changed,
/* aIsImportant */ false);
// All of the properties we are interested in should have been set at once.
- MOZ_ASSERT(changed == (declaration.HasProperty(eCSSProperty_font_family) &&
- declaration.HasProperty(eCSSProperty_font_style) &&
- declaration.HasProperty(eCSSProperty_font_weight) &&
- declaration.HasProperty(eCSSProperty_font_stretch)));
+ MOZ_ASSERT(changed == (declaration->HasProperty(eCSSProperty_font_family) &&
+ declaration->HasProperty(eCSSProperty_font_style) &&
+ declaration->HasProperty(eCSSProperty_font_weight) &&
+ declaration->HasProperty(eCSSProperty_font_stretch)));
if (!changed) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return;
}
- nsCSSCompressedDataBlock* data = declaration.GetNormalBlock();
- MOZ_ASSERT(!declaration.GetImportantBlock());
+ nsCSSCompressedDataBlock* data = declaration->GetNormalBlock();
+ MOZ_ASSERT(!declaration->GetImportantBlock());
const nsCSSValue* family = data->ValueFor(eCSSProperty_font_family);
if (family->GetUnit() != eCSSUnit_FontFamilyList) {
@@ -426,7 +426,7 @@ FontFaceSet::Add(FontFace& aFontFace, ErrorResult& aRv)
FontFaceRecord* rec = mNonRuleFaces.AppendElement();
rec->mFontFace = &aFontFace;
- rec->mSheetType = 0; // unused for mNonRuleFaces
+ rec->mSheetType = SheetType::Unknown; // unused for mNonRuleFaces
rec->mLoadEventShouldFire =
aFontFace.Status() == FontFaceLoadStatus::Unloaded ||
aFontFace.Status() == FontFaceLoadStatus::Loading;
@@ -834,7 +834,7 @@ FontFaceSet::InsertNonRuleFontFace(FontFace* aFontFace,
// InsertRuleFontFace does?
RefPtr entry =
FindOrCreateUserFontEntryFromFontFace(fontfamily, aFontFace,
- nsStyleSet::eDocSheet);
+ SheetType::Doc);
if (!entry) {
return;
}
@@ -846,7 +846,7 @@ FontFaceSet::InsertNonRuleFontFace(FontFace* aFontFace,
}
void
-FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, uint8_t aSheetType,
+FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
nsTArray& aOldRecords,
bool& aFontSetModified)
{
@@ -957,13 +957,13 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace)
}
return FindOrCreateUserFontEntryFromFontFace(fontfamily, aFontFace,
- nsStyleSet::eDocSheet);
+ SheetType::Doc);
}
/* static */ already_AddRefed
FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
FontFace* aFontFace,
- uint8_t aSheetType)
+ SheetType aSheetType)
{
FontFaceSet* set = aFontFace->GetPrimaryFontFaceSet();
@@ -1102,8 +1102,8 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
// the same-site origin check and access control headers are
// enforced against the sheet principal rather than the document
// principal to allow user stylesheets to include @font-face rules
- face->mUseOriginPrincipal = (aSheetType == nsStyleSet::eUserSheet ||
- aSheetType == nsStyleSet::eAgentSheet);
+ face->mUseOriginPrincipal = (aSheetType == SheetType::User ||
+ aSheetType == SheetType::Agent);
face->mLocalName.Truncate();
face->mFormatFlags = 0;
diff --git a/layout/style/FontFaceSet.h b/layout/style/FontFaceSet.h
index 1d6c5ac1e2..541bb6c7e8 100644
--- a/layout/style/FontFaceSet.h
+++ b/layout/style/FontFaceSet.h
@@ -226,7 +226,7 @@ private:
// accordingly.
struct FontFaceRecord {
RefPtr mFontFace;
- uint8_t mSheetType; // only relevant for mRuleFaces entries
+ SheetType mSheetType; // only relevant for mRuleFaces entries
// When true, indicates that when finished loading, the FontFace should be
// included in the subsequent loadingdone/loadingerror event fired at the
@@ -237,7 +237,7 @@ private:
static already_AddRefed FindOrCreateUserFontEntryFromFontFace(
const nsAString& aFamilyName,
FontFace* aFontFace,
- uint8_t aSheetType);
+ SheetType aSheetType);
// search for @font-face rule that matches a userfont font entry
nsCSSFontFaceRule* FindRuleForUserFontEntry(gfxUserFontEntry* aUserFontEntry);
@@ -258,7 +258,7 @@ private:
nsresult aStatus);
void RebuildUserFontSet();
- void InsertRuleFontFace(FontFace* aFontFace, uint8_t aSheetType,
+ void InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
nsTArray& aOldRecords,
bool& aFontSetModified);
void InsertNonRuleFontFace(FontFace* aFontFace, bool& aFontSetModified);
diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp
index 24b253f779..2bf3a648a8 100644
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -507,6 +507,30 @@ SheetLoadData::ScheduleLoadEventIfNeeded(nsresult aStatus)
}
}
+/*********************
+ * Style sheet reuse *
+ *********************/
+
+bool
+LoaderReusableStyleSheets::FindReusableStyleSheet(nsIURI* aURL,
+ RefPtr& aResult)
+{
+ MOZ_ASSERT(aURL);
+ for (size_t i = mReusableSheets.Length(); i > 0; --i) {
+ size_t index = i - 1;
+ bool sameURI;
+ MOZ_ASSERT(mReusableSheets[index]->GetOriginalURI());
+ nsresult rv = aURL->Equals(mReusableSheets[index]->GetOriginalURI(),
+ &sameURI);
+ if (!NS_FAILED(rv) && sameURI) {
+ aResult = mReusableSheets[index];
+ mReusableSheets.RemoveElementAt(index);
+ return true;
+ }
+ }
+ return false;
+}
+
/*************************
* Loader Implementation *
*************************/
@@ -2151,7 +2175,8 @@ nsresult
Loader::LoadChildSheet(CSSStyleSheet* aParentSheet,
nsIURI* aURL,
nsMediaList* aMedia,
- ImportRule* aParentRule)
+ ImportRule* aParentRule,
+ LoaderReusableStyleSheets* aReusableSheets)
{
LOG(("css::Loader::LoadChildSheet"));
NS_PRECONDITION(aURL, "Must have a URI to load");
@@ -2220,18 +2245,23 @@ Loader::LoadChildSheet(CSSStyleSheet* aParentSheet,
// Now that we know it's safe to load this (passes security check and not a
// loop) do so.
RefPtr sheet;
- bool isAlternate;
StyleSheetState state;
- const nsSubstring& empty = EmptyString();
- // For now, use CORS_NONE for child sheets
- rv = CreateSheet(aURL, nullptr, principal, CORS_NONE,
- aParentSheet->GetReferrerPolicy(),
- EmptyString(), // integrity is only checked on main sheet
- parentData ? parentData->mSyncLoad : false,
- false, empty, state, &isAlternate, getter_AddRefs(sheet));
- NS_ENSURE_SUCCESS(rv, rv);
+ if (aReusableSheets && aReusableSheets->FindReusableStyleSheet(aURL, sheet)) {
+ aParentRule->SetSheet(sheet);
+ state = eSheetComplete;
+ } else {
+ bool isAlternate;
+ const nsSubstring& empty = EmptyString();
+ // For now, use CORS_NONE for child sheets
+ rv = CreateSheet(aURL, nullptr, principal, CORS_NONE,
+ aParentSheet->GetReferrerPolicy(),
+ EmptyString(), // integrity is only checked on main sheet
+ parentData ? parentData->mSyncLoad : false,
+ false, empty, state, &isAlternate, getter_AddRefs(sheet));
+ NS_ENSURE_SUCCESS(rv, rv);
- PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate);
+ PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate);
+ }
rv = InsertChildSheet(sheet, aParentSheet, aParentRule);
NS_ENSURE_SUCCESS(rv, rv);
diff --git a/layout/style/Loader.h b/layout/style/Loader.h
index 6c86097120..22a32f4bd2 100644
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -20,6 +20,7 @@
#include "nsURIHashKey.h"
#include "mozilla/Attributes.h"
#include "mozilla/CORSMode.h"
+#include "mozilla/CSSStyleSheet.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/net/ReferrerPolicy.h"
@@ -30,7 +31,6 @@ class nsMediaList;
class nsIStyleSheetLinkingElement;
namespace mozilla {
-class CSSStyleSheet;
namespace dom {
class Element;
} // namespace dom
@@ -131,6 +131,47 @@ namespace css {
class SheetLoadData;
class ImportRule;
+/*********************
+ * Style sheet reuse *
+ *********************/
+
+class MOZ_RAII LoaderReusableStyleSheets
+{
+public:
+ LoaderReusableStyleSheets()
+ {
+ }
+
+ /**
+ * Look for a reusable sheet (see AddReusableSheet) matching the
+ * given URL. If found, set aResult, remove the reused sheet from
+ * the internal list, and return true. If not found, return false;
+ * in this case, aResult is not modified.
+ *
+ * @param aURL the url to match
+ * @param aResult [out] the style sheet which can be reused
+ */
+ bool FindReusableStyleSheet(nsIURI* aURL, RefPtr& aResult);
+
+ /**
+ * Indicate that a certain style sheet is available for reuse if its
+ * URI matches the URI of an @import. Sheets should be added in the
+ * opposite order in which they are intended to be reused.
+ *
+ * @param aSheet the sheet which can be reused
+ */
+ void AddReusableSheet(CSSStyleSheet* aSheet) {
+ mReusableSheets.AppendElement(aSheet);
+ }
+
+private:
+ LoaderReusableStyleSheets(const LoaderReusableStyleSheets&) = delete;
+ LoaderReusableStyleSheets& operator=(const LoaderReusableStyleSheets&) = delete;
+
+ // The sheets that can be reused.
+ nsTArray> mReusableSheets;
+};
+
/***********************************************************************
* Enum that describes the state of the sheet returned by CreateSheet. *
***********************************************************************/
@@ -242,11 +283,14 @@ public:
* @param aMedia the already-parsed media list for the child sheet
* @param aRule the @import rule importing this child. This is used to
* properly order the child sheet list of aParentSheet.
+ * @param aSavedSheets any saved style sheets which could be reused
+ * for this load
*/
nsresult LoadChildSheet(CSSStyleSheet* aParentSheet,
nsIURI* aURL,
nsMediaList* aMedia,
- ImportRule* aRule);
+ ImportRule* aRule,
+ LoaderReusableStyleSheets* aSavedSheets);
/**
* Synchronously load and return the stylesheet at aURL. Any child sheets
diff --git a/layout/style/RuleNodeCacheConditions.h b/layout/style/RuleNodeCacheConditions.h
index e34b6a8381..044434e29d 100644
--- a/layout/style/RuleNodeCacheConditions.h
+++ b/layout/style/RuleNodeCacheConditions.h
@@ -20,6 +20,22 @@ class nsStyleContext;
namespace mozilla {
+/**
+ * nsRuleNodeCacheConditions is used to store information about whether
+ * we can store a style struct that we're computing in the rule tree.
+ *
+ * For inherited structs (i.e., structs with inherited properties), we
+ * cache the struct in the rule tree if it does not depend on any data
+ * in the style context tree, and otherwise store it in the style
+ * context tree. This means that for inherited structs, setting any
+ * conditions is equivalent to making the struct uncacheable.
+ *
+ * For reset structs (i.e., structs with non-inherited properties), we
+ * are also able to cache structs in the rule tree conditionally on
+ * certain common conditions. For these structs, setting conditions
+ * (SetFontSizeDependency, SetWritingModeDependency) instead causes the
+ * struct to be stored, with the condition, in the rule tree.
+ */
class RuleNodeCacheConditions
{
public:
@@ -45,6 +61,15 @@ public:
bool Matches(nsStyleContext* aStyleContext) const;
+ /**
+ * Record that the data being computed depend on the font-size
+ * property of the element for which they are being computed.
+ *
+ * Note that we sometimes actually call this when there is a
+ * dependency on the font-size property of the parent element, but we
+ * only do so while computing inherited structs (nsStyleFont), and we
+ * only store reset structs conditionally.
+ */
void SetFontSizeDependency(nscoord aCoord)
{
MOZ_ASSERT(!(mBits & eHaveFontSize) || mFontSize == aCoord);
@@ -52,6 +77,12 @@ public:
mBits |= eHaveFontSize;
}
+ /**
+ * Record that the data being computed depend on the writing mode of
+ * the element for which they are being computed, which in turn
+ * depends on its 'writing-mode', 'direction', and 'text-orientation'
+ * properties.
+ */
void SetWritingModeDependency(uint8_t aWritingMode)
{
MOZ_ASSERT(!(mBits & eHaveWritingMode) || GetWritingMode() == aWritingMode);
diff --git a/layout/style/SheetType.h b/layout/style/SheetType.h
new file mode 100644
index 0000000000..8554116247
--- /dev/null
+++ b/layout/style/SheetType.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/* enum to represent a level in the cascade */
+
+#ifndef mozilla_SheetType_h
+#define mozilla_SheetType_h
+
+namespace mozilla {
+
+// The "origins" of the CSS cascade, from lowest precedence to
+// highest (for non-!important rules).
+//
+// Be sure to update NS_RULE_NODE_LEVEL_MASK when changing the number
+// of sheet types; static assertions enforce this.
+enum class SheetType : uint8_t {
+ Agent, // CSS
+ User, // CSS
+ PresHint,
+ SVGAttrAnimation,
+ Doc, // CSS
+ ScopedDoc,
+ StyleAttr,
+ Override, // CSS
+ Animation,
+ Transition,
+
+ Count,
+ Unknown = 0xff
+};
+
+} // namespace mozilla
+
+#endif // mozilla_SheetType_h
diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp
index 4d4bda7ab1..dcf04abd3d 100644
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -2491,7 +2491,7 @@ BuildStyleRule(nsCSSProperty aProperty,
bool aUseSVGMode)
{
// Set up an empty CSS Declaration
- nsAutoPtr declaration(new css::Declaration());
+ RefPtr declaration(new css::Declaration());
declaration->InitializeEmpty();
bool changed; // ignored, but needed as outparam for ParseProperty
@@ -2510,12 +2510,11 @@ BuildStyleRule(nsCSSProperty aProperty,
// check whether property parsed without CSS parsing errors
if (!declaration->HasNonImportantValueFor(propertyToCheck)) {
- NS_WARNING("failure in BuildStyleRule");
return nullptr;
}
RefPtr rule = new css::StyleRule(nullptr,
- declaration.forget(),
+ declaration,
0, 0);
return rule.forget();
}
@@ -2532,7 +2531,7 @@ LookupStyleContext(dom::Element* aElement)
return nsComputedDOMStyle::GetStyleContextForElement(aElement, nullptr, shell);
}
-bool
+/* static */ bool
StyleAnimationValue::ComputeValue(nsCSSProperty aProperty,
dom::Element* aTargetElement,
const nsAString& aSpecifiedValue,
@@ -2564,6 +2563,59 @@ StyleAnimationValue::ComputeValue(nsCSSProperty aProperty,
return true;
}
+ nsAutoTArray values;
+ bool ok = ComputeValues(aProperty, nsCSSProps::eIgnoreEnabledState,
+ aTargetElement, styleRule, values,
+ aIsContextSensitive);
+ if (!ok) {
+ return false;
+ }
+
+ MOZ_ASSERT(values.Length() == 1);
+ MOZ_ASSERT(values[0].mProperty == aProperty);
+
+ aComputedValue = values[0].mValue;
+ return true;
+}
+
+/* static */ bool
+StyleAnimationValue::ComputeValues(nsCSSProperty aProperty,
+ nsCSSProps::EnabledState aEnabledState,
+ dom::Element* aTargetElement,
+ const nsAString& aSpecifiedValue,
+ bool aUseSVGMode,
+ nsTArray& aResult)
+{
+ MOZ_ASSERT(aTargetElement, "null target element");
+ MOZ_ASSERT(aTargetElement->GetCurrentDoc(),
+ "we should only be able to actively animate nodes that "
+ "are in a document");
+
+ // Parse specified value into a temporary css::StyleRule
+ RefPtr styleRule =
+ BuildStyleRule(aProperty, aTargetElement, aSpecifiedValue, aUseSVGMode);
+ if (!styleRule) {
+ return false;
+ }
+
+ aResult.Clear();
+ return ComputeValues(aProperty, aEnabledState, aTargetElement, styleRule,
+ aResult, /* aIsContextSensitive */ nullptr);
+}
+
+/* static */ bool
+StyleAnimationValue::ComputeValues(
+ nsCSSProperty aProperty,
+ nsCSSProps::EnabledState aEnabledState,
+ dom::Element* aTargetElement,
+ css::StyleRule* aStyleRule,
+ nsTArray& aValues,
+ bool* aIsContextSensitive)
+{
+ if (!nsCSSProps::IsEnabled(aProperty, aEnabledState)) {
+ return false;
+ }
+
// Look up style context for our target element
RefPtr styleContext = LookupStyleContext(aTargetElement);
if (!styleContext) {
@@ -2573,10 +2625,14 @@ StyleAnimationValue::ComputeValue(nsCSSProperty aProperty,
RefPtr tmpStyleContext;
if (aIsContextSensitive) {
+ MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
+ "to correctly set aIsContextSensitive for shorthand properties, "
+ "this code must be adjusted");
+
nsCOMArray ruleArray;
ruleArray.AppendObject(styleSet->InitialStyleRule());
- ruleArray.AppendObject(styleRule);
- styleRule->RuleMatched();
+ ruleArray.AppendObject(aStyleRule);
+ aStyleRule->RuleMatched();
tmpStyleContext =
styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
if (!tmpStyleContext) {
@@ -2587,8 +2643,8 @@ StyleAnimationValue::ComputeValue(nsCSSProperty aProperty,
nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty];
tmpStyleContext->StyleData(sid);
- // If the rule node will have cached style data if the value is not
- // context-sensitive. So if there's nothing cached, it's not context
+ // The rule node will have unconditional cached style data if the value is
+ // not context-sensitive. So if there's nothing cached, it's not context
// sensitive.
*aIsContextSensitive =
!tmpStyleContext->RuleNode()->NodeHasCachedUnconditionalData(sid);
@@ -2602,8 +2658,8 @@ StyleAnimationValue::ComputeValue(nsCSSProperty aProperty,
// value may have been biased by the 'initial' values supplied.
if (!aIsContextSensitive || *aIsContextSensitive) {
nsCOMArray ruleArray;
- ruleArray.AppendObject(styleRule);
- styleRule->RuleMatched();
+ ruleArray.AppendObject(aStyleRule);
+ aStyleRule->RuleMatched();
tmpStyleContext =
styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
if (!tmpStyleContext) {
@@ -2611,8 +2667,27 @@ StyleAnimationValue::ComputeValue(nsCSSProperty aProperty,
}
}
- // Extract computed value of our property from the temporary style rule
- return ExtractComputedValue(aProperty, tmpStyleContext, aComputedValue);
+ // Extract computed value of our property (or all longhand components, if
+ // aProperty is a shorthand) from the temporary style rule
+ if (nsCSSProps::IsShorthand(aProperty)) {
+ CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty, aEnabledState) {
+ if (nsCSSProps::kAnimTypeTable[*p] == eStyleAnimType_None) {
+ // Skip non-animatable component longhands.
+ continue;
+ }
+ PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
+ pair->mProperty = *p;
+ if (!ExtractComputedValue(*p, tmpStyleContext,
+ pair->mValue)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
+ pair->mProperty = aProperty;
+ return ExtractComputedValue(aProperty, tmpStyleContext, pair->mValue);
+ }
}
bool
diff --git a/layout/style/StyleAnimationValue.h b/layout/style/StyleAnimationValue.h
index e2984109b4..46152f52f9 100644
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -10,9 +10,9 @@
#include "nsStringFwd.h"
#include "nsStringBuffer.h"
-#include "nsCSSProperty.h"
#include "nsCoord.h"
#include "nsColor.h"
+#include "nsCSSProps.h"
#include "nsCSSValue.h"
class nsIFrame;
@@ -21,6 +21,10 @@ class gfx3DMatrix;
namespace mozilla {
+namespace css {
+class StyleRule;
+} // namespace css
+
namespace dom {
class Element;
} // namespace dom
@@ -29,6 +33,8 @@ namespace gfx {
class Matrix4x4;
} // namespace gfx
+struct PropertyStyleAnimationValuePair;
+
/**
* Utility class to handle animated style values
*/
@@ -153,6 +159,23 @@ public:
StyleAnimationValue& aComputedValue,
bool* aIsContextSensitive = nullptr);
+ /**
+ * Like ComputeValue, but returns an array of StyleAnimationValues.
+ *
+ * On success, when aProperty is a longhand, aResult will have a single
+ * value in it. When aProperty is a shorthand, aResult will be filled with
+ * values for all of aProperty's longhand components. aEnabledState
+ * is used to filter the longhand components that will be appended
+ * to aResult. On failure, aResult might still have partial results
+ * in it.
+ */
+ static bool ComputeValues(nsCSSProperty aProperty,
+ nsCSSProps::EnabledState aEnabledState,
+ mozilla::dom::Element* aTargetElement,
+ const nsAString& aSpecifiedValue,
+ bool aUseSVGMode,
+ nsTArray& aResult);
+
/**
* Creates a specified value for the given computed value.
*
@@ -373,6 +396,13 @@ public:
{ return !(*this == aOther); }
private:
+ static bool ComputeValues(nsCSSProperty aProperty,
+ nsCSSProps::EnabledState aEnabledState,
+ mozilla::dom::Element* aTargetElement,
+ mozilla::css::StyleRule* aStyleRule,
+ nsTArray& aValues,
+ bool* aIsContextSensitive);
+
void FreeValue();
static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) {
@@ -412,6 +442,12 @@ private:
}
};
+struct PropertyStyleAnimationValuePair
+{
+ nsCSSProperty mProperty;
+ StyleAnimationValue mValue;
+};
+
} // namespace mozilla
#endif
diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp
index e34a897c13..973ceba64e 100644
--- a/layout/style/StyleRule.cpp
+++ b/layout/style/StyleRule.cpp
@@ -1448,7 +1448,6 @@ StyleRule::StyleRule(StyleRule& aCopy,
StyleRule::~StyleRule()
{
delete mSelector;
- delete mDeclaration;
if (mDOMRule) {
mDOMRule->DOMDeclaration()->DropReference();
}
diff --git a/layout/style/StyleRule.h b/layout/style/StyleRule.h
index 6fdffb0775..5ba5c9a201 100644
--- a/layout/style/StyleRule.h
+++ b/layout/style/StyleRule.h
@@ -307,10 +307,7 @@ public:
protected:
virtual ~ImportantRule();
- // Not an owning reference; the StyleRule that owns this
- // ImportantRule also owns the mDeclaration, and any rule node
- // pointing to this rule keeps that StyleRule alive as well.
- Declaration* mDeclaration;
+ RefPtr mDeclaration;
friend class StyleRule;
};
@@ -385,7 +382,7 @@ private:
private:
nsCSSSelectorList* mSelector; // null for style attribute
- Declaration* mDeclaration;
+ RefPtr mDeclaration;
RefPtr mImportantRule; // initialized by RuleMatched
RefPtr mDOMRule;
diff --git a/layout/style/crashtests/1200568-1.html b/layout/style/crashtests/1200568-1.html
new file mode 100644
index 0000000000..e2dc9c09df
--- /dev/null
+++ b/layout/style/crashtests/1200568-1.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/layout/style/crashtests/crashtests.list b/layout/style/crashtests/crashtests.list
index 6e2be3ba3e..0e729eda87 100644
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -114,5 +114,6 @@ pref(dom.webcomponents.enabled,true) load 1089463-1.html
load 1136010-1.html
load 1153693-1.html
load 1167782-1.html
+load 1200568-1.html
load large_border_image_width.html
load border-image-visited-link.html
diff --git a/layout/style/full-screen-override.css b/layout/style/full-screen-override.css
deleted file mode 100644
index 2358f35bb4..0000000000
--- a/layout/style/full-screen-override.css
+++ /dev/null
@@ -1,26 +0,0 @@
-/* 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/. */
-
-
-*|*:-moz-full-screen-ancestor {
- /* Ancestors of a full-screen element should not induce stacking contexts
- that would prevent the full-screen element from being on top. */
- z-index: initial !important;
- /* Ancestors of a full-screen element should not be partially transparent,
- since that would apply to the full-screen element and make the page visible
- behind it. It would also create a pseudo-stacking-context that would let content
- draw on top of the full-screen element. */
- opacity: initial !important;
- /* Ancestors of a full-screen element should not apply SVG masking, clipping, or
- filtering, since that would affect the full-screen element and create a pseudo-
- stacking context. */
- mask: initial !important;
- clip-path: initial !important;
- filter: initial !important;
- clip: initial !important;
- transform: initial !important;
- transform-style: initial !important;
- /* FIXME: do we need to worry about 'overflow'? */
- will-change: initial !important;
-}
diff --git a/layout/style/html.css b/layout/style/html.css
index 9c0819f0b1..931ba6a6eb 100644
--- a/layout/style/html.css
+++ b/layout/style/html.css
@@ -831,7 +831,12 @@ marquee[direction="up"], marquee[direction="down"] {
white-space: nowrap;
font-size: 50%;
line-height: 1;
+%ifndef XP_WIN
+ /* The widely-used Windows font Meiryo doesn't work fine with this
+ * setting, so disable this on Windows. We should re-enable it once
+ * Microsoft fixes this issue. See bug 1164279. */
font-variant-east-asian: ruby;
+%endif
}
@supports (text-emphasis: none) {
rtc, rt {
diff --git a/layout/style/jar.mn b/layout/style/jar.mn
index 531d0375f0..7bc7b4b8aa 100644
--- a/layout/style/jar.mn
+++ b/layout/style/jar.mn
@@ -4,9 +4,8 @@
toolkit.jar:
* res/ua.css (ua.css)
- res/html.css (html.css)
+* res/html.css (html.css)
res/quirk.css (quirk.css)
- res/full-screen-override.css (full-screen-override.css)
res/plaintext.css (plaintext.css)
res/viewsource.css (viewsource.css)
res/counterstyles.css (counterstyles.css)
diff --git a/layout/style/moz.build b/layout/style/moz.build
index 7702dd4903..2833d04701 100644
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -88,6 +88,7 @@ EXPORTS.mozilla += [
'LayerAnimationInfo.h',
'RuleNodeCacheConditions.h',
'RuleProcessorCache.h',
+ 'SheetType.h',
'StyleAnimationValue.h',
]
diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp
index 8fff0e4c34..d76e5d3b83 100644
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -244,11 +244,13 @@ CSSAnimation::QueueEvents()
// First notifying for start of 0th iteration by appending an
// 'animationstart':
StickyTimeDuration elapsedTime =
- std::min(StickyTimeDuration(mEffect->InitialAdvance()),
+ std::min(StickyTimeDuration(InitialAdvance()),
computedTiming.mActiveDuration);
- manager->QueueEvent(
- AnimationEventInfo(owningElement, mAnimationName, eAnimationStart,
- elapsedTime, owningPseudoType));
+ manager->QueueEvent(AnimationEventInfo(owningElement, owningPseudoType,
+ eAnimationStart, mAnimationName,
+ elapsedTime,
+ ElapsedTimeToTimeStamp(elapsedTime),
+ this));
// Then have the shared code below append an 'animationend':
message = eAnimationEnd;
} else {
@@ -261,15 +263,16 @@ CSSAnimation::QueueEvents()
TimeDuration iterationStart = mEffect->Timing().mIterationDuration *
computedTiming.mCurrentIteration;
elapsedTime = StickyTimeDuration(std::max(iterationStart,
- mEffect->InitialAdvance()));
+ InitialAdvance()));
} else {
MOZ_ASSERT(message == eAnimationEnd);
elapsedTime = computedTiming.mActiveDuration;
}
- manager->QueueEvent(
- AnimationEventInfo(owningElement, mAnimationName, message, elapsedTime,
- owningPseudoType));
+ manager->QueueEvent(AnimationEventInfo(owningElement, owningPseudoType,
+ message, mAnimationName, elapsedTime,
+ ElapsedTimeToTimeStamp(elapsedTime),
+ this));
}
bool
@@ -310,6 +313,30 @@ CSSAnimation::UpdateTiming(SeekFlag aSeekFlag, SyncNotifyFlag aSyncNotifyFlag)
Animation::UpdateTiming(aSeekFlag, aSyncNotifyFlag);
}
+TimeStamp
+CSSAnimation::ElapsedTimeToTimeStamp(const StickyTimeDuration&
+ aElapsedTime) const
+{
+ // Initializes to null. We always return this object to benefit from
+ // return-value-optimization.
+ TimeStamp result;
+
+ // Currently we may dispatch animationstart events before resolving
+ // mStartTime if we have a delay <= 0. This will change in bug 1134163
+ // but until then we should just use the latest refresh driver time as
+ // the event timestamp in that case.
+ if (!mEffect || mStartTime.IsNull()) {
+ nsPresContext* presContext = GetPresContext();
+ if (presContext) {
+ result = presContext->RefreshDriver()->MostRecentRefresh();
+ }
+ return result;
+ }
+
+ result = AnimationTimeToTimeStamp(aElapsedTime + mEffect->Timing().mDelay);
+ return result;
+}
+
////////////////////////// nsAnimationManager ////////////////////////////
NS_IMPL_CYCLE_COLLECTION(nsAnimationManager, mEventDispatcher)
@@ -366,8 +393,9 @@ nsIStyleRule*
nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
mozilla::dom::Element* aElement)
{
- if (!mPresContext->IsDynamic()) {
- // For print or print preview, ignore animations.
+ // Ignore animations for print or print preview, and for elements
+ // that are not attached to the document tree.
+ if (!mPresContext->IsDynamic() || !aElement->IsInComposedDoc()) {
return nullptr;
}
@@ -465,7 +493,7 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
animationChanged =
oldEffect->Timing() != newEffect->Timing() ||
oldEffect->Properties() != newEffect->Properties();
- oldEffect->SetTiming(newEffect->Timing(), *oldAnim);
+ oldEffect->SetTiming(newEffect->Timing());
oldEffect->Properties() = newEffect->Properties();
}
diff --git a/layout/style/nsAnimationManager.h b/layout/style/nsAnimationManager.h
index 9c608bafd6..131d405394 100644
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -26,15 +26,22 @@ class Promise;
} /* namespace dom */
struct AnimationEventInfo {
- RefPtr mElement;
- mozilla::InternalAnimationEvent mEvent;
+ RefPtr mElement;
+ RefPtr mAnimation;
+ InternalAnimationEvent mEvent;
+ TimeStamp mTimeStamp;
- AnimationEventInfo(mozilla::dom::Element *aElement,
- const nsSubstring& aAnimationName,
+ AnimationEventInfo(dom::Element* aElement,
+ nsCSSPseudoElements::Type aPseudoType,
EventMessage aMessage,
- const mozilla::StickyTimeDuration& aElapsedTime,
- nsCSSPseudoElements::Type aPseudoType)
- : mElement(aElement), mEvent(true, aMessage)
+ const nsSubstring& aAnimationName,
+ const StickyTimeDuration& aElapsedTime,
+ const TimeStamp& aTimeStamp,
+ dom::Animation* aAnimation)
+ : mElement(aElement)
+ , mAnimation(aAnimation)
+ , mEvent(true, aMessage)
+ , mTimeStamp(aTimeStamp)
{
// XXX Looks like nobody initialize WidgetEvent::time
mEvent.animationName = aAnimationName;
@@ -44,9 +51,11 @@ struct AnimationEventInfo {
// InternalAnimationEvent doesn't support copy-construction, so we need
// to ourselves in order to work with nsTArray
- AnimationEventInfo(const AnimationEventInfo &aOther)
+ AnimationEventInfo(const AnimationEventInfo& aOther)
: mElement(aOther.mElement)
+ , mAnimation(aOther.mAnimation)
, mEvent(true, aOther.mEvent.mMessage)
+ , mTimeStamp(aOther.mTimeStamp)
{
mEvent.AssignAnimationEventData(aOther.mEvent, false);
}
@@ -165,6 +174,21 @@ protected:
void UpdateTiming(SeekFlag aSeekFlag,
SyncNotifyFlag aSyncNotifyFlag) override;
+ // Returns the duration from the start of the animation's source effect's
+ // active interval to the point where the animation actually begins playback.
+ // This is zero unless the animation's source effect has a negative delay in
+ // which // case it is the absolute value of that delay.
+ // This is used for setting the elapsedTime member of CSS AnimationEvents.
+ TimeDuration InitialAdvance() const {
+ return mEffect ?
+ std::max(TimeDuration(), mEffect->Timing().mDelay * -1) :
+ TimeDuration();
+ }
+ // Converts an AnimationEvent's elapsedTime value to an equivalent TimeStamp
+ // that can be used to sort events by when they occurred.
+ TimeStamp ElapsedTimeToTimeStamp(const StickyTimeDuration& aElapsedTime)
+ const;
+
nsString mAnimationName;
// The (pseudo-)element whose computed animation-name refers to this
@@ -306,6 +330,7 @@ public:
* contexts are created.
*/
void DispatchEvents() { mEventDispatcher.DispatchEvents(mPresContext); }
+ void SortEvents() { mEventDispatcher.SortEvents(); }
void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
// Stop animations on the element. This method takes the real element
diff --git a/layout/style/nsCSSDataBlock.cpp b/layout/style/nsCSSDataBlock.cpp
index 9d63be15fc..8655d8f497 100644
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -40,8 +40,8 @@ MoveValue(nsCSSValue* aSource, nsCSSValue* aDest)
static bool
ShouldIgnoreColors(nsRuleData *aRuleData)
{
- return aRuleData->mLevel != nsStyleSet::eAgentSheet &&
- aRuleData->mLevel != nsStyleSet::eUserSheet &&
+ return aRuleData->mLevel != SheetType::Agent &&
+ aRuleData->mLevel != SheetType::User &&
!aRuleData->mPresContext->UseDocumentColors();
}
@@ -260,6 +260,15 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
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);
}
}
diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp
index 52c8cb38bd..b89f3b9787 100644
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -57,11 +57,13 @@ typedef nsCSSProps::KTableValue KTableValue;
// pref-backed bool values (hooked up in nsCSSParser::Startup)
static bool sOpentypeSVGEnabled;
+static bool sWebkitPrefixedAliasesEnabled;
static bool sUnprefixingServiceEnabled;
#ifdef NIGHTLY_BUILD
static bool sUnprefixingServiceGloballyWhitelisted;
#endif
static bool sMozGradientsEnabled;
+static bool sControlCharVisibility;
const uint32_t
nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
@@ -129,7 +131,8 @@ public:
nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal,
uint32_t aLineNumber,
- bool aAllowUnsafeRules);
+ bool aAllowUnsafeRules,
+ LoaderReusableStyleSheets* aReusableSheets);
nsresult ParseStyleAttribute(const nsAString& aAttributeValue,
nsIURI* aDocURL,
@@ -159,6 +162,12 @@ public:
bool* aChanged,
bool aIsImportant,
bool aIsSVGMode);
+ void ParseLonghandProperty(const nsCSSProperty aPropID,
+ const nsAString& aPropValue,
+ nsIURI* aSheetURL,
+ nsIURI* aBaseURL,
+ nsIPrincipal* aSheetPrincipal,
+ nsCSSValue& aValue);
void ParseMediaList(const nsSubstring& aBuffer,
nsIURI* aURL, // for error reporting
@@ -321,6 +330,9 @@ public:
if (mUnsafeRulesEnabled) {
enabledState |= nsCSSProps::eEnabledInUASheets;
}
+ if (mIsChrome) {
+ enabledState |= nsCSSProps::eEnabledInChrome;
+ }
return enabledState;
}
@@ -537,6 +549,15 @@ protected:
bool GetToken(bool aSkipWS);
void UngetToken();
bool GetNextTokenLocation(bool aSkipWS, uint32_t *linenum, uint32_t *colnum);
+ void AssertNextTokenAt(uint32_t aLine, uint32_t aCol)
+ {
+ // Beware that this method will call GetToken/UngetToken (in
+ // GetNextTokenLocation) in DEBUG builds, but not in non-DEBUG builds.
+ DebugOnly lineAfter, colAfter;
+ MOZ_ASSERT(GetNextTokenLocation(true, &lineAfter, &colAfter) &&
+ lineAfter == aLine && colAfter == aCol,
+ "shouldn't have consumed any tokens");
+ }
bool ExpectSymbol(char16_t aSymbol, bool aSkipWS);
bool ExpectEndProperty();
@@ -717,8 +738,9 @@ protected:
eCSSContext_Page
};
- css::Declaration* ParseDeclarationBlock(uint32_t aFlags,
- nsCSSContextType aContext = eCSSContext_General);
+ already_AddRefed
+ ParseDeclarationBlock(uint32_t aFlags,
+ nsCSSContextType aContext = eCSSContext_General);
bool ParseDeclaration(css::Declaration* aDeclaration,
uint32_t aFlags,
bool aMustCallValueAppended,
@@ -732,23 +754,26 @@ protected:
nsCSSKeyword LookupKeywordPrefixAware(nsAString& aKeywordStr,
const KTableValue aKeywordTable[]);
- bool ShouldUseUnprefixingService();
+ bool ShouldUseUnprefixingService() const;
bool ParsePropertyWithUnprefixingService(const nsAString& aPropertyName,
css::Declaration* aDeclaration,
uint32_t aFlags,
bool aMustCallValueAppended,
bool* aChanged,
nsCSSContextType aContext);
- // When we detect a webkit-prefixed gradient expression, this function can
- // be used to parse its body into outparam |aValue|. Only call if
- // ShouldUseUnprefixingService() returns true.
- bool ParseWebkitPrefixedGradient(nsAString& aPrefixedFuncName,
- nsCSSValue& aValue);
+ // When we detect a webkit-prefixed gradient expression, this function can be
+ // used to parse its body into outparam |aValue|, with the help of the
+ // CSSUnprefixingService.
+ // Only call if ShouldUseUnprefixingService() returns true.
+ bool ParseWebkitPrefixedGradientWithService(nsAString& aPrefixedFuncName,
+ nsCSSValue& aValue);
bool ParseProperty(nsCSSProperty aPropID);
bool ParsePropertyByFunction(nsCSSProperty aPropID);
- bool ParseSingleValueProperty(nsCSSValue& aValue,
- nsCSSProperty aPropID);
+ CSSParseResult ParseSingleValueProperty(nsCSSValue& aValue,
+ nsCSSProperty aPropID);
+ bool ParseSingleValuePropertyByFunction(nsCSSValue& aValue,
+ nsCSSProperty aPropID);
// These are similar to ParseSingleValueProperty but only work for
// properties that are parsed with ParseBoxProperties or
@@ -799,6 +824,7 @@ protected:
mPosition(aPosition), mSize(aSize) {};
};
+ bool IsFunctionTokenValidForBackgroundImage(const nsCSSToken& aToken) const;
bool ParseBackgroundItem(BackgroundParseState& aState);
bool ParseValueList(nsCSSProperty aPropID); // a single value prop-id
@@ -866,7 +892,7 @@ protected:
CSSParseResult ParseGridLineNames(nsCSSValue& aValue);
bool ParseGridLineNameListRepeat(nsCSSValueList** aTailPtr);
bool ParseOptionalLineNameListAfterSubgrid(nsCSSValue& aValue);
- bool ParseGridTrackBreadth(nsCSSValue& aValue);
+ CSSParseResult ParseGridTrackBreadth(nsCSSValue& aValue);
CSSParseResult ParseGridTrackSize(nsCSSValue& aValue);
bool ParseGridAutoColumnsRows(nsCSSProperty aPropID);
bool ParseGridTrackListRepeat(nsCSSValueList** aTailPtr);
@@ -1047,7 +1073,7 @@ protected:
int32_t ParseChoice(nsCSSValue aValues[],
const nsCSSProperty aPropIDs[], int32_t aNumIDs);
- bool ParseColor(nsCSSValue& aValue);
+ CSSParseResult ParseColor(nsCSSValue& aValue);
bool ParseNumberColorComponent(uint8_t& aComponent, char aStop);
bool ParsePercentageColorComponent(float& aComponent, char aStop);
// ParseHSLColor parses everything starting with the opening '('
@@ -1060,23 +1086,21 @@ protected:
bool ParseColorOpacity(float& aOpacity);
bool ParseEnum(nsCSSValue& aValue,
const KTableValue aKeywordTable[]);
- bool ParseVariant(nsCSSValue& aValue,
- int32_t aVariantMask,
- const KTableValue aKeywordTable[]);
- bool ParseVariantWithRestrictions(nsCSSValue& aValue,
- int32_t aVariantMask,
- const KTableValue aKeywordTable[],
- uint32_t aRestrictions);
- bool ParseNonNegativeVariant(nsCSSValue& aValue,
- int32_t aVariantMask,
- const KTableValue aKeywordTable[]);
- bool ParseOneOrLargerVariant(nsCSSValue& aValue,
- int32_t aVariantMask,
- const KTableValue aKeywordTable[]);
- bool ParseNonNegativeInteger(nsCSSValue& aValue)
- {
- return ParseNonNegativeVariant(aValue, VARIANT_INTEGER, nullptr);
- }
+
+ // Variant parsing methods
+ CSSParseResult ParseVariant(nsCSSValue& aValue,
+ int32_t aVariantMask,
+ const KTableValue aKeywordTable[]);
+ CSSParseResult ParseVariantWithRestrictions(nsCSSValue& aValue,
+ int32_t aVariantMask,
+ const KTableValue aKeywordTable[],
+ uint32_t aRestrictions);
+ CSSParseResult ParseNonNegativeVariant(nsCSSValue& aValue,
+ int32_t aVariantMask,
+ const KTableValue aKeywordTable[]);
+ CSSParseResult ParseOneOrLargerVariant(nsCSSValue& aValue,
+ int32_t aVariantMask,
+ const KTableValue aKeywordTable[]);
// Variant parsing methods that are guaranteed to UngetToken any token
// consumed on failure
@@ -1086,10 +1110,59 @@ protected:
{
MOZ_ASSERT(!(aVariantMask & VARIANT_MULTIPLE_TOKENS),
"use ParseVariant for variants in VARIANT_MULTIPLE_TOKENS");
- CSSParseResult result = (CSSParseResult)ParseVariant(aValue, aVariantMask, aKeywordTable);
+ CSSParseResult result = ParseVariant(aValue, aVariantMask, aKeywordTable);
MOZ_ASSERT(result != CSSParseResult::Error);
return result == CSSParseResult::Ok;
}
+ bool ParseSingleTokenVariantWithRestrictions(
+ nsCSSValue& aValue,
+ int32_t aVariantMask,
+ const KTableValue aKeywordTable[],
+ uint32_t aRestrictions)
+ {
+ MOZ_ASSERT(!(aVariantMask & VARIANT_MULTIPLE_TOKENS),
+ "use ParseVariantWithRestrictions for variants in "
+ "VARIANT_MULTIPLE_TOKENS");
+ CSSParseResult result =
+ ParseVariantWithRestrictions(aValue, aVariantMask, aKeywordTable,
+ aRestrictions);
+ MOZ_ASSERT(result != CSSParseResult::Error);
+ return result == CSSParseResult::Ok;
+ }
+ bool ParseSingleTokenNonNegativeVariant(nsCSSValue& aValue,
+ int32_t aVariantMask,
+ const KTableValue aKeywordTable[])
+ {
+ MOZ_ASSERT(!(aVariantMask & VARIANT_MULTIPLE_TOKENS),
+ "use ParseNonNegativeVariant for variants in "
+ "VARIANT_MULTIPLE_TOKENS");
+ CSSParseResult result =
+ ParseNonNegativeVariant(aValue, aVariantMask, aKeywordTable);
+ MOZ_ASSERT(result != CSSParseResult::Error);
+ return result == CSSParseResult::Ok;
+ }
+ bool ParseSingleTokenOneOrLargerVariant(nsCSSValue& aValue,
+ int32_t aVariantMask,
+ const KTableValue aKeywordTable[])
+ {
+ MOZ_ASSERT(!(aVariantMask & VARIANT_MULTIPLE_TOKENS),
+ "use ParseOneOrLargerVariant for variants in "
+ "VARIANT_MULTIPLE_TOKENS");
+ CSSParseResult result =
+ ParseOneOrLargerVariant(aValue, aVariantMask, aKeywordTable);
+ MOZ_ASSERT(result != CSSParseResult::Error);
+ return result == CSSParseResult::Ok;
+ }
+
+ // Helpers for some common ParseSingleTokenNonNegativeVariant calls.
+ bool ParseNonNegativeInteger(nsCSSValue& aValue)
+ {
+ return ParseSingleTokenNonNegativeVariant(aValue, VARIANT_INTEGER, nullptr);
+ }
+ bool ParseNonNegativeNumber(nsCSSValue& aValue)
+ {
+ return ParseSingleTokenNonNegativeVariant(aValue, VARIANT_NUMBER, nullptr);
+ }
// http://dev.w3.org/csswg/css-values/#custom-idents
// Parse an identifier that is none of:
@@ -1118,10 +1191,17 @@ protected:
bool ParseImageRect(nsCSSValue& aImage);
bool ParseElement(nsCSSValue& aValue);
bool ParseColorStop(nsCSSValueGradient* aGradient);
- bool ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating,
- bool aIsLegacy);
- bool ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating,
- bool aIsLegacy);
+
+ enum GradientParsingFlags {
+ eGradient_Repeating = 1 << 0, // repeating-{linear|radial}-gradient
+ eGradient_MozLegacy = 1 << 1, // -moz-{linear|radial}-gradient
+ eGradient_WebkitLegacy = 1 << 2, // -webkit-{linear|radial}-gradient
+
+ // Mask to catch both "legacy" flags:
+ eGradient_AnyLegacy = eGradient_MozLegacy | eGradient_WebkitLegacy
+ };
+ bool ParseLinearGradient(nsCSSValue& aValue, uint8_t aFlags);
+ bool ParseRadialGradient(nsCSSValue& aValue, uint8_t aFlags);
bool IsLegacyGradientLine(const nsCSSTokenType& aType,
const nsString& aId);
bool ParseGradientColorStops(nsCSSValueGradient* aGradient,
@@ -1192,6 +1272,9 @@ protected:
// Used for @import rules
mozilla::css::Loader* mChildLoader; // not ref counted, it owns us
+ // Any sheets we may reuse when parsing an @import.
+ LoaderReusableStyleSheets* mReusableSheets;
+
// Sheet section we're in. This is used to enforce correct ordering of the
// various rule types (eg the fact that a @charset rule must come before
// anything else). Note that there are checks of similar things in various
@@ -1222,6 +1305,9 @@ protected:
// True if unsafe rules should be allowed
bool mUnsafeRulesEnabled : 1;
+ // True if we are in parsing rules for the chrome.
+ bool mIsChrome : 1;
+
// True if viewport units should be allowed.
bool mViewportUnitsEnabled : 1;
@@ -1337,6 +1423,7 @@ CSSParserImpl::CSSParserImpl()
mScanner(nullptr),
mReporter(nullptr),
mChildLoader(nullptr),
+ mReusableSheets(nullptr),
mSection(eCSSSection_Charset),
mNameSpaceMap(nullptr),
mHavePushBack(false),
@@ -1344,6 +1431,7 @@ CSSParserImpl::CSSParserImpl()
mHashlessColorQuirk(false),
mUnitlessLengthQuirk(false),
mUnsafeRulesEnabled(false),
+ mIsChrome(false),
mViewportUnitsEnabled(true),
mHTMLMediaMode(false),
mParsingCompoundProperty(false),
@@ -1449,7 +1537,8 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal,
uint32_t aLineNumber,
- bool aAllowUnsafeRules)
+ bool aAllowUnsafeRules,
+ LoaderReusableStyleSheets* aReusableSheets)
{
NS_PRECONDITION(aSheetPrincipal, "Must have principal here!");
NS_PRECONDITION(aBaseURI, "need base URI");
@@ -1495,6 +1584,8 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
}
mUnsafeRulesEnabled = aAllowUnsafeRules;
+ mIsChrome = nsContentUtils::IsSystemPrincipal(aSheetPrincipal);
+ mReusableSheets = aReusableSheets;
nsCSSToken* tk = &mToken;
for (;;) {
@@ -1518,6 +1609,8 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
ReleaseScanner();
mUnsafeRulesEnabled = false;
+ mIsChrome = false;
+ mReusableSheets = nullptr;
// XXX check for low level errors
return NS_OK;
@@ -1555,7 +1648,7 @@ CSSParserImpl::ParseStyleAttribute(const nsAString& aAttributeValue,
uint32_t parseFlags = eParseDeclaration_AllowImportant;
- css::Declaration* declaration = ParseDeclarationBlock(parseFlags);
+ RefPtr declaration = ParseDeclarationBlock(parseFlags);
if (declaration) {
// Create a style rule for the declaration
NS_ADDREF(*aResult = new css::StyleRule(nullptr, declaration, 0, 0));
@@ -1663,6 +1756,33 @@ CSSParserImpl::ParseRule(const nsAString& aRule,
return rv;
}
+void
+CSSParserImpl::ParseLonghandProperty(const nsCSSProperty aPropID,
+ const nsAString& aPropValue,
+ nsIURI* aSheetURL,
+ nsIURI* aBaseURL,
+ nsIPrincipal* aSheetPrincipal,
+ nsCSSValue& aValue)
+{
+ MOZ_ASSERT(aPropID < eCSSProperty_COUNT_no_shorthands,
+ "ParseLonghandProperty must only take a longhand property");
+
+ RefPtr declaration = new Declaration;
+ declaration->InitializeEmpty();
+
+ bool changed;
+ ParseProperty(aPropID, aPropValue, aSheetURL, aBaseURL, aSheetPrincipal,
+ declaration, &changed,
+ /* aIsImportant */ false,
+ /* aIsSVGMode */ false);
+
+ if (changed) {
+ aValue = *declaration->GetNormalBlock()->ValueFor(aPropID);
+ } else {
+ aValue.Reset();
+ }
+}
+
void
CSSParserImpl::ParseProperty(const nsCSSProperty aPropID,
const nsAString& aPropValue,
@@ -1693,10 +1813,7 @@ CSSParserImpl::ParseProperty(const nsCSSProperty aPropID,
// Check for unknown or preffed off properties
if (eCSSProperty_UNKNOWN == aPropID ||
- !(nsCSSProps::IsEnabled(aPropID) ||
- (mUnsafeRulesEnabled &&
- nsCSSProps::PropHasFlags(aPropID,
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS)))) {
+ !nsCSSProps::IsEnabled(aPropID, PropertyEnabledState())) {
NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue(aPropID));
REPORT_UNEXPECTED_P(PEUnknownProperty, propName);
REPORT_UNEXPECTED(PEDeclDropped);
@@ -1888,7 +2005,8 @@ CSSParserImpl::ParseSourceSizeList(const nsAString& aBuffer,
query->SetNegated();
}
- if (!ParseNonNegativeVariant(value, VARIANT_LPCALC, nullptr)) {
+ if (ParseNonNegativeVariant(value, VARIANT_LPCALC, nullptr) !=
+ CSSParseResult::Ok) {
hitError = true;
break;
}
@@ -1937,7 +2055,8 @@ CSSParserImpl::ParseColorString(const nsSubstring& aBuffer,
nsAutoSuppressErrors suppressErrors(this, aSuppressErrors);
// Parse a color, and check that there's nothing else after it.
- bool colorParsed = ParseColor(aValue) && !GetToken(true);
+ bool colorParsed = ParseColor(aValue) == CSSParseResult::Ok &&
+ !GetToken(true);
if (aSuppressErrors) {
CLEAR_ERROR();
@@ -3000,7 +3119,8 @@ CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc,
parseFunc = &CSSParserImpl::ParsePageRule;
newSection = eCSSSection_General;
- } else if ((nsCSSProps::IsEnabled(eCSSPropertyAlias_MozAnimation) &&
+ } else if ((nsCSSProps::IsEnabled(eCSSPropertyAlias_MozAnimation,
+ PropertyEnabledState()) &&
mToken.mIdent.LowerCaseEqualsLiteral("-moz-keyframes")) ||
mToken.mIdent.LowerCaseEqualsLiteral("keyframes")) {
parseFunc = &CSSParserImpl::ParseKeyframesRule;
@@ -3330,11 +3450,12 @@ CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery)
bool rv = false;
switch (feature->mValueType) {
case nsMediaFeature::eLength:
- rv = ParseNonNegativeVariant(expr->mValue, VARIANT_LENGTH, nullptr);
+ rv = ParseSingleTokenNonNegativeVariant(expr->mValue, VARIANT_LENGTH,
+ nullptr);
break;
case nsMediaFeature::eInteger:
case nsMediaFeature::eBoolInteger:
- rv = ParseNonNegativeVariant(expr->mValue, VARIANT_INTEGER, nullptr);
+ rv = ParseNonNegativeInteger(expr->mValue);
// Enforce extra restrictions for eBoolInteger
if (rv &&
feature->mValueType == nsMediaFeature::eBoolInteger &&
@@ -3342,7 +3463,7 @@ CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery)
rv = false;
break;
case nsMediaFeature::eFloat:
- rv = ParseNonNegativeVariant(expr->mValue, VARIANT_NUMBER, nullptr);
+ rv = ParseNonNegativeNumber(expr->mValue);
break;
case nsMediaFeature::eIntRatio:
{
@@ -3353,10 +3474,10 @@ CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery)
// We don't bother with ParseNonNegativeVariant since we have to
// check for != 0 as well; no need to worry about the UngetToken
// since we're throwing out up to the next ')' anyway.
- rv = ParseVariant(a->Item(0), VARIANT_INTEGER, nullptr) &&
+ rv = ParseSingleTokenVariant(a->Item(0), VARIANT_INTEGER, nullptr) &&
a->Item(0).GetIntValue() > 0 &&
ExpectSymbol('/', true) &&
- ParseVariant(a->Item(1), VARIANT_INTEGER, nullptr) &&
+ ParseSingleTokenVariant(a->Item(1), VARIANT_INTEGER, nullptr) &&
a->Item(1).GetIntValue() > 0;
}
break;
@@ -3383,11 +3504,11 @@ CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery)
}
break;
case nsMediaFeature::eEnumerated:
- rv = ParseVariant(expr->mValue, VARIANT_KEYWORD,
- feature->mData.mKeywordTable);
+ rv = ParseSingleTokenVariant(expr->mValue, VARIANT_KEYWORD,
+ feature->mData.mKeywordTable);
break;
case nsMediaFeature::eIdent:
- rv = ParseVariant(expr->mValue, VARIANT_IDENTIFIER, nullptr);
+ rv = ParseSingleTokenVariant(expr->mValue, VARIANT_IDENTIFIER, nullptr);
break;
}
if (!rv || !ExpectSymbol(')', true)) {
@@ -3458,7 +3579,7 @@ CSSParserImpl::ProcessImport(const nsString& aURLSpec,
}
if (mChildLoader) {
- mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule);
+ mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule, mReusableSheets);
}
}
@@ -3950,7 +4071,7 @@ CSSParserImpl::ParseFontFeatureValueSet(nsCSSFontFeatureValuesRule
nsAutoTArray featureSelectors;
nsCSSValue intValue;
- while (ParseNonNegativeVariant(intValue, VARIANT_INTEGER, nullptr)) {
+ while (ParseNonNegativeInteger(intValue)) {
featureSelectors.AppendElement(uint32_t(intValue.GetIntValue()));
}
@@ -4058,18 +4179,16 @@ CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc, void* aData)
MOZ_ASSERT(mViewportUnitsEnabled,
"Viewport units should be enabled outside of @page rules.");
mViewportUnitsEnabled = false;
- nsAutoPtr declaration(
- ParseDeclarationBlock(parseFlags,
- eCSSContext_Page));
+ RefPtr declaration =
+ ParseDeclarationBlock(parseFlags, eCSSContext_Page);
mViewportUnitsEnabled = true;
if (!declaration) {
return false;
}
- // Takes ownership of declaration.
- RefPtr rule = new nsCSSPageRule(Move(declaration),
- linenum, colnum);
+ RefPtr rule =
+ new nsCSSPageRule(declaration, linenum, colnum);
(*aAppendFunc)(rule, aData);
return true;
@@ -4088,14 +4207,14 @@ CSSParserImpl::ParseKeyframeRule()
// Ignore !important in keyframe rules
uint32_t parseFlags = eParseDeclaration_InBraces;
- nsAutoPtr declaration(ParseDeclarationBlock(parseFlags));
+ RefPtr declaration(ParseDeclarationBlock(parseFlags));
if (!declaration) {
return nullptr;
}
// Takes ownership of declaration, and steals contents of selectorList.
RefPtr rule =
- new nsCSSKeyframeRule(selectorList, Move(declaration), linenum, colnum);
+ new nsCSSKeyframeRule(selectorList, declaration, linenum, colnum);
return rule.forget();
}
@@ -4625,7 +4744,7 @@ CSSParserImpl::ParseCounterDescriptorValue(nsCSSCounterDesc aDescID,
switch (system.GetIntValue()) {
case NS_STYLE_COUNTER_SYSTEM_FIXED: {
nsCSSValue start;
- if (!ParseVariant(start, VARIANT_INTEGER, nullptr)) {
+ if (!ParseSingleTokenVariant(start, VARIANT_INTEGER, nullptr)) {
start.SetIntValue(1, eCSSUnit_Integer);
}
aValue.SetPairValue(system, start);
@@ -4648,10 +4767,10 @@ CSSParserImpl::ParseCounterDescriptorValue(nsCSSCounterDesc aDescID,
case eCSSCounterDesc_Negative: {
nsCSSValue first, second;
- if (!ParseVariant(first, VARIANT_COUNTER_SYMBOL, nullptr)) {
+ if (!ParseSingleTokenVariant(first, VARIANT_COUNTER_SYMBOL, nullptr)) {
return false;
}
- if (!ParseVariant(second, VARIANT_COUNTER_SYMBOL, nullptr)) {
+ if (!ParseSingleTokenVariant(second, VARIANT_COUNTER_SYMBOL, nullptr)) {
aValue = first;
} else {
aValue.SetPairValue(first, second);
@@ -4661,10 +4780,10 @@ CSSParserImpl::ParseCounterDescriptorValue(nsCSSCounterDesc aDescID,
case eCSSCounterDesc_Prefix:
case eCSSCounterDesc_Suffix:
- return ParseVariant(aValue, VARIANT_COUNTER_SYMBOL, nullptr);
+ return ParseSingleTokenVariant(aValue, VARIANT_COUNTER_SYMBOL, nullptr);
case eCSSCounterDesc_Range: {
- if (ParseVariant(aValue, VARIANT_AUTO, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_AUTO, nullptr)) {
return true;
}
nsCSSValuePairList* item = aValue.SetPairListValue();
@@ -4687,7 +4806,7 @@ CSSParserImpl::ParseCounterDescriptorValue(nsCSSCounterDesc aDescID,
case eCSSCounterDesc_Pad: {
nsCSSValue width, symbol;
bool hasWidth = ParseNonNegativeInteger(width);
- if (!ParseVariant(symbol, VARIANT_COUNTER_SYMBOL, nullptr) ||
+ if (!ParseSingleTokenVariant(symbol, VARIANT_COUNTER_SYMBOL, nullptr) ||
(!hasWidth && !ParseNonNegativeInteger(width))) {
return false;
}
@@ -4702,7 +4821,7 @@ CSSParserImpl::ParseCounterDescriptorValue(nsCSSCounterDesc aDescID,
nsCSSValueList* item = nullptr;
for (;;) {
nsCSSValue value;
- if (!ParseVariant(value, VARIANT_COUNTER_SYMBOL, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_COUNTER_SYMBOL, nullptr)) {
return !!item;
}
if (!item) {
@@ -4722,7 +4841,7 @@ CSSParserImpl::ParseCounterDescriptorValue(nsCSSCounterDesc aDescID,
for (;;) {
nsCSSValue weight, symbol;
bool hasWeight = ParseNonNegativeInteger(weight);
- if (!ParseVariant(symbol, VARIANT_COUNTER_SYMBOL, nullptr) ||
+ if (!ParseSingleTokenVariant(symbol, VARIANT_COUNTER_SYMBOL, nullptr) ||
(!hasWeight && !ParseNonNegativeInteger(weight))) {
return false;
}
@@ -4747,8 +4866,8 @@ CSSParserImpl::ParseCounterDescriptorValue(nsCSSCounterDesc aDescID,
}
case eCSSCounterDesc_SpeakAs:
- if (ParseVariant(aValue, VARIANT_AUTO | VARIANT_KEYWORD,
- nsCSSProps::kCounterSpeakAsKTable)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_AUTO | VARIANT_KEYWORD,
+ nsCSSProps::kCounterSpeakAsKTable)) {
if (aValue.GetUnit() == eCSSUnit_Enumerated &&
aValue.GetIntValue() == NS_STYLE_COUNTER_SPEAKAS_SPELL_OUT) {
// Currently spell-out is not supported, so it is explicitly
@@ -4771,8 +4890,10 @@ CSSParserImpl::ParseCounterRange(nsCSSValuePair& aPair)
{
static const int32_t VARIANT_BOUND = VARIANT_INTEGER | VARIANT_KEYWORD;
nsCSSValue lower, upper;
- if (!ParseVariant(lower, VARIANT_BOUND, nsCSSProps::kCounterRangeKTable) ||
- !ParseVariant(upper, VARIANT_BOUND, nsCSSProps::kCounterRangeKTable)) {
+ if (!ParseSingleTokenVariant(lower, VARIANT_BOUND,
+ nsCSSProps::kCounterRangeKTable) ||
+ !ParseSingleTokenVariant(upper, VARIANT_BOUND,
+ nsCSSProps::kCounterRangeKTable)) {
return false;
}
if (lower.GetUnit() != eCSSUnit_Enumerated &&
@@ -5011,7 +5132,7 @@ CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData,
// Next parse the declaration block
uint32_t parseFlags = eParseDeclaration_InBraces |
eParseDeclaration_AllowImportant;
- css::Declaration* declaration = ParseDeclarationBlock(parseFlags);
+ RefPtr declaration = ParseDeclarationBlock(parseFlags);
if (nullptr == declaration) {
delete slist;
return false;
@@ -6236,7 +6357,7 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList,
return true;
}
-css::Declaration*
+already_AddRefed
CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags, nsCSSContextType aContext)
{
bool checkForBraces = (aFlags & eParseDeclaration_InBraces) != 0;
@@ -6253,7 +6374,7 @@ CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags, nsCSSContextType aContext)
return nullptr;
}
}
- css::Declaration* declaration = new css::Declaration();
+ RefPtr declaration = new css::Declaration();
mData.AssertInitialState();
for (;;) {
bool changed;
@@ -6271,15 +6392,15 @@ CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags, nsCSSContextType aContext)
}
}
declaration->CompressFrom(&mData);
- return declaration;
+ return declaration.forget();
}
-bool
+CSSParseResult
CSSParserImpl::ParseColor(nsCSSValue& aValue)
{
if (!GetToken(true)) {
REPORT_UNEXPECTED_EOF(PEColorEOF);
- return false;
+ return CSSParseResult::NotFound;
}
nsCSSToken* tk = &mToken;
@@ -6295,14 +6416,14 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
eCSSUnit_ShortHexColor :
eCSSUnit_HexColor;
aValue.SetIntegerColorValue(rgba, unit);
- return true;
+ return CSSParseResult::Ok;
}
break;
case eCSSToken_Ident:
if (NS_ColorNameToRGB(tk->mIdent, &rgba)) {
aValue.SetStringValue(tk->mIdent, eCSSUnit_Ident);
- return true;
+ return CSSParseResult::Ok;
}
else {
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(tk->mIdent);
@@ -6310,7 +6431,7 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
int32_t value;
if (nsCSSProps::FindKeyword(keyword, nsCSSProps::kColorKTable, value)) {
aValue.SetIntValue(value, eCSSUnit_EnumColor);
- return true;
+ return CSSParseResult::Ok;
}
}
}
@@ -6327,7 +6448,7 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
ParseNumberColorComponent(g, ',') &&
ParseNumberColorComponent(b, ')')) {
aValue.SetIntegerColorValue(NS_RGB(r, g, b), eCSSUnit_RGBColor);
- return true;
+ return CSSParseResult::Ok;
}
} else {
float r, g, b;
@@ -6336,11 +6457,11 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
ParsePercentageColorComponent(b, ')')) {
aValue.SetFloatColorValue(r, g, b, 1.0f,
eCSSUnit_PercentageRGBColor);
- return true;
+ return CSSParseResult::Ok;
}
}
SkipUntil(')');
- return false;
+ return CSSParseResult::Error;
}
else if (mToken.mIdent.LowerCaseEqualsLiteral("rgba")) {
// rgba ( component , component , component , opacity )
@@ -6355,7 +6476,7 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
ParseColorOpacity(a)) {
aValue.SetIntegerColorValue(NS_RGBA(r, g, b, a),
eCSSUnit_RGBAColor);
- return true;
+ return CSSParseResult::Ok;
}
} else {
float r, g, b, a;
@@ -6364,11 +6485,11 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
ParsePercentageColorComponent(b, ',') &&
ParseColorOpacity(a)) {
aValue.SetFloatColorValue(r, g, b, a, eCSSUnit_PercentageRGBAColor);
- return true;
+ return CSSParseResult::Ok;
}
}
SkipUntil(')');
- return false;
+ return CSSParseResult::Error;
}
else if (mToken.mIdent.LowerCaseEqualsLiteral("hsl")) {
// hsl ( hue , saturation , lightness )
@@ -6376,10 +6497,10 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
float h, s, l;
if (ParseHSLColor(h, s, l, ')')) {
aValue.SetFloatColorValue(h, s, l, 1.0f, eCSSUnit_HSLColor);
- return true;
+ return CSSParseResult::Ok;
}
SkipUntil(')');
- return false;
+ return CSSParseResult::Error;
}
else if (mToken.mIdent.LowerCaseEqualsLiteral("hsla")) {
// hsla ( hue , saturation , lightness , opacity )
@@ -6389,10 +6510,10 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
if (ParseHSLColor(h, s, l, ',') &&
ParseColorOpacity(a)) {
aValue.SetFloatColorValue(h, s, l, a, eCSSUnit_HSLAColor);
- return true;
+ return CSSParseResult::Ok;
}
SkipUntil(')');
- return false;
+ return CSSParseResult::Error;
}
break;
default:
@@ -6444,14 +6565,14 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
}
if (NS_HexToRGB(str, &rgba)) {
aValue.SetIntegerColorValue(rgba, eCSSUnit_HexColor);
- return true;
+ return CSSParseResult::Ok;
}
}
// It's not a color
REPORT_UNEXPECTED_TOKEN(PEColorNotColor);
UngetToken();
- return false;
+ return CSSParseResult::NotFound;
}
bool
@@ -6692,12 +6813,17 @@ CSSParserImpl::LookupKeywordPrefixAware(nsAString& aKeywordStr,
}
bool
-CSSParserImpl::ShouldUseUnprefixingService()
+CSSParserImpl::ShouldUseUnprefixingService() const
{
if (!sUnprefixingServiceEnabled) {
// Unprefixing is globally disabled.
return false;
}
+ if (sWebkitPrefixedAliasesEnabled) {
+ // Native webkit-prefix support is enabled, which trumps the unprefixing
+ // service for handling prefixed CSS. Don't try to use both at once.
+ return false;
+ }
#ifdef NIGHTLY_BUILD
if (sUnprefixingServiceGloballyWhitelisted) {
@@ -6767,8 +6893,9 @@ CSSParserImpl::ParsePropertyWithUnprefixingService(
}
bool
-CSSParserImpl::ParseWebkitPrefixedGradient(nsAString& aPrefixedFuncName,
- nsCSSValue& aValue)
+CSSParserImpl::ParseWebkitPrefixedGradientWithService(
+ nsAString& aPrefixedFuncName,
+ nsCSSValue& aValue)
{
MOZ_ASSERT(ShouldUseUnprefixingService(),
"Should only call if we're allowed to use unprefixing service");
@@ -6820,10 +6947,10 @@ CSSParserImpl::ParseWebkitPrefixedGradient(nsAString& aPrefixedFuncName,
nsAutoScannerChanger scannerChanger(this, unprefixedFuncBody);
if (unprefixedFuncName.EqualsLiteral("linear-gradient")) {
- return ParseLinearGradient(aValue, false, false);
+ return ParseLinearGradient(aValue, 0);
}
if (unprefixedFuncName.EqualsLiteral("radial-gradient")) {
- return ParseRadialGradient(aValue, false, false);
+ return ParseRadialGradient(aValue, 0);
}
NS_ERROR("CSSUnprefixingService returned an unrecognized type of "
@@ -7204,7 +7331,7 @@ CSSParserImpl::TranslateDimension(nsCSSValue& aValue,
VARIANT_CALC | \
VARIANT_OPENTYPE_SVG_KEYWORD
-bool
+CSSParseResult
CSSParserImpl::ParseVariantWithRestrictions(nsCSSValue& aValue,
int32_t aVariantMask,
const KTableValue aKeywordTable[],
@@ -7226,7 +7353,7 @@ CSSParserImpl::ParseVariantWithRestrictions(nsCSSValue& aValue,
// full-range parsing inside the calc() expression, and the code that
// computes the calc will be required to clamp the resulting value to an
// appropriate range.
-bool
+CSSParseResult
CSSParserImpl::ParseNonNegativeVariant(nsCSSValue& aValue,
int32_t aVariantMask,
const KTableValue aKeywordTable[])
@@ -7240,35 +7367,35 @@ CSSParserImpl::ParseNonNegativeVariant(nsCSSValue& aValue,
VARIANT_INTEGER)) == 0,
"need to update code below to handle additional variants");
- if (ParseVariant(aValue, aVariantMask, aKeywordTable)) {
+ CSSParseResult result = ParseVariant(aValue, aVariantMask, aKeywordTable);
+ if (result == CSSParseResult::Ok) {
if (eCSSUnit_Number == aValue.GetUnit() ||
aValue.IsLengthUnit()){
if (aValue.GetFloatValue() < 0) {
UngetToken();
- return false;
+ return CSSParseResult::NotFound;
}
}
else if (aValue.GetUnit() == eCSSUnit_Percent) {
if (aValue.GetPercentValue() < 0) {
UngetToken();
- return false;
+ return CSSParseResult::NotFound;
}
} else if (aValue.GetUnit() == eCSSUnit_Integer) {
if (aValue.GetIntValue() < 0) {
UngetToken();
- return false;
+ return CSSParseResult::NotFound;
}
}
- return true;
}
- return false;
+ return result;
}
// Note that callers passing VARIANT_CALC in aVariantMask will get
// full-range parsing inside the calc() expression, and the code that
// computes the calc will be required to clamp the resulting value to an
// appropriate range.
-bool
+CSSParseResult
CSSParserImpl::ParseOneOrLargerVariant(nsCSSValue& aValue,
int32_t aVariantMask,
const KTableValue aKeywordTable[])
@@ -7280,25 +7407,25 @@ CSSParserImpl::ParseOneOrLargerVariant(nsCSSValue& aValue,
VARIANT_INTEGER)) == 0,
"need to update code below to handle additional variants");
- if (ParseVariant(aValue, aVariantMask, aKeywordTable)) {
+ CSSParseResult result = ParseVariant(aValue, aVariantMask, aKeywordTable);
+ if (result == CSSParseResult::Ok) {
if (aValue.GetUnit() == eCSSUnit_Integer) {
if (aValue.GetIntValue() < 1) {
UngetToken();
- return false;
+ return CSSParseResult::NotFound;
}
} else if (eCSSUnit_Number == aValue.GetUnit()) {
if (aValue.GetFloatValue() < 1.0f) {
UngetToken();
- return false;
+ return CSSParseResult::NotFound;
}
}
- return true;
}
- return false;
+ return result;
}
-// Assigns to aValue iff it returns true.
-bool
+// Assigns to aValue iff it returns CSSParseResult::Ok.
+CSSParseResult
CSSParserImpl::ParseVariant(nsCSSValue& aValue,
int32_t aVariantMask,
const KTableValue aKeywordTable[])
@@ -7317,9 +7444,13 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
"must not set both VARIANT_IDENTIFIER and "
"VARIANT_IDENTIFIER_NO_INHERIT");
- if (!GetToken(true)) {
- return false;
+ uint32_t lineBefore, colBefore;
+ if (!GetNextTokenLocation(true, &lineBefore, &colBefore) ||
+ !GetToken(true)) {
+ // Must be at EOF.
+ return CSSParseResult::NotFound;
}
+
nsCSSToken* tk = &mToken;
if (((aVariantMask & (VARIANT_AHK | VARIANT_NORMAL | VARIANT_NONE | VARIANT_ALL)) != 0) &&
(eCSSToken_Ident == tk->mType)) {
@@ -7330,7 +7461,7 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
if ((aVariantMask & VARIANT_AUTO) != 0) {
if (eCSSKeyword_auto == keyword) {
aValue.SetAutoValue();
- return true;
+ return CSSParseResult::Ok;
}
}
if ((aVariantMask & VARIANT_INHERIT) != 0) {
@@ -7342,41 +7473,41 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
// they probably need to be added in ParseCustomIdent as well.
if (eCSSKeyword_inherit == keyword) {
aValue.SetInheritValue();
- return true;
+ return CSSParseResult::Ok;
}
else if (eCSSKeyword_initial == keyword) {
aValue.SetInitialValue();
- return true;
+ return CSSParseResult::Ok;
}
else if (eCSSKeyword_unset == keyword &&
nsLayoutUtils::UnsetValueEnabled()) {
aValue.SetUnsetValue();
- return true;
+ return CSSParseResult::Ok;
}
}
if ((aVariantMask & VARIANT_NONE) != 0) {
if (eCSSKeyword_none == keyword) {
aValue.SetNoneValue();
- return true;
+ return CSSParseResult::Ok;
}
}
if ((aVariantMask & VARIANT_ALL) != 0) {
if (eCSSKeyword_all == keyword) {
aValue.SetAllValue();
- return true;
+ return CSSParseResult::Ok;
}
}
if ((aVariantMask & VARIANT_NORMAL) != 0) {
if (eCSSKeyword_normal == keyword) {
aValue.SetNormalValue();
- return true;
+ return CSSParseResult::Ok;
}
}
if ((aVariantMask & VARIANT_SYSFONT) != 0) {
if (eCSSKeyword__moz_use_system_font == keyword &&
!IsParsingCompoundProperty()) {
aValue.SetSystemFontValue();
- return true;
+ return CSSParseResult::Ok;
}
}
if ((aVariantMask & VARIANT_OPENTYPE_SVG_KEYWORD) != 0) {
@@ -7388,7 +7519,7 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
int32_t value;
if (nsCSSProps::FindKeyword(keyword, aKeywordTable, value)) {
aValue.SetIntValue(value, eCSSUnit_Enumerated);
- return true;
+ return CSSParseResult::Ok;
}
}
}
@@ -7398,12 +7529,12 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
if (((aVariantMask & VARIANT_NUMBER) != 0) &&
(eCSSToken_Number == tk->mType)) {
aValue.SetFloatValue(tk->mNumber, eCSSUnit_Number);
- return true;
+ return CSSParseResult::Ok;
}
if (((aVariantMask & VARIANT_INTEGER) != 0) &&
(eCSSToken_Number == tk->mType) && tk->mIntegerValid) {
aValue.SetIntValue(tk->mInteger, eCSSUnit_Integer);
- return true;
+ return CSSParseResult::Ok;
}
if (((aVariantMask & (VARIANT_LENGTH | VARIANT_ANGLE |
VARIANT_FREQUENCY | VARIANT_TIME)) != 0 &&
@@ -7416,25 +7547,27 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
((aVariantMask & VARIANT_NONNEGATIVE_DIMENSION) != 0 &&
tk->mNumber < 0.0)) {
UngetToken();
- return false;
+ AssertNextTokenAt(lineBefore, colBefore);
+ return CSSParseResult::NotFound;
}
if (TranslateDimension(aValue, aVariantMask, tk->mNumber, tk->mIdent)) {
- return true;
+ return CSSParseResult::Ok;
}
// Put the token back; we didn't parse it, so we shouldn't consume it
UngetToken();
- return false;
+ AssertNextTokenAt(lineBefore, colBefore);
+ return CSSParseResult::NotFound;
}
if (((aVariantMask & VARIANT_PERCENT) != 0) &&
(eCSSToken_Percentage == tk->mType)) {
aValue.SetPercentValue(tk->mNumber);
- return true;
+ return CSSParseResult::Ok;
}
if (mUnitlessLengthQuirk) { // NONSTANDARD: Nav interprets unitless numbers as px
if (((aVariantMask & VARIANT_LENGTH) != 0) &&
(eCSSToken_Number == tk->mType)) {
aValue.SetFloatValue(tk->mNumber, eCSSUnit_Pixel);
- return true;
+ return CSSParseResult::Ok;
}
}
@@ -7444,55 +7577,73 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
if (((aVariantMask & VARIANT_LENGTH) != 0) &&
(eCSSToken_Number == tk->mType)) {
aValue.SetFloatValue(tk->mNumber, eCSSUnit_Pixel);
- return true;
+ return CSSParseResult::Ok;
}
}
if (((aVariantMask & VARIANT_URL) != 0) &&
eCSSToken_URL == tk->mType) {
SetValueToURL(aValue, tk->mIdent);
- return true;
+ return CSSParseResult::Ok;
}
if ((aVariantMask & VARIANT_GRADIENT) != 0 &&
eCSSToken_Function == tk->mType) {
// a generated gradient
nsDependentString tmp(tk->mIdent, 0);
- bool isLegacy = false;
+ uint8_t gradientFlags = 0;
if (sMozGradientsEnabled &&
StringBeginsWith(tmp, NS_LITERAL_STRING("-moz-"))) {
tmp.Rebind(tmp, 5);
- isLegacy = true;
+ gradientFlags |= eGradient_MozLegacy;
+ } else if (sWebkitPrefixedAliasesEnabled &&
+ StringBeginsWith(tmp, NS_LITERAL_STRING("-webkit-"))) {
+ tmp.Rebind(tmp, 8);
+ gradientFlags |= eGradient_WebkitLegacy;
}
- bool isRepeating = false;
if (StringBeginsWith(tmp, NS_LITERAL_STRING("repeating-"))) {
tmp.Rebind(tmp, 10);
- isRepeating = true;
+ gradientFlags |= eGradient_Repeating;
}
if (tmp.LowerCaseEqualsLiteral("linear-gradient")) {
- return ParseLinearGradient(aValue, isRepeating, isLegacy);
+ if (!ParseLinearGradient(aValue, gradientFlags)) {
+ return CSSParseResult::Error;
+ }
+ return CSSParseResult::Ok;
}
if (tmp.LowerCaseEqualsLiteral("radial-gradient")) {
- return ParseRadialGradient(aValue, isRepeating, isLegacy);
+ if (!ParseRadialGradient(aValue, gradientFlags)) {
+ return CSSParseResult::Error;
+ }
+ return CSSParseResult::Ok;
}
if (ShouldUseUnprefixingService() &&
- !isRepeating && !isLegacy &&
+ !gradientFlags &&
StringBeginsWith(tmp, NS_LITERAL_STRING("-webkit-"))) {
// Copy 'tmp' into a string on the stack, since as soon as we
// start parsing, its backing store (in "tk") will be overwritten
nsAutoString prefixedFuncName(tmp);
- return ParseWebkitPrefixedGradient(prefixedFuncName, aValue);
+ if (!ParseWebkitPrefixedGradientWithService(prefixedFuncName, aValue)) {
+ return CSSParseResult::Error;
+ }
+ return CSSParseResult::Ok;
}
}
if ((aVariantMask & VARIANT_IMAGE_RECT) != 0 &&
eCSSToken_Function == tk->mType &&
tk->mIdent.LowerCaseEqualsLiteral("-moz-image-rect")) {
- return ParseImageRect(aValue);
+ if (!ParseImageRect(aValue)) {
+ return CSSParseResult::Error;
+ }
+ return CSSParseResult::Ok;
}
if ((aVariantMask & VARIANT_ELEMENT) != 0 &&
eCSSToken_Function == tk->mType &&
tk->mIdent.LowerCaseEqualsLiteral("-moz-element")) {
- return ParseElement(aValue);
+ if (!ParseElement(aValue)) {
+ return CSSParseResult::Error;
+ }
+ return CSSParseResult::Ok;
}
if ((aVariantMask & VARIANT_COLOR) != 0) {
if (mHashlessColorQuirk || // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix
@@ -7507,10 +7658,7 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
{
// Put token back so that parse color can get it
UngetToken();
- if (ParseColor(aValue)) {
- return true;
- }
- return false;
+ return ParseColor(aValue);
}
}
if (((aVariantMask & VARIANT_STRING) != 0) &&
@@ -7518,7 +7666,7 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
nsAutoString buffer;
buffer.Append(tk->mIdent);
aValue.SetStringValue(buffer, eCSSUnit_String);
- return true;
+ return CSSParseResult::Ok;
}
if (((aVariantMask &
(VARIANT_IDENTIFIER | VARIANT_IDENTIFIER_NO_INHERIT)) != 0) &&
@@ -7529,38 +7677,41 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
(tk->mIdent.LowerCaseEqualsLiteral("unset") &&
nsLayoutUtils::UnsetValueEnabled())))) {
aValue.SetStringValue(tk->mIdent, eCSSUnit_Ident);
- return true;
+ return CSSParseResult::Ok;
}
if (((aVariantMask & VARIANT_COUNTER) != 0) &&
(eCSSToken_Function == tk->mType) &&
(tk->mIdent.LowerCaseEqualsLiteral("counter") ||
tk->mIdent.LowerCaseEqualsLiteral("counters"))) {
- return ParseCounter(aValue);
+ if (!ParseCounter(aValue)) {
+ return CSSParseResult::Error;
+ }
+ return CSSParseResult::Ok;
}
if (((aVariantMask & VARIANT_ATTR) != 0) &&
(eCSSToken_Function == tk->mType) &&
tk->mIdent.LowerCaseEqualsLiteral("attr")) {
if (!ParseAttr(aValue)) {
SkipUntil(')');
- return false;
+ return CSSParseResult::Error;
}
- return true;
+ return CSSParseResult::Ok;
}
if (((aVariantMask & VARIANT_TIMING_FUNCTION) != 0) &&
(eCSSToken_Function == tk->mType)) {
if (tk->mIdent.LowerCaseEqualsLiteral("cubic-bezier")) {
if (!ParseTransitionTimingFunctionValues(aValue)) {
SkipUntil(')');
- return false;
+ return CSSParseResult::Error;
}
- return true;
+ return CSSParseResult::Ok;
}
if (tk->mIdent.LowerCaseEqualsLiteral("steps")) {
if (!ParseTransitionStepTimingFunctionValues(aValue)) {
SkipUntil(')');
- return false;
+ return CSSParseResult::Error;
}
- return true;
+ return CSSParseResult::Ok;
}
}
if ((aVariantMask & VARIANT_CALC) &&
@@ -7568,11 +7719,15 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
(tk->mIdent.LowerCaseEqualsLiteral("calc") ||
tk->mIdent.LowerCaseEqualsLiteral("-moz-calc"))) {
// calc() currently allows only lengths and percents inside it.
- return ParseCalc(aValue, aVariantMask & VARIANT_LP);
+ if (!ParseCalc(aValue, aVariantMask & VARIANT_LP)) {
+ return CSSParseResult::Error;
+ }
+ return CSSParseResult::Ok;
}
UngetToken();
- return false;
+ AssertNextTokenAt(lineBefore, colBefore);
+ return CSSParseResult::NotFound;
}
bool
@@ -7756,7 +7911,7 @@ CSSParserImpl::ParseSymbols(nsCSSValue& aValue)
nsCSSValueList* item = symbols.SetListValue();
for (;;) {
// FIXME Should also include VARIANT_IMAGE. See bug 1071436.
- if (!ParseVariant(item->mValue, VARIANT_STRING, nullptr)) {
+ if (!ParseSingleTokenVariant(item->mValue, VARIANT_STRING, nullptr)) {
break;
}
if (ExpectSymbol(')', true)) {
@@ -7810,17 +7965,18 @@ CSSParserImpl::SetValueToURL(nsCSSValue& aValue, const nsString& aURL)
bool
CSSParserImpl::ParseImageOrientation(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT, nullptr)) {
// 'inherit', 'initial' and 'unset' must be alone
return true;
}
// Check for an angle with optional 'flip'.
nsCSSValue angle;
- if (ParseVariant(angle, VARIANT_ANGLE, nullptr)) {
+ if (ParseSingleTokenVariant(angle, VARIANT_ANGLE, nullptr)) {
nsCSSValue flip;
- if (ParseVariant(flip, VARIANT_KEYWORD, nsCSSProps::kImageOrientationFlipKTable)) {
+ if (ParseSingleTokenVariant(flip, VARIANT_KEYWORD,
+ nsCSSProps::kImageOrientationFlipKTable)) {
RefPtr array = nsCSSValue::Array::Create(2);
array->Item(0) = angle;
array->Item(1) = flip;
@@ -7835,7 +7991,8 @@ CSSParserImpl::ParseImageOrientation(nsCSSValue& aValue)
// The remaining possibilities (bare 'flip' and 'from-image') are both
// keywords, so we can handle them at the same time.
nsCSSValue keyword;
- if (ParseVariant(keyword, VARIANT_KEYWORD, nsCSSProps::kImageOrientationKTable)) {
+ if (ParseSingleTokenVariant(keyword, VARIANT_KEYWORD,
+ nsCSSProps::kImageOrientationKTable)) {
aValue = keyword;
return true;
}
@@ -7873,13 +8030,13 @@ CSSParserImpl::ParseImageRect(nsCSSValue& aImage)
}
static const int32_t VARIANT_SIDE = VARIANT_NUMBER | VARIANT_PERCENT;
- if (!ParseNonNegativeVariant(top, VARIANT_SIDE, nullptr) ||
+ if (!ParseSingleTokenNonNegativeVariant(top, VARIANT_SIDE, nullptr) ||
!ExpectSymbol(',', true) ||
- !ParseNonNegativeVariant(right, VARIANT_SIDE, nullptr) ||
+ !ParseSingleTokenNonNegativeVariant(right, VARIANT_SIDE, nullptr) ||
!ExpectSymbol(',', true) ||
- !ParseNonNegativeVariant(bottom, VARIANT_SIDE, nullptr) ||
+ !ParseSingleTokenNonNegativeVariant(bottom, VARIANT_SIDE, nullptr) ||
!ExpectSymbol(',', true) ||
- !ParseNonNegativeVariant(left, VARIANT_SIDE, nullptr) ||
+ !ParseSingleTokenNonNegativeVariant(left, VARIANT_SIDE, nullptr) ||
!ExpectSymbol(')', true))
break;
@@ -7925,7 +8082,7 @@ CSSParserImpl::ParseFlex()
{
// First check for inherit / initial / unset
nsCSSValue tmpVal;
- if (ParseVariant(tmpVal, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(tmpVal, VARIANT_INHERIT, nullptr)) {
AppendValue(eCSSProperty_flex_grow, tmpVal);
AppendValue(eCSSProperty_flex_shrink, tmpVal);
AppendValue(eCSSProperty_flex_basis, tmpVal);
@@ -7933,7 +8090,7 @@ CSSParserImpl::ParseFlex()
}
// Next, check for 'none' == '0 0 auto'
- if (ParseVariant(tmpVal, VARIANT_NONE, nullptr)) {
+ if (ParseSingleTokenVariant(tmpVal, VARIANT_NONE, nullptr)) {
AppendValue(eCSSProperty_flex_grow, nsCSSValue(0.0f, eCSSUnit_Number));
AppendValue(eCSSProperty_flex_shrink, nsCSSValue(0.0f, eCSSUnit_Number));
AppendValue(eCSSProperty_flex_basis, nsCSSValue(eCSSUnit_Auto));
@@ -7975,8 +8132,8 @@ CSSParserImpl::ParseFlex()
// it'll treat unitless 0 as a number. The flexbox spec requires this:
// "a unitless zero that is not already preceded by two flex factors must be
// interpreted as a flex factor.
- if (!ParseNonNegativeVariant(tmpVal, flexBasisVariantMask | VARIANT_NUMBER,
- nsCSSProps::kWidthKTable)) {
+ if (ParseNonNegativeVariant(tmpVal, flexBasisVariantMask | VARIANT_NUMBER,
+ nsCSSProps::kWidthKTable) != CSSParseResult::Ok) {
// First component was not a valid flex-basis or flex-grow value. Fail.
return false;
}
@@ -7988,7 +8145,7 @@ CSSParserImpl::ParseFlex()
// (b) If we didn't get flex-grow yet, parse _next_ component as flex-grow.
bool doneParsing = false;
if (wasFirstComponentFlexBasis) {
- if (ParseNonNegativeVariant(tmpVal, VARIANT_NUMBER, nullptr)) {
+ if (ParseNonNegativeNumber(tmpVal)) {
flexGrow = tmpVal;
} else {
// Failed to parse anything after our flex-basis -- that's fine. We can
@@ -8000,7 +8157,7 @@ CSSParserImpl::ParseFlex()
if (!doneParsing) {
// (c) OK -- the last thing we parsed was flex-grow, so look for a
// flex-shrink in the next position.
- if (ParseNonNegativeVariant(tmpVal, VARIANT_NUMBER, nullptr)) {
+ if (ParseNonNegativeNumber(tmpVal)) {
flexShrink = tmpVal;
}
@@ -8022,10 +8179,15 @@ CSSParserImpl::ParseFlex()
// by *no* flex factors (if it were the first token), we would've already
// parsed it in our very first call to ParseNonNegativeVariant(). So, any
// unitless 0 encountered here *must* have been preceded by 2 flex factors.
- if (!wasFirstComponentFlexBasis &&
+ if (!wasFirstComponentFlexBasis) {
+ CSSParseResult result =
ParseNonNegativeVariant(tmpVal, flexBasisVariantMask,
- nsCSSProps::kWidthKTable)) {
- flexBasis = tmpVal;
+ nsCSSProps::kWidthKTable);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::Ok) {
+ flexBasis = tmpVal;
+ }
}
}
@@ -8073,7 +8235,7 @@ bool
CSSParserImpl::ParseGridAutoFlow()
{
nsCSSValue value;
- if (ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
AppendValue(eCSSProperty_grid_auto_flow, value);
return true;
}
@@ -8233,27 +8395,30 @@ CSSParserImpl::ParseOptionalLineNameListAfterSubgrid(nsCSSValue& aValue)
}
// Parse a .
-bool
+CSSParseResult
CSSParserImpl::ParseGridTrackBreadth(nsCSSValue& aValue)
{
- if (ParseNonNegativeVariant(aValue,
+ CSSParseResult result =
+ ParseNonNegativeVariant(aValue,
VARIANT_AUTO | VARIANT_LPCALC | VARIANT_KEYWORD,
- nsCSSProps::kGridTrackBreadthKTable)) {
- return true;
+ nsCSSProps::kGridTrackBreadthKTable);
+ if (result == CSSParseResult::Ok ||
+ result == CSSParseResult::Error) {
+ return result;
}
// Attempt to parse (a dimension with the "fr" unit).
if (!GetToken(true)) {
- return false;
+ return CSSParseResult::NotFound;
}
if (!(eCSSToken_Dimension == mToken.mType &&
mToken.mIdent.LowerCaseEqualsLiteral("fr") &&
mToken.mNumber >= 0)) {
UngetToken();
- return false;
+ return CSSParseResult::NotFound;
}
aValue.SetFloatValue(mToken.mNumber, eCSSUnit_FlexFraction);
- return true;
+ return CSSParseResult::Ok;
}
// Parse a .
@@ -8261,8 +8426,10 @@ CSSParseResult
CSSParserImpl::ParseGridTrackSize(nsCSSValue& aValue)
{
// Attempt to parse a single .
- if (ParseGridTrackBreadth(aValue)) {
- return CSSParseResult::Ok;
+ CSSParseResult result = ParseGridTrackBreadth(aValue);
+ if (result == CSSParseResult::Ok ||
+ result == CSSParseResult::Error) {
+ return result;
}
// Attempt to parse a minmax() function.
@@ -8275,9 +8442,9 @@ CSSParserImpl::ParseGridTrackSize(nsCSSValue& aValue)
return CSSParseResult::NotFound;
}
nsCSSValue::Array* func = aValue.InitFunction(eCSSKeyword_minmax, 2);
- if (ParseGridTrackBreadth(func->Item(1)) &&
+ if (ParseGridTrackBreadth(func->Item(1)) == CSSParseResult::Ok &&
ExpectSymbol(',', true) &&
- ParseGridTrackBreadth(func->Item(2)) &&
+ ParseGridTrackBreadth(func->Item(2)) == CSSParseResult::Ok &&
ExpectSymbol(')', true)) {
return CSSParseResult::Ok;
}
@@ -8289,7 +8456,7 @@ bool
CSSParserImpl::ParseGridAutoColumnsRows(nsCSSProperty aPropID)
{
nsCSSValue value;
- if (ParseVariant(value, VARIANT_INHERIT, nullptr) ||
+ if (ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr) ||
ParseGridTrackSize(value) == CSSParseResult::Ok) {
AppendValue(aPropID, value);
return true;
@@ -8570,7 +8737,7 @@ bool
CSSParserImpl::ParseGridTemplateColumnsRows(nsCSSProperty aPropID)
{
nsCSSValue value;
- if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
AppendValue(aPropID, value);
return true;
}
@@ -8686,7 +8853,7 @@ bool
CSSParserImpl::ParseGridTemplateAreas()
{
nsCSSValue value;
- if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
AppendValue(eCSSProperty_grid_template_areas, value);
return true;
}
@@ -8723,7 +8890,7 @@ CSSParserImpl::ParseGridTemplate()
// <'grid-template-columns'> / <'grid-template-rows'> |
// [ / ]? [ ? ? ? ]+
nsCSSValue value;
- if (ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
AppendValue(eCSSProperty_grid_template_areas, value);
AppendValue(eCSSProperty_grid_template_columns, value);
AppendValue(eCSSProperty_grid_template_rows, value);
@@ -8734,7 +8901,7 @@ CSSParserImpl::ParseGridTemplate()
// 'none' can appear either by itself,
// or as the beginning of <'grid-template-columns'> / <'grid-template-rows'>
- if (ParseVariant(value, VARIANT_NONE, nullptr)) {
+ if (ParseSingleTokenVariant(value, VARIANT_NONE, nullptr)) {
AppendValue(eCSSProperty_grid_template_columns, value);
if (ExpectSymbol('/', true)) {
return ParseGridTemplateAfterSlash(/* aColumnsIsTrackList = */ false);
@@ -8811,7 +8978,7 @@ bool
CSSParserImpl::ParseGridTemplateAfterSlash(bool aColumnsIsTrackList)
{
nsCSSValue rowsValue;
- if (ParseVariant(rowsValue, VARIANT_NONE, nullptr)) {
+ if (ParseSingleTokenVariant(rowsValue, VARIANT_NONE, nullptr)) {
// <'grid-template-columns'> / <'grid-template-rows'>
AppendValue(eCSSProperty_grid_template_rows, rowsValue);
nsCSSValue areasValue(eCSSUnit_None); // implied
@@ -8936,7 +9103,7 @@ bool
CSSParserImpl::ParseGrid()
{
nsCSSValue value;
- if (ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
for (const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(eCSSProperty_grid);
*subprops != eCSSProperty_UNKNOWN; ++subprops) {
@@ -9028,7 +9195,7 @@ CSSParserImpl::ParseGridLine(nsCSSValue& aValue)
// auto |
// [ span? && [ || ] ]
- if (ParseVariant(aValue, VARIANT_AUTO, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_AUTO, nullptr)) {
return true;
}
@@ -9111,7 +9278,7 @@ bool
CSSParserImpl::ParseGridColumnRowStartEnd(nsCSSProperty aPropID)
{
nsCSSValue value;
- if (ParseVariant(value, VARIANT_INHERIT, nullptr) ||
+ if (ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr) ||
ParseGridLine(value)) {
AppendValue(aPropID, value);
return true;
@@ -9140,7 +9307,7 @@ CSSParserImpl::ParseGridColumnRow(nsCSSProperty aStartPropID,
{
nsCSSValue value;
nsCSSValue secondValue;
- if (ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
AppendValue(aStartPropID, value);
AppendValue(aEndPropID, value);
return true;
@@ -9175,7 +9342,7 @@ bool
CSSParserImpl::ParseGridArea()
{
nsCSSValue values[4];
- if (ParseVariant(values[0], VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(values[0], VARIANT_INHERIT, nullptr)) {
AppendValue(eCSSProperty_grid_row_start, values[0]);
AppendValue(eCSSProperty_grid_column_start, values[0]);
AppendValue(eCSSProperty_grid_row_end, values[0]);
@@ -9287,13 +9454,19 @@ bool
CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient)
{
nsCSSValueGradientStop* stop = aGradient->mStops.AppendElement();
- if (!ParseVariant(stop->mColor, VARIANT_COLOR, nullptr)) {
+ CSSParseResult result = ParseVariant(stop->mColor, VARIANT_COLOR, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::NotFound) {
stop->mIsInterpolationHint = true;
}
// Stop positions do not have to fall between the starting-point and
// ending-point, so we don't use ParseNonNegativeVariant.
- if (!ParseVariant(stop->mLocation, VARIANT_LP | VARIANT_CALC, nullptr)) {
+ result = ParseVariant(stop->mLocation, VARIANT_LP | VARIANT_CALC, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::NotFound) {
if (stop->mIsInterpolationHint) {
return false;
}
@@ -9302,6 +9475,31 @@ CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient)
return true;
}
+// Helper for ParseLinearGradient -- returns true iff aPosition represents a
+// box-position value which was parsed with only edge keywords.
+// e.g. "left top", or "bottom", but not "left 10px"
+//
+// (NOTE: Even though callers may want to exclude explicit "center", we still
+// need to allow for _CENTER here, because omitted position-values (e.g. the
+// x-component of a value like "top") will have been parsed as being *implicit*
+// center. The correct way to disallow *explicit* center is to pass "false" for
+// ParseBoxPositionValues()'s "aAllowExplicitCenter" parameter, before you
+// call this function.)
+static bool
+IsBoxPositionStrictlyEdgeKeywords(nsCSSValuePair& aPosition)
+{
+ const nsCSSValue& xValue = aPosition.mXValue;
+ const nsCSSValue& yValue = aPosition.mYValue;
+ return (xValue.GetUnit() == eCSSUnit_Enumerated &&
+ (xValue.GetIntValue() & (NS_STYLE_BG_POSITION_LEFT |
+ NS_STYLE_BG_POSITION_CENTER |
+ NS_STYLE_BG_POSITION_RIGHT)) &&
+ yValue.GetUnit() == eCSSUnit_Enumerated &&
+ (yValue.GetIntValue() & (NS_STYLE_BG_POSITION_TOP |
+ NS_STYLE_BG_POSITION_CENTER |
+ NS_STYLE_BG_POSITION_BOTTOM)));
+}
+
//
// : linear-gradient( ? ')'
// | radial-gradient( ? ')'
@@ -9323,17 +9521,19 @@ CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient)
//
// : , [, ]*
bool
-CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating,
- bool aIsLegacy)
+CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue,
+ uint8_t aFlags)
{
RefPtr cssGradient
- = new nsCSSValueGradient(false, aIsRepeating);
+ = new nsCSSValueGradient(false, aFlags & eGradient_Repeating);
if (!GetToken(true)) {
return false;
}
- if (mToken.mType == eCSSToken_Ident &&
+ // Check for "to" syntax (but not if parsing a -webkit-linear-gradient)
+ if (!(aFlags & eGradient_WebkitLegacy) &&
+ mToken.mType == eCSSToken_Ident &&
mToken.mIdent.LowerCaseEqualsLiteral("to")) {
// "to" syntax doesn't allow explicit "center"
@@ -9343,16 +9543,7 @@ CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating,
}
// [ to [left | right] || [top | bottom] ] ,
- const nsCSSValue& xValue = cssGradient->mBgPos.mXValue;
- const nsCSSValue& yValue = cssGradient->mBgPos.mYValue;
- if (xValue.GetUnit() != eCSSUnit_Enumerated ||
- !(xValue.GetIntValue() & (NS_STYLE_BG_POSITION_LEFT |
- NS_STYLE_BG_POSITION_CENTER |
- NS_STYLE_BG_POSITION_RIGHT)) ||
- yValue.GetUnit() != eCSSUnit_Enumerated ||
- !(yValue.GetIntValue() & (NS_STYLE_BG_POSITION_TOP |
- NS_STYLE_BG_POSITION_CENTER |
- NS_STYLE_BG_POSITION_BOTTOM))) {
+ if (!IsBoxPositionStrictlyEdgeKeywords(cssGradient->mBgPos)) {
SkipUntil(')');
return false;
}
@@ -9365,11 +9556,14 @@ CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating,
return ParseGradientColorStops(cssGradient, aValue);
}
- if (!aIsLegacy) {
+ if (!(aFlags & eGradient_AnyLegacy)) {
+ // We're parsing an unprefixed linear-gradient, and we tried & failed to
+ // parse a 'to' token above. Put the token back & try to re-parse our
+ // expression as ?
UngetToken();
// ,
- if (ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr) &&
+ if (ParseSingleTokenVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr) &&
!ExpectSymbol(',', true)) {
SkipUntil(')');
return false;
@@ -9378,29 +9572,48 @@ CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating,
return ParseGradientColorStops(cssGradient, aValue);
}
- nsCSSTokenType ty = mToken.mType;
- nsString id = mToken.mIdent;
+ // If we get here, we're parsing a prefixed linear-gradient expression. Put
+ // back the first token (which we may have checked for "to" above) and try to
+ // parse expression as ?
+ bool haveGradientLine = IsLegacyGradientLine(mToken.mType, mToken.mIdent);
UngetToken();
- //
- bool haveGradientLine = IsLegacyGradientLine(ty, id);
if (haveGradientLine) {
+ // Parse a
cssGradient->mIsLegacySyntax = true;
bool haveAngle =
- ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr);
+ ParseSingleTokenVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr);
// if we got an angle, we might now have a comma, ending the gradient-line
- if (!haveAngle || !ExpectSymbol(',', true)) {
- if (!ParseBoxPositionValues(cssGradient->mBgPos, false)) {
+ bool haveAngleComma = haveAngle && ExpectSymbol(',', true);
+
+ // If we're webkit-prefixed & didn't get an angle,
+ // OR if we're moz-prefixed & didn't get an angle+comma,
+ // then proceed to parse a box-position.
+ if (((aFlags & eGradient_WebkitLegacy) && !haveAngle) ||
+ ((aFlags & eGradient_MozLegacy) && !haveAngleComma)) {
+ // (Note: 3rd arg controls whether the "center" keyword is allowed.
+ // -moz-linear-gradient allows it; -webkit-linear-gradient does not.)
+ if (!ParseBoxPositionValues(cssGradient->mBgPos, false,
+ (aFlags & eGradient_MozLegacy))) {
+ SkipUntil(')');
+ return false;
+ }
+
+ // -webkit-linear-gradient only supports edge keywords here.
+ if ((aFlags & eGradient_WebkitLegacy) &&
+ !IsBoxPositionStrictlyEdgeKeywords(cssGradient->mBgPos)) {
SkipUntil(')');
return false;
}
if (!ExpectSymbol(',', true) &&
- // if we didn't already get an angle, we might have one now,
- // otherwise it's an error
+ // If we didn't already get an angle, and we're not -webkit prefixed,
+ // we can parse an angle+comma now. Otherwise it's an error.
(haveAngle ||
- !ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr) ||
+ (aFlags & eGradient_WebkitLegacy) ||
+ !ParseSingleTokenVariant(cssGradient->mAngle, VARIANT_ANGLE,
+ nullptr) ||
// now we better have a comma
!ExpectSymbol(',', true))) {
SkipUntil(')');
@@ -9413,28 +9626,30 @@ CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating,
}
bool
-CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating,
- bool aIsLegacy)
+CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue,
+ uint8_t aFlags)
{
RefPtr cssGradient
- = new nsCSSValueGradient(true, aIsRepeating);
+ = new nsCSSValueGradient(true, aFlags & eGradient_Repeating);
// [ || ]
bool haveShape =
- ParseVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD,
- nsCSSProps::kRadialGradientShapeKTable);
+ ParseSingleTokenVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD,
+ nsCSSProps::kRadialGradientShapeKTable);
- bool haveSize = ParseVariant(cssGradient->GetRadialSize(), VARIANT_KEYWORD,
- aIsLegacy ?
- nsCSSProps::kRadialGradientLegacySizeKTable :
- nsCSSProps::kRadialGradientSizeKTable);
+ bool haveSize =
+ ParseSingleTokenVariant(cssGradient->GetRadialSize(), VARIANT_KEYWORD,
+ (aFlags & eGradient_AnyLegacy) ?
+ nsCSSProps::kRadialGradientLegacySizeKTable :
+ nsCSSProps::kRadialGradientSizeKTable);
if (haveSize) {
if (!haveShape) {
//
- haveShape = ParseVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD,
- nsCSSProps::kRadialGradientShapeKTable);
+ haveShape =
+ ParseSingleTokenVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD,
+ nsCSSProps::kRadialGradientShapeKTable);
}
- } else if (!aIsLegacy) {
+ } else if (!(aFlags & eGradient_AnyLegacy)) {
// Save RadialShape before parsing RadiusX because RadialShape and
// RadiusX share the storage.
int32_t shape =
@@ -9443,7 +9658,8 @@ CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating,
// | [ | ]{2}
cssGradient->mIsExplicitSize = true;
haveSize =
- ParseNonNegativeVariant(cssGradient->GetRadiusX(), VARIANT_LP, nullptr);
+ ParseSingleTokenNonNegativeVariant(cssGradient->GetRadiusX(), VARIANT_LP,
+ nullptr);
if (!haveSize) {
// It was not an explicit size after all.
// Note that ParseNonNegativeVariant may have put something
@@ -9457,11 +9673,13 @@ CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating,
} else {
// vertical extent is optional
bool haveYSize =
- ParseNonNegativeVariant(cssGradient->GetRadiusY(), VARIANT_LP, nullptr);
+ ParseSingleTokenNonNegativeVariant(cssGradient->GetRadiusY(),
+ VARIANT_LP, nullptr);
if (!haveShape) {
nsCSSValue shapeValue;
- haveShape = ParseVariant(shapeValue, VARIANT_KEYWORD,
- nsCSSProps::kRadialGradientShapeKTable);
+ haveShape =
+ ParseSingleTokenVariant(shapeValue, VARIANT_KEYWORD,
+ nsCSSProps::kRadialGradientShapeKTable);
if (haveShape) {
shape = shapeValue.GetIntValue();
}
@@ -9485,7 +9703,7 @@ CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating,
return false;
}
- if (!aIsLegacy) {
+ if (!(aFlags & eGradient_AnyLegacy)) {
if (mToken.mType == eCSSToken_Ident &&
mToken.mIdent.LowerCaseEqualsLiteral("at")) {
// [ || ]? at ,
@@ -9516,10 +9734,12 @@ CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating,
haveGradientLine = IsLegacyGradientLine(ty, id);
}
if (haveGradientLine) {
- bool haveAngle =
- ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr);
+ // Note: -webkit-radial-gradient() doesn't accept angles.
+ bool haveAngle = (aFlags & eGradient_WebkitLegacy)
+ ? false
+ : ParseSingleTokenVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr);
- // if we got an angle, we might now have a comma, ending the gradient-line
+ // If we got an angle, we might now have a comma, ending the gradient-line
if (!haveAngle || !ExpectSymbol(',', true)) {
if (!ParseBoxPositionValues(cssGradient->mBgPos, false)) {
SkipUntil(')');
@@ -9527,10 +9747,12 @@ CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating,
}
if (!ExpectSymbol(',', true) &&
- // if we didn't already get an angle, we might have one now,
- // otherwise it's an error
+ // If we didn't already get an angle, and we're not -webkit prefixed,
+ // can parse an angle+comma now. Otherwise it's an error.
(haveAngle ||
- !ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr) ||
+ (aFlags & eGradient_WebkitLegacy) ||
+ !ParseSingleTokenVariant(cssGradient->mAngle, VARIANT_ANGLE,
+ nullptr) ||
// now we better have a comma
!ExpectSymbol(',', true))) {
SkipUntil(')');
@@ -9546,17 +9768,17 @@ CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating,
// radial gradients might have a shape and size here for legacy syntax
if (!haveShape && !haveSize) {
haveShape =
- ParseVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD,
- nsCSSProps::kRadialGradientShapeKTable);
+ ParseSingleTokenVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD,
+ nsCSSProps::kRadialGradientShapeKTable);
haveSize =
- ParseVariant(cssGradient->GetRadialSize(), VARIANT_KEYWORD,
- nsCSSProps::kRadialGradientLegacySizeKTable);
+ ParseSingleTokenVariant(cssGradient->GetRadialSize(), VARIANT_KEYWORD,
+ nsCSSProps::kRadialGradientLegacySizeKTable);
// could be in either order
if (!haveShape) {
haveShape =
- ParseVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD,
- nsCSSProps::kRadialGradientShapeKTable);
+ ParseSingleTokenVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD,
+ nsCSSProps::kRadialGradientShapeKTable);
}
}
@@ -9677,7 +9899,12 @@ CSSParserImpl::ParseChoice(nsCSSValue aValues[],
for (index = 0; index < aNumIDs; index++) {
int32_t bit = 1 << index;
if ((found & bit) == 0) {
- if (ParseSingleValueProperty(aValues[index], aPropIDs[index])) {
+ CSSParseResult result =
+ ParseSingleValueProperty(aValues[index], aPropIDs[index]);
+ if (result == CSSParseResult::Error) {
+ return -1;
+ }
+ if (result == CSSParseResult::Ok) {
found |= bit;
// It's more efficient to break since it will reset |hadFound|
// to |found|. Furthermore, ParseListStyle depends on our going
@@ -9838,14 +10065,19 @@ CSSParserImpl::ParseBoxCornerRadius(nsCSSProperty aPropID)
{
nsCSSValue dimenX, dimenY;
// required first value
- if (! ParseNonNegativeVariant(dimenX, VARIANT_HLP | VARIANT_CALC, nullptr))
+ if (ParseNonNegativeVariant(dimenX, VARIANT_HLP | VARIANT_CALC, nullptr) !=
+ CSSParseResult::Ok) {
return false;
+ }
// optional second value (forbidden if first value is inherit/initial/unset)
if (dimenX.GetUnit() != eCSSUnit_Inherit &&
dimenX.GetUnit() != eCSSUnit_Initial &&
dimenX.GetUnit() != eCSSUnit_Unset) {
- ParseNonNegativeVariant(dimenY, VARIANT_LP | VARIANT_CALC, nullptr);
+ if (ParseNonNegativeVariant(dimenY, VARIANT_LP | VARIANT_CALC, nullptr) ==
+ CSSParseResult::Error) {
+ return false;
+ }
}
if (dimenX == dimenY || dimenY.GetUnit() == eCSSUnit_Null) {
@@ -9868,11 +10100,16 @@ CSSParserImpl::ParseBoxCornerRadiiInternals(nsCSSValue array[])
int32_t countX = 0, countY = 0;
NS_FOR_CSS_SIDES (side) {
- if (! ParseNonNegativeVariant(dimenX.*nsCSSRect::sides[side],
- (side > 0 ? 0 : VARIANT_INHERIT) |
- VARIANT_LP | VARIANT_CALC,
- nullptr))
+ CSSParseResult result =
+ ParseNonNegativeVariant(dimenX.*nsCSSRect::sides[side],
+ (side > 0 ? 0 : VARIANT_INHERIT) |
+ VARIANT_LP | VARIANT_CALC,
+ nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::NotFound) {
break;
+ }
countX++;
}
if (countX == 0)
@@ -9880,9 +10117,14 @@ CSSParserImpl::ParseBoxCornerRadiiInternals(nsCSSValue array[])
if (ExpectSymbol('/', true)) {
NS_FOR_CSS_SIDES (side) {
- if (! ParseNonNegativeVariant(dimenY.*nsCSSRect::sides[side],
- VARIANT_LP | VARIANT_CALC, nullptr))
+ CSSParseResult result =
+ ParseNonNegativeVariant(dimenY.*nsCSSRect::sides[side],
+ VARIANT_LP | VARIANT_CALC, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::NotFound) {
break;
+ }
countY++;
}
if (countY == 0)
@@ -10036,7 +10278,7 @@ CSSParserImpl::ParseProperty(nsCSSProperty aPropID)
case CSS_PROPERTY_PARSE_VALUE: {
result = false;
nsCSSValue value;
- if (ParseSingleValueProperty(value, aPropID)) {
+ if (ParseSingleValueProperty(value, aPropID) == CSSParseResult::Ok) {
AppendValue(aPropID, value);
result = true;
}
@@ -10408,29 +10650,23 @@ CSSParserImpl::ParseBoxPropertyVariant(nsCSSValue& aValue,
uint32_t aRestrictions,
bool& aConsumedTokens)
{
- aConsumedTokens = false;
-
- uint32_t lineBefore, colBefore;
- if (!GetNextTokenLocation(true, &lineBefore, &colBefore)) {
- return false;
- }
-
- if (!ParseVariantWithRestrictions(aValue, aVariantMask, aKeywordTable,
- aRestrictions)) {
- uint32_t lineAfter, colAfter;
- if (!GetNextTokenLocation(true, &lineAfter, &colAfter)) {
- // any single token value that was invalid will have been pushed back,
- // so GetNextTokenLocation encountering EOF means we failed while
- // parsing a multi-token value
+ CSSParseResult result =
+ ParseVariantWithRestrictions(aValue, aVariantMask, aKeywordTable,
+ aRestrictions);
+ switch (result) {
+ case CSSParseResult::Ok:
aConsumedTokens = true;
- } else if (lineAfter != lineBefore || colAfter != colBefore) {
+ return true;
+ case CSSParseResult::NotFound:
+ aConsumedTokens = false;
+ return false;
+ default:
+ MOZ_ASSERT_UNREACHABLE("invalid CSSParseResult value");
+ // fall through
+ case CSSParseResult::Error:
aConsumedTokens = true;
- }
- return false;
+ return false;
}
-
- aConsumedTokens = true;
- return true;
}
bool
@@ -10455,12 +10691,6 @@ CSSParserImpl::ParseBoxProperty(nsCSSValue& aValue,
return false;
}
- if (aPropID == eCSSProperty_script_level ||
- aPropID == eCSSProperty_math_display) {
- MOZ_ASSERT(false, "must not be called for unsafe properties");
- return false;
- }
-
if (variant & ~(VARIANT_AHKLP | VARIANT_COLOR | VARIANT_CALC)) {
MOZ_ASSERT(false, "must only be called for properties that take certain "
"variants");
@@ -10475,6 +10705,61 @@ CSSParserImpl::ParseBoxProperty(nsCSSValue& aValue,
}
bool
+CSSParserImpl::ParseSingleValuePropertyByFunction(nsCSSValue& aValue,
+ nsCSSProperty aPropID)
+{
+ switch (aPropID) {
+ case eCSSProperty_font_family:
+ return ParseFamily(aValue);
+ case eCSSProperty_font_synthesis:
+ return ParseFontSynthesis(aValue);
+ case eCSSProperty_font_variant_alternates:
+ return ParseFontVariantAlternates(aValue);
+ case eCSSProperty_font_variant_east_asian:
+ return ParseFontVariantEastAsian(aValue);
+ case eCSSProperty_font_variant_ligatures:
+ return ParseFontVariantLigatures(aValue);
+ case eCSSProperty_font_variant_numeric:
+ return ParseFontVariantNumeric(aValue);
+ case eCSSProperty_font_feature_settings:
+ return ParseFontFeatureSettings(aValue);
+ case eCSSProperty_font_weight:
+ return ParseFontWeight(aValue);
+ case eCSSProperty_image_orientation:
+ return ParseImageOrientation(aValue);
+ case eCSSProperty_list_style_type:
+ return ParseListStyleType(aValue);
+ case eCSSProperty_marks:
+ return ParseMarks(aValue);
+ case eCSSProperty_scroll_snap_points_x:
+ return ParseScrollSnapPoints(aValue, eCSSProperty_scroll_snap_points_x);
+ case eCSSProperty_scroll_snap_points_y:
+ return ParseScrollSnapPoints(aValue, eCSSProperty_scroll_snap_points_y);
+ case eCSSProperty_scroll_snap_destination:
+ return ParseScrollSnapDestination(aValue);
+ case eCSSProperty_scroll_snap_coordinate:
+ return ParseScrollSnapCoordinate(aValue);
+ case eCSSProperty_text_align:
+ return ParseTextAlign(aValue);
+ case eCSSProperty_text_align_last:
+ return ParseTextAlignLast(aValue);
+ case eCSSProperty_text_decoration_line:
+ return ParseTextDecorationLine(aValue);
+ case eCSSProperty_text_combine_upright:
+ return ParseTextCombineUpright(aValue);
+ case eCSSProperty_text_overflow:
+ return ParseTextOverflow(aValue);
+ case eCSSProperty_touch_action:
+ return ParseTouchAction(aValue);
+ case eCSSProperty_contain:
+ return ParseContain(aValue);
+ default:
+ MOZ_ASSERT(false, "should not reach here");
+ return false;
+ }
+}
+
+CSSParseResult
CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
nsCSSProperty aPropID)
{
@@ -10488,76 +10773,39 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
if (aPropID < 0 || aPropID >= eCSSProperty_COUNT_no_shorthands) {
MOZ_ASSERT(false, "not a single value property");
- return false;
+ return CSSParseResult::NotFound;
}
if (nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_VALUE_PARSER_FUNCTION)) {
- switch (aPropID) {
- case eCSSProperty_font_family:
- return ParseFamily(aValue);
- case eCSSProperty_font_synthesis:
- return ParseFontSynthesis(aValue);
- case eCSSProperty_font_variant_alternates:
- return ParseFontVariantAlternates(aValue);
- case eCSSProperty_font_variant_east_asian:
- return ParseFontVariantEastAsian(aValue);
- case eCSSProperty_font_variant_ligatures:
- return ParseFontVariantLigatures(aValue);
- case eCSSProperty_font_variant_numeric:
- return ParseFontVariantNumeric(aValue);
- case eCSSProperty_font_feature_settings:
- return ParseFontFeatureSettings(aValue);
- case eCSSProperty_font_weight:
- return ParseFontWeight(aValue);
- case eCSSProperty_image_orientation:
- return ParseImageOrientation(aValue);
- case eCSSProperty_list_style_type:
- return ParseListStyleType(aValue);
- case eCSSProperty_marks:
- return ParseMarks(aValue);
- case eCSSProperty_scroll_snap_points_x:
- return ParseScrollSnapPoints(aValue, eCSSProperty_scroll_snap_points_x);
- case eCSSProperty_scroll_snap_points_y:
- return ParseScrollSnapPoints(aValue, eCSSProperty_scroll_snap_points_y);
- case eCSSProperty_scroll_snap_destination:
- return ParseScrollSnapDestination(aValue);
- case eCSSProperty_scroll_snap_coordinate:
- return ParseScrollSnapCoordinate(aValue);
- case eCSSProperty_text_align:
- return ParseTextAlign(aValue);
- case eCSSProperty_text_align_last:
- return ParseTextAlignLast(aValue);
- case eCSSProperty_text_decoration_line:
- return ParseTextDecorationLine(aValue);
- case eCSSProperty_text_combine_upright:
- return ParseTextCombineUpright(aValue);
- case eCSSProperty_text_overflow:
- return ParseTextOverflow(aValue);
- case eCSSProperty_touch_action:
- return ParseTouchAction(aValue);
- case eCSSProperty_contain:
- return ParseContain(aValue);
- default:
- MOZ_ASSERT(false, "should not reach here");
- return false;
+ uint32_t lineBefore, colBefore;
+ if (!GetNextTokenLocation(true, &lineBefore, &colBefore)) {
+ // We're at EOF before parsing.
+ return CSSParseResult::NotFound;
}
+
+ if (ParseSingleValuePropertyByFunction(aValue, aPropID)) {
+ return CSSParseResult::Ok;
+ }
+
+ uint32_t lineAfter, colAfter;
+ if (!GetNextTokenLocation(true, &lineAfter, &colAfter) ||
+ lineAfter != lineBefore ||
+ colAfter != colBefore) {
+ // Any single token value that was invalid will have been pushed back,
+ // so GetNextTokenLocation encountering EOF means we failed while
+ // parsing a multi-token value.
+ return CSSParseResult::Error;
+ }
+
+ return CSSParseResult::NotFound;
}
uint32_t variant = nsCSSProps::ParserVariant(aPropID);
if (variant == 0) {
MOZ_ASSERT(false, "not a single value property");
- return false;
+ return CSSParseResult::NotFound;
}
- // We only allow 'script-level' when unsafe rules are enabled, because
- // otherwise it could interfere with rulenode optimizations if used in
- // a non-MathML-enabled document. We also only allow math-display when
- // unsafe rules are enabled.
- if (!mUnsafeRulesEnabled &&
- (aPropID == eCSSProperty_script_level ||
- aPropID == eCSSProperty_math_display))
- return false;
-
const KTableValue* kwtable = nsCSSProps::kKeywordTableTable[aPropID];
uint32_t restrictions = nsCSSProps::ValueRestrictions(aPropID);
return ParseVariantWithRestrictions(aValue, variant, kwtable, restrictions);
@@ -10592,8 +10840,8 @@ CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID,
case eCSSFontDesc_Style:
// property is VARIANT_HMK|VARIANT_SYSFONT
- return ParseVariant(aValue, VARIANT_KEYWORD | VARIANT_NORMAL,
- nsCSSProps::kFontStyleKTable);
+ return ParseSingleTokenVariant(aValue, VARIANT_KEYWORD | VARIANT_NORMAL,
+ nsCSSProps::kFontStyleKTable);
case eCSSFontDesc_Weight:
return (ParseFontWeight(aValue) &&
@@ -10606,8 +10854,8 @@ CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID,
case eCSSFontDesc_Stretch:
// property is VARIANT_HK|VARIANT_SYSFONT
- return ParseVariant(aValue, VARIANT_KEYWORD,
- nsCSSProps::kFontStretchKTable);
+ return ParseSingleTokenVariant(aValue, VARIANT_KEYWORD,
+ nsCSSProps::kFontStretchKTable);
// These two are unique to @font-face and have their own special grammar.
case eCSSFontDesc_Src:
@@ -10620,7 +10868,8 @@ CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID,
return ParseFontFeatureSettings(aValue);
case eCSSFontDesc_FontLanguageOverride:
- return ParseVariant(aValue, VARIANT_NORMAL | VARIANT_STRING, nullptr);
+ return ParseSingleTokenVariant(aValue, VARIANT_NORMAL | VARIANT_STRING,
+ nullptr);
case eCSSFontDesc_UNKNOWN:
case eCSSFontDesc_COUNT:
@@ -10664,7 +10913,7 @@ CSSParserImpl::ParseBackground()
nsCSSValue color;
// Check first for inherit/initial/unset.
- if (ParseVariant(color, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(color, VARIANT_INHERIT, nullptr)) {
// must be alone
for (const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(eCSSProperty_background);
@@ -10726,6 +10975,35 @@ CSSParserImpl::ParseBackground()
return true;
}
+// Helper for ParseBackgroundItem. Returns true if the passed-in nsCSSToken is
+// a function which is accepted for background-image.
+bool
+CSSParserImpl::IsFunctionTokenValidForBackgroundImage(
+ const nsCSSToken& aToken) const
+{
+ MOZ_ASSERT(aToken.mType == eCSSToken_Function,
+ "Should only be called for function-typed tokens");
+
+ const nsAString& funcName = aToken.mIdent;
+
+ return funcName.LowerCaseEqualsLiteral("linear-gradient") ||
+ funcName.LowerCaseEqualsLiteral("radial-gradient") ||
+ funcName.LowerCaseEqualsLiteral("repeating-linear-gradient") ||
+ funcName.LowerCaseEqualsLiteral("repeating-radial-gradient") ||
+ funcName.LowerCaseEqualsLiteral("-moz-linear-gradient") ||
+ funcName.LowerCaseEqualsLiteral("-moz-radial-gradient") ||
+ funcName.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient") ||
+ funcName.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient") ||
+ funcName.LowerCaseEqualsLiteral("-moz-image-rect") ||
+ funcName.LowerCaseEqualsLiteral("-moz-element") ||
+ ((sWebkitPrefixedAliasesEnabled || ShouldUseUnprefixingService()) &&
+ (funcName.LowerCaseEqualsLiteral("-webkit-gradient") ||
+ funcName.LowerCaseEqualsLiteral("-webkit-linear-gradient") ||
+ funcName.LowerCaseEqualsLiteral("-webkit-radial-gradient") ||
+ funcName.LowerCaseEqualsLiteral("-webkit-repeating-linear-gradient") ||
+ funcName.LowerCaseEqualsLiteral("-webkit-repeating-radial-gradient")));
+}
+
// Parse one item of the background shorthand property.
bool
CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState)
@@ -10778,8 +11056,9 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState)
if (haveImage)
return false;
haveImage = true;
- if (!ParseSingleValueProperty(aState.mImage->mValue,
- eCSSProperty_background_image)) {
+ if (ParseSingleValueProperty(aState.mImage->mValue,
+ eCSSProperty_background_image) !=
+ CSSParseResult::Ok) {
NS_NOTREACHED("should be able to parse");
return false;
}
@@ -10788,8 +11067,9 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState)
if (haveAttach)
return false;
haveAttach = true;
- if (!ParseSingleValueProperty(aState.mAttachment->mValue,
- eCSSProperty_background_attachment)) {
+ if (ParseSingleValueProperty(aState.mAttachment->mValue,
+ eCSSProperty_background_attachment) !=
+ CSSParseResult::Ok) {
NS_NOTREACHED("should be able to parse");
return false;
}
@@ -10826,8 +11106,9 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState)
if (haveOrigin)
return false;
haveOrigin = true;
- if (!ParseSingleValueProperty(aState.mOrigin->mValue,
- eCSSProperty_background_origin)) {
+ if (ParseSingleValueProperty(aState.mOrigin->mValue,
+ eCSSProperty_background_origin) !=
+ CSSParseResult::Ok) {
NS_NOTREACHED("should be able to parse");
return false;
}
@@ -10850,8 +11131,13 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState)
NS_STYLE_BG_ORIGIN_CONTENT,
"bg-clip and bg-origin style constants must agree");
- if (!ParseSingleValueProperty(aState.mClip->mValue,
- eCSSProperty_background_clip)) {
+ CSSParseResult result =
+ ParseSingleValueProperty(aState.mClip->mValue,
+ eCSSProperty_background_clip);
+ MOZ_ASSERT(result != CSSParseResult::Error,
+ "how can failing to parse a single background-clip value "
+ "consume tokens?");
+ if (result == CSSParseResult::NotFound) {
// When exactly one value is set, it is used for both
// 'background-origin' and 'background-clip'.
// See assertions above showing these values are compatible.
@@ -10861,32 +11147,21 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState)
if (haveColor)
return false;
haveColor = true;
- if (!ParseSingleValueProperty(aState.mColor,
- eCSSProperty_background_color)) {
+ if (ParseSingleValueProperty(aState.mColor,
+ eCSSProperty_background_color) !=
+ CSSParseResult::Ok) {
return false;
}
}
} else if (tt == eCSSToken_URL ||
(tt == eCSSToken_Function &&
- (mToken.mIdent.LowerCaseEqualsLiteral("linear-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("radial-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("repeating-linear-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("repeating-radial-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("-moz-linear-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("-moz-image-rect") ||
- mToken.mIdent.LowerCaseEqualsLiteral("-moz-element") ||
- (ShouldUseUnprefixingService() &&
- (mToken.mIdent.LowerCaseEqualsLiteral("-webkit-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("-webkit-linear-gradient") ||
- mToken.mIdent.LowerCaseEqualsLiteral("-webkit-radial-gradient")))))) {
+ IsFunctionTokenValidForBackgroundImage(mToken))) {
if (haveImage)
return false;
haveImage = true;
- if (!ParseSingleValueProperty(aState.mImage->mValue,
- eCSSProperty_background_image)) {
+ if (ParseSingleValueProperty(aState.mImage->mValue,
+ eCSSProperty_background_image) !=
+ CSSParseResult::Ok) {
return false;
}
} else if (tt == eCSSToken_Dimension ||
@@ -10915,8 +11190,9 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState)
haveColor = true;
// Note: This parses 'inherit', 'initial' and 'unset', but
// we've already checked for them, so it's ok.
- if (!ParseSingleValueProperty(aState.mColor,
- eCSSProperty_background_color)) {
+ if (ParseSingleValueProperty(aState.mColor,
+ eCSSProperty_background_color) !=
+ CSSParseResult::Ok) {
return false;
}
}
@@ -10934,10 +11210,11 @@ CSSParserImpl::ParseValueList(nsCSSProperty aPropID)
// aPropID is a single value prop-id
nsCSSValue value;
// 'initial', 'inherit' and 'unset' stand alone, no list permitted.
- if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
nsCSSValueList* item = value.SetListValue();
for (;;) {
- if (!ParseSingleValueProperty(item->mValue, aPropID)) {
+ if (ParseSingleValueProperty(item->mValue, aPropID) !=
+ CSSParseResult::Ok) {
return false;
}
if (!ExpectSymbol(',', true)) {
@@ -10956,7 +11233,7 @@ CSSParserImpl::ParseBackgroundRepeat()
{
nsCSSValue value;
// 'initial', 'inherit' and 'unset' stand alone, no list permitted.
- if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
nsCSSValuePair valuePair;
if (!ParseBackgroundRepeatValues(valuePair)) {
return false;
@@ -11009,7 +11286,7 @@ CSSParserImpl::ParseBackgroundPosition()
{
nsCSSValue value;
// 'initial', 'inherit' and 'unset' stand alone, no list permitted.
- if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
nsCSSValue itemValue;
if (!ParsePositionValue(itemValue)) {
return false;
@@ -11057,7 +11334,10 @@ bool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut,
&yValue = aOut.mYValue;
int32_t variantMask =
(aAcceptsInherit ? VARIANT_INHERIT : 0) | VARIANT_LP | VARIANT_CALC;
- if (ParseVariant(xValue, variantMask, nullptr)) {
+ CSSParseResult result = ParseVariant(xValue, variantMask, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::Ok) {
if (eCSSUnit_Inherit == xValue.GetUnit() ||
eCSSUnit_Initial == xValue.GetUnit() ||
eCSSUnit_Unset == xValue.GetUnit()) { // both are inherit, initial or unset
@@ -11066,7 +11346,10 @@ bool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut,
}
// We have one percentage/length/calc. Get the optional second
// percentage/length/calc/keyword.
- if (ParseVariant(yValue, VARIANT_LP | VARIANT_CALC, nullptr)) {
+ result = ParseVariant(yValue, VARIANT_LP | VARIANT_CALC, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::Ok) {
// We have two numbers
return true;
}
@@ -11107,7 +11390,10 @@ bool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut,
}
else {
// Only one keyword. See if we have a length, percentage, or calc.
- if (ParseVariant(yValue, VARIANT_LP | VARIANT_CALC, nullptr)) {
+ result = ParseVariant(yValue, VARIANT_LP | VARIANT_CALC, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::Ok) {
if (!(mask & BG_CLR)) {
// The first keyword can only be 'center', 'left', or 'right'
return false;
@@ -11150,8 +11436,12 @@ CSSParserImpl::ParsePositionValue(nsCSSValue& aOut)
// Parse all the values into the array.
uint32_t valueCount = 0;
for (int32_t i = 0; i < 4; i++) {
- if (!ParseVariant(value->Item(i), VARIANT_LPCALC | VARIANT_KEYWORD,
- nsCSSProps::kBackgroundPositionKTable)) {
+ CSSParseResult result =
+ ParseVariant(value->Item(i), VARIANT_LPCALC | VARIANT_KEYWORD,
+ nsCSSProps::kBackgroundPositionKTable);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::NotFound) {
break;
}
++valueCount;
@@ -11314,7 +11604,7 @@ CSSParserImpl::ParseBackgroundSize()
{
nsCSSValue value;
// 'initial', 'inherit' and 'unset' stand alone, no list permitted.
- if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
nsCSSValuePair valuePair;
if (!ParseBackgroundSizeValues(valuePair)) {
return false;
@@ -11353,10 +11643,17 @@ bool CSSParserImpl::ParseBackgroundSizeValues(nsCSSValuePair &aOut)
// First try a percentage or a length value
nsCSSValue &xValue = aOut.mXValue,
&yValue = aOut.mYValue;
- if (ParseNonNegativeVariant(xValue, BG_SIZE_VARIANT, nullptr)) {
+ CSSParseResult result =
+ ParseNonNegativeVariant(xValue, BG_SIZE_VARIANT, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::Ok) {
// We have one percentage/length/calc/auto. Get the optional second
// percentage/length/calc/keyword.
- if (ParseNonNegativeVariant(yValue, BG_SIZE_VARIANT, nullptr)) {
+ result = ParseNonNegativeVariant(yValue, BG_SIZE_VARIANT, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::Ok) {
// We have a second percentage/length/calc/auto.
return true;
}
@@ -11430,7 +11727,8 @@ CSSParserImpl::ParseBorderImageSlice(bool aAcceptsInherit,
*aConsumedTokens = true;
}
- if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (aAcceptsInherit &&
+ ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
// Keywords "inherit", "initial" and "unset" can not be mixed, so we
// are done.
AppendValue(eCSSProperty_border_image_slice, value);
@@ -11479,7 +11777,8 @@ CSSParserImpl::ParseBorderImageWidth(bool aAcceptsInherit)
// border-image-width: initial | [|||auto]{1,4}
nsCSSValue value;
- if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (aAcceptsInherit &&
+ ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
// Keywords "inherit", "initial" and "unset" can not be mixed, so we
// are done.
AppendValue(eCSSProperty_border_image_width, value);
@@ -11501,7 +11800,8 @@ CSSParserImpl::ParseBorderImageOutset(bool aAcceptsInherit)
// border-image-outset: initial | [|]{1,4}
nsCSSValue value;
- if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (aAcceptsInherit &&
+ ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
// Keywords "inherit", "initial" and "unset" can not be mixed, so we
// are done.
AppendValue(eCSSProperty_border_image_outset, value);
@@ -11521,7 +11821,8 @@ bool
CSSParserImpl::ParseBorderImageRepeat(bool aAcceptsInherit)
{
nsCSSValue value;
- if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (aAcceptsInherit &&
+ ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
// Keywords "inherit", "initial" and "unset" can not be mixed, so we
// are done.
AppendValue(eCSSProperty_border_image_repeat, value);
@@ -11556,7 +11857,7 @@ CSSParserImpl::ParseBorderImage()
//
nsCSSValue value;
- if (ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
AppendValue(eCSSProperty_border_image_source, value);
AppendValue(eCSSProperty_border_image_slice, value);
AppendValue(eCSSProperty_border_image_width, value);
@@ -11584,11 +11885,13 @@ CSSParserImpl::ParseBorderImage()
while (!CheckEndProperty()) {
//
if (!foundSource) {
- nsAutoCSSParserInputStateRestorer stateRestorer(this);
- if (ParseVariant(imageSourceValue, VARIANT_IMAGE, nullptr)) {
+ CSSParseResult result =
+ ParseVariant(imageSourceValue, VARIANT_IMAGE, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::Ok) {
AppendValue(eCSSProperty_border_image_source, imageSourceValue);
foundSource = true;
- stateRestorer.DoNotRestore();
continue;
}
}
@@ -11645,14 +11948,18 @@ bool
CSSParserImpl::ParseBorderSpacing()
{
nsCSSValue xValue, yValue;
- if (!ParseNonNegativeVariant(xValue, VARIANT_HL | VARIANT_CALC, nullptr)) {
+ if (ParseNonNegativeVariant(xValue, VARIANT_HL | VARIANT_CALC, nullptr) !=
+ CSSParseResult::Ok) {
return false;
}
// If we have one length, get the optional second length.
// set the second value equal to the first.
if (xValue.IsLengthUnit() || xValue.IsCalcUnit()) {
- ParseNonNegativeVariant(yValue, VARIANT_LENGTH | VARIANT_CALC, nullptr);
+ if (ParseNonNegativeVariant(yValue, VARIANT_LENGTH | VARIANT_CALC,
+ nullptr) == CSSParseResult::Error) {
+ return false;
+ }
}
if (yValue == xValue || yValue.GetUnit() == eCSSUnit_Null) {
@@ -11753,11 +12060,12 @@ CSSParserImpl::ParseBorderColors(nsCSSProperty aProperty)
{
nsCSSValue value;
// 'inherit', 'initial', 'unset' and 'none' are only allowed on their own
- if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NONE,
+ nullptr)) {
nsCSSValueList *cur = value.SetListValue();
for (;;) {
- if (!ParseVariant(cur->mValue, VARIANT_COLOR | VARIANT_KEYWORD,
- nsCSSProps::kBorderColorKTable)) {
+ if (ParseVariant(cur->mValue, VARIANT_COLOR | VARIANT_KEYWORD,
+ nsCSSProps::kBorderColorKTable) != CSSParseResult::Ok) {
return false;
}
if (CheckEndProperty()) {
@@ -11996,7 +12304,8 @@ CSSParserImpl::ParseCalcTerm(nsCSSValue& aValue, int32_t& aVariantMask)
UngetToken();
// Always pass VARIANT_NUMBER to ParseVariant so that unitless zero
// always gets picked up
- if (!ParseVariant(aValue, aVariantMask | VARIANT_NUMBER, nullptr)) {
+ if (ParseVariant(aValue, aVariantMask | VARIANT_NUMBER, nullptr) !=
+ CSSParseResult::Ok) {
return false;
}
// ...and do the VARIANT_NUMBER check ourselves.
@@ -12037,7 +12346,7 @@ bool
CSSParserImpl::ParseRect(nsCSSProperty aPropID)
{
nsCSSValue val;
- if (ParseVariant(val, VARIANT_INHERIT | VARIANT_AUTO, nullptr)) {
+ if (ParseSingleTokenVariant(val, VARIANT_INHERIT | VARIANT_AUTO, nullptr)) {
AppendValue(aPropID, val);
return true;
}
@@ -12051,8 +12360,8 @@ CSSParserImpl::ParseRect(nsCSSProperty aPropID)
nsCSSRect& rect = val.SetRectValue();
bool useCommas;
NS_FOR_CSS_SIDES(side) {
- if (! ParseVariant(rect.*(nsCSSRect::sides[side]),
- VARIANT_AL, nullptr)) {
+ if (!ParseSingleTokenVariant(rect.*(nsCSSRect::sides[side]),
+ VARIANT_AL, nullptr)) {
return false;
}
if (side == 0) {
@@ -12152,11 +12461,12 @@ CSSParserImpl::ParseContent()
nsCSSValue value;
// 'inherit', 'initial', 'unset', 'normal', 'none', and 'alt-content' must
// be alone
- if (!ParseVariant(value, VARIANT_HMK | VARIANT_NONE,
- kContentSolitaryKWs)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_HMK | VARIANT_NONE,
+ kContentSolitaryKWs)) {
nsCSSValueList* cur = value.SetListValue();
for (;;) {
- if (!ParseVariant(cur->mValue, VARIANT_CONTENT, kContentListKWs)) {
+ if (ParseVariant(cur->mValue, VARIANT_CONTENT, kContentListKWs) !=
+ CSSParseResult::Ok) {
return false;
}
if (CheckEndProperty()) {
@@ -12178,7 +12488,8 @@ CSSParserImpl::ParseCounterData(nsCSSProperty aPropID)
eCSSKeyword_UNKNOWN
};
nsCSSValue value;
- if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NONE,
+ nullptr)) {
if (!GetToken(true)) {
return false;
}
@@ -12220,10 +12531,11 @@ CSSParserImpl::ParseCursor()
{
nsCSSValue value;
// 'inherit', 'initial' and 'unset' must be alone
- if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
nsCSSValueList* cur = value.SetListValue();
for (;;) {
- if (!ParseVariant(cur->mValue, VARIANT_UK, nsCSSProps::kCursorKTable)) {
+ if (!ParseSingleTokenVariant(cur->mValue, VARIANT_UK,
+ nsCSSProps::kCursorKTable)) {
return false;
}
if (cur->mValue.GetUnit() != eCSSUnit_URL) { // keyword must be last
@@ -12235,9 +12547,9 @@ CSSParserImpl::ParseCursor()
val->Item(0) = cur->mValue;
// Parse optional x and y position of cursor hotspot (css3-ui).
- if (ParseVariant(val->Item(1), VARIANT_NUMBER, nullptr)) {
+ if (ParseSingleTokenVariant(val->Item(1), VARIANT_NUMBER, nullptr)) {
// If we have one number, we must have two.
- if (!ParseVariant(val->Item(2), VARIANT_NUMBER, nullptr)) {
+ if (!ParseSingleTokenVariant(val->Item(2), VARIANT_NUMBER, nullptr)) {
return false;
}
}
@@ -12259,7 +12571,7 @@ bool
CSSParserImpl::ParseFont()
{
nsCSSValue family;
- if (ParseVariant(family, VARIANT_HK, nsCSSProps::kFontKTable)) {
+ if (ParseSingleTokenVariant(family, VARIANT_HK, nsCSSProps::kFontKTable)) {
if (eCSSUnit_Inherit == family.GetUnit() ||
eCSSUnit_Initial == family.GetUnit() ||
eCSSUnit_Unset == family.GetUnit()) {
@@ -12364,17 +12676,18 @@ CSSParserImpl::ParseFont()
// Get mandatory font-size
nsCSSValue size;
- if (! ParseNonNegativeVariant(size, VARIANT_KEYWORD | VARIANT_LP,
- nsCSSProps::kFontSizeKTable)) {
+ if (!ParseSingleTokenNonNegativeVariant(size, VARIANT_KEYWORD | VARIANT_LP,
+ nsCSSProps::kFontSizeKTable)) {
return false;
}
// Get optional "/" line-height
nsCSSValue lineHeight;
if (ExpectSymbol('/', true)) {
- if (! ParseNonNegativeVariant(lineHeight,
- VARIANT_NUMBER | VARIANT_LP | VARIANT_NORMAL,
- nullptr)) {
+ if (!ParseSingleTokenNonNegativeVariant(lineHeight,
+ VARIANT_NUMBER | VARIANT_LP |
+ VARIANT_NORMAL,
+ nullptr)) {
return false;
}
}
@@ -12423,8 +12736,8 @@ CSSParserImpl::ParseFont()
bool
CSSParserImpl::ParseFontSynthesis(nsCSSValue& aValue)
{
- if (!ParseVariant(aValue, VARIANT_HK | VARIANT_NONE,
- nsCSSProps::kFontSynthesisKTable)) {
+ if (!ParseSingleTokenVariant(aValue, VARIANT_HK | VARIANT_NONE,
+ nsCSSProps::kFontSynthesisKTable)) {
return false;
}
@@ -12532,7 +12845,8 @@ CSSParserImpl::ParseSingleAlternate(int32_t& aWhichFeature,
bool
CSSParserImpl::ParseFontVariantAlternates(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL,
+ nullptr)) {
return true;
}
@@ -12646,7 +12960,8 @@ static const int32_t maskEastAsian[] = {
bool
CSSParserImpl::ParseFontVariantEastAsian(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL,
+ nullptr)) {
return true;
}
@@ -12661,7 +12976,8 @@ CSSParserImpl::ParseFontVariantEastAsian(nsCSSValue& aValue)
bool
CSSParserImpl::ParseContain(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT | VARIANT_NONE,
+ nullptr)) {
return true;
}
static const int32_t maskContain[] = { MASK_END_VALUE };
@@ -12692,9 +13008,9 @@ static const int32_t maskLigatures[] = {
bool
CSSParserImpl::ParseFontVariantLigatures(nsCSSValue& aValue)
{
- if (ParseVariant(aValue,
- VARIANT_INHERIT | VARIANT_NORMAL | VARIANT_NONE,
- nullptr)) {
+ if (ParseSingleTokenVariant(aValue,
+ VARIANT_INHERIT | VARIANT_NORMAL | VARIANT_NONE,
+ nullptr)) {
return true;
}
@@ -12716,7 +13032,8 @@ static const int32_t maskNumeric[] = {
bool
CSSParserImpl::ParseFontVariantNumeric(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL,
+ nullptr)) {
return true;
}
@@ -12735,9 +13052,9 @@ CSSParserImpl::ParseFontVariant()
nsCSSValue value;
nsCSSValue normal(eCSSUnit_Normal);
- if (ParseVariant(value,
- VARIANT_INHERIT | VARIANT_NORMAL | VARIANT_NONE,
- nullptr)) {
+ if (ParseSingleTokenVariant(value,
+ VARIANT_INHERIT | VARIANT_NORMAL | VARIANT_NONE,
+ nullptr)) {
AppendValue(eCSSProperty_font_variant_ligatures, value);
if (eCSSUnit_None == value.GetUnit()) {
// 'none' applies the value 'normal' to all properties other
@@ -12919,8 +13236,8 @@ CSSParserImpl::ParseFontVariant()
bool
CSSParserImpl::ParseFontWeight(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_HKI | VARIANT_SYSFONT,
- nsCSSProps::kFontWeightKTable)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_HKI | VARIANT_SYSFONT,
+ nsCSSProps::kFontWeightKTable)) {
if (eCSSUnit_Integer == aValue.GetUnit()) { // ensure unit value
int32_t intValue = aValue.GetIntValue();
if ((100 <= intValue) &&
@@ -13300,7 +13617,8 @@ ValidFontFeatureTag(const nsString& aTag)
bool
CSSParserImpl::ParseFontFeatureSettings(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL,
+ nullptr)) {
return true;
}
@@ -13411,7 +13729,8 @@ CSSParserImpl::ParseListStyle()
bool
CSSParserImpl::ParseListStyleType(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_STRING, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT | VARIANT_STRING,
+ nullptr)) {
return true;
}
@@ -13438,7 +13757,8 @@ CSSParserImpl::ParseMargin()
bool
CSSParserImpl::ParseMarks(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_HK, nsCSSProps::kPageMarksKTable)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_HK,
+ nsCSSProps::kPageMarksKTable)) {
if (eCSSUnit_Enumerated == aValue.GetUnit()) {
if (NS_STYLE_PAGE_MARKS_NONE != aValue.GetIntValue() &&
false == CheckEndProperty()) {
@@ -13463,7 +13783,7 @@ bool
CSSParserImpl::ParseObjectPosition()
{
nsCSSValue value;
- if (!ParseVariant(value, VARIANT_INHERIT, nullptr) &&
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr) &&
!ParsePositionValue(value)) {
return false;
}
@@ -13509,7 +13829,8 @@ bool
CSSParserImpl::ParseOverflow()
{
nsCSSValue overflow;
- if (!ParseVariant(overflow, VARIANT_HK, nsCSSProps::kOverflowKTable)) {
+ if (!ParseSingleTokenVariant(overflow, VARIANT_HK,
+ nsCSSProps::kOverflowKTable)) {
return false;
}
@@ -13548,7 +13869,7 @@ bool
CSSParserImpl::ParseQuotes()
{
nsCSSValue value;
- if (!ParseVariant(value, VARIANT_HOS, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_HOS, nullptr)) {
return false;
}
if (value.GetUnit() == eCSSUnit_String) {
@@ -13557,11 +13878,11 @@ CSSParserImpl::ParseQuotes()
for (;;) {
quotes->mXValue = open;
// get mandatory close
- if (!ParseVariant(quotes->mYValue, VARIANT_STRING, nullptr)) {
+ if (!ParseSingleTokenVariant(quotes->mYValue, VARIANT_STRING, nullptr)) {
return false;
}
// look for another open
- if (!ParseVariant(open, VARIANT_STRING, nullptr)) {
+ if (!ParseSingleTokenVariant(open, VARIANT_STRING, nullptr)) {
break;
}
quotes->mNext = new nsCSSValuePairList;
@@ -13576,11 +13897,12 @@ bool
CSSParserImpl::ParseSize()
{
nsCSSValue width, height;
- if (!ParseVariant(width, VARIANT_AHKL, nsCSSProps::kPageSizeKTable)) {
+ if (!ParseSingleTokenVariant(width, VARIANT_AHKL,
+ nsCSSProps::kPageSizeKTable)) {
return false;
}
if (width.IsLengthUnit()) {
- ParseVariant(height, VARIANT_LENGTH, nullptr);
+ ParseSingleTokenVariant(height, VARIANT_LENGTH, nullptr);
}
if (width == height || height.GetUnit() == eCSSUnit_Null) {
@@ -13632,13 +13954,13 @@ CSSParserImpl::ParseTextDecoration()
bool
CSSParserImpl::ParseTextAlign(nsCSSValue& aValue, const KTableValue aTable[])
{
- if (ParseVariant(aValue, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT, nullptr)) {
// 'inherit', 'initial' and 'unset' must be alone
return true;
}
nsCSSValue left;
- if (!ParseVariant(left, VARIANT_KEYWORD, aTable)) {
+ if (!ParseSingleTokenVariant(left, VARIANT_KEYWORD, aTable)) {
return false;
}
@@ -13648,7 +13970,7 @@ CSSParserImpl::ParseTextAlign(nsCSSValue& aValue, const KTableValue aTable[])
}
nsCSSValue right;
- if (ParseVariant(right, VARIANT_KEYWORD, aTable)) {
+ if (ParseSingleTokenVariant(right, VARIANT_KEYWORD, aTable)) {
// 'true' must be combined with some other value than 'true'.
if (left.GetIntValue() == NS_STYLE_TEXT_ALIGN_UNSAFE &&
right.GetIntValue() == NS_STYLE_TEXT_ALIGN_UNSAFE) {
@@ -13693,7 +14015,8 @@ CSSParserImpl::ParseTextDecorationLine(nsCSSValue& aValue)
NS_STYLE_TEXT_DECORATION_LINE_BLINK |
NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS),
"text decoration constants need to be bitmasks");
- if (ParseVariant(aValue, VARIANT_HK, nsCSSProps::kTextDecorationLineKTable)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_HK,
+ nsCSSProps::kTextDecorationLineKTable)) {
if (eCSSUnit_Enumerated == aValue.GetUnit()) {
int32_t intValue = aValue.GetIntValue();
if (intValue != NS_STYLE_TEXT_DECORATION_LINE_NONE) {
@@ -13726,19 +14049,19 @@ CSSParserImpl::ParseTextDecorationLine(nsCSSValue& aValue)
bool
CSSParserImpl::ParseTextOverflow(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT, nullptr)) {
// 'inherit', 'initial' and 'unset' must be alone
return true;
}
nsCSSValue left;
- if (!ParseVariant(left, VARIANT_KEYWORD | VARIANT_STRING,
- nsCSSProps::kTextOverflowKTable))
+ if (!ParseSingleTokenVariant(left, VARIANT_KEYWORD | VARIANT_STRING,
+ nsCSSProps::kTextOverflowKTable))
return false;
nsCSSValue right;
- if (ParseVariant(right, VARIANT_KEYWORD | VARIANT_STRING,
- nsCSSProps::kTextOverflowKTable))
+ if (ParseSingleTokenVariant(right, VARIANT_KEYWORD | VARIANT_STRING,
+ nsCSSProps::kTextOverflowKTable))
aValue.SetPairValue(left, right);
else {
aValue = left;
@@ -13752,7 +14075,8 @@ CSSParserImpl::ParseTouchAction(nsCSSValue& aValue)
// Avaliable values of property touch-action:
// auto | none | [pan-x || pan-y] | manipulation
- if (!ParseVariant(aValue, VARIANT_HK, nsCSSProps::kTouchActionKTable)) {
+ if (!ParseSingleTokenVariant(aValue, VARIANT_HK,
+ nsCSSProps::kTouchActionKTable)) {
return false;
}
@@ -13788,8 +14112,8 @@ CSSParserImpl::ParseTouchAction(nsCSSValue& aValue)
bool
CSSParserImpl::ParseTextCombineUpright(nsCSSValue& aValue)
{
- if (!ParseVariant(aValue, VARIANT_HK,
- nsCSSProps::kTextCombineUprightKTable)) {
+ if (!ParseSingleTokenVariant(aValue, VARIANT_HK,
+ nsCSSProps::kTextCombineUprightKTable)) {
return false;
}
@@ -13843,7 +14167,7 @@ CSSParserImpl::ParseFunctionInternals(const int32_t aVariantMask[],
for (uint16_t index = 0; index < aMaxElems; ++index) {
nsCSSValue newValue;
int32_t m = aVariantMaskAll ? aVariantMaskAll : aVariantMask[index];
- if (!ParseVariant(newValue, m, nullptr)) {
+ if (ParseVariant(newValue, m, nullptr) != CSSParseResult::Ok) {
break;
}
@@ -14135,7 +14459,7 @@ bool CSSParserImpl::ParseWillChange()
VARIANT_ALL |
VARIANT_AUTO;
nsCSSValue value;
- if (!ParseVariant(value, variantMask, nullptr)) {
+ if (!ParseSingleTokenVariant(value, variantMask, nullptr)) {
return false;
}
@@ -14206,7 +14530,8 @@ bool CSSParserImpl::ParseTransform(bool aIsPrefixed)
{
nsCSSValue value;
// 'inherit', 'initial', 'unset' and 'none' must be alone
- if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NONE,
+ nullptr)) {
nsCSSValueSharedList* list = new nsCSSValueSharedList;
value.SetSharedListValue(list);
list->mHead = new nsCSSValueList;
@@ -14249,8 +14574,8 @@ CSSParserImpl::ParsePolygonFunction(nsCSSValue& aValue)
nsCSSValuePairList* item = coordinates.SetPairListValue();
for (;;) {
nsCSSValue xValue, yValue;
- if (!ParseVariant(xValue, VARIANT_LPCALC, nullptr) ||
- !ParseVariant(yValue, VARIANT_LPCALC, nullptr)) {
+ if (ParseVariant(xValue, VARIANT_LPCALC, nullptr) != CSSParseResult::Ok ||
+ ParseVariant(yValue, VARIANT_LPCALC, nullptr) != CSSParseResult::Ok) {
REPORT_UNEXPECTED_TOKEN(PECoordinatePair);
SkipUntil(')');
return false;
@@ -14291,9 +14616,14 @@ CSSParserImpl::ParseCircleOrEllipseFunction(nsCSSKeyword aKeyword,
int32_t mask = VARIANT_LPCALC | VARIANT_NONNEGATIVE_DIMENSION |
VARIANT_KEYWORD;
- if (ParseVariant(radiusX, mask, nsCSSProps::kShapeRadiusKTable)) {
+ CSSParseResult result =
+ ParseVariant(radiusX, mask, nsCSSProps::kShapeRadiusKTable);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::Ok) {
if (aKeyword == eCSSKeyword_ellipse) {
- if (!ParseVariant(radiusY, mask, nsCSSProps::kShapeRadiusKTable)) {
+ if (ParseVariant(radiusY, mask, nsCSSProps::kShapeRadiusKTable) !=
+ CSSParseResult::Ok) {
REPORT_UNEXPECTED_TOKEN(PEExpectedRadius);
SkipUntil(')');
return false;
@@ -14345,12 +14675,20 @@ CSSParserImpl::ParseInsetFunction(nsCSSValue& aValue)
RefPtr functionArray =
aValue.InitFunction(eCSSKeyword_inset, 5);
- if (ParseVariant(functionArray->Item(1), VARIANT_LPCALC, nullptr)) {
- // Consume up to 4, but only require one.
- ParseVariant(functionArray->Item(2), VARIANT_LPCALC, nullptr) &&
- ParseVariant(functionArray->Item(3), VARIANT_LPCALC, nullptr) &&
- ParseVariant(functionArray->Item(4), VARIANT_LPCALC, nullptr);
- } else {
+ int count = 0;
+ while (count < 4) {
+ CSSParseResult result =
+ ParseVariant(functionArray->Item(count + 1), VARIANT_LPCALC, nullptr);
+ if (result == CSSParseResult::Error) {
+ count = 0;
+ break;
+ } else if (result == CSSParseResult::NotFound) {
+ break;
+ }
+ ++count;
+ }
+
+ if (count == 0) {
REPORT_UNEXPECTED_TOKEN(PEExpectedShapeArg);
SkipUntil(')');
return false;
@@ -14414,7 +14752,7 @@ CSSParserImpl::ParseBasicShape(nsCSSValue& aValue, bool* aConsumedTokens)
bool CSSParserImpl::ParseClipPath()
{
nsCSSValue value;
- if (!ParseVariant(value, VARIANT_HUO, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_HUO, nullptr)) {
if (!nsLayoutUtils::CSSClipPathShapesEnabled()) {
// With CSS Clip Path Shapes disabled, we should only accept
// SVG clipPath reference and none.
@@ -14489,7 +14827,11 @@ bool CSSParserImpl::ParseTransformOrigin(bool aPerspective)
value.SetPairValue(position.mXValue, position.mYValue);
} else {
nsCSSValue depth;
- if (!ParseVariant(depth, VARIANT_LENGTH | VARIANT_CALC, nullptr)) {
+ CSSParseResult result =
+ ParseVariant(depth, VARIANT_LENGTH | VARIANT_CALC, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::NotFound) {
depth.SetFloatValue(0.0f, eCSSUnit_Pixel);
}
value.SetTripletValue(position.mXValue, position.mYValue, depth);
@@ -14533,7 +14875,7 @@ CSSParserImpl::ParseDropShadow(nsCSSValue* aValue)
bool
CSSParserImpl::ParseSingleFilter(nsCSSValue* aValue)
{
- if (ParseVariant(*aValue, VARIANT_URL, nullptr)) {
+ if (ParseSingleTokenVariant(*aValue, VARIANT_URL, nullptr)) {
return true;
}
@@ -14655,7 +14997,8 @@ CSSParserImpl::ParseFilter()
{
nsCSSValue value;
// 'inherit', 'initial', 'unset' and 'none' must be alone
- if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NONE,
+ nullptr)) {
nsCSSValueList* cur = value.SetListValue();
while (cur) {
if (!ParseSingleFilter(&cur->mValue)) {
@@ -14683,14 +15026,17 @@ CSSParserImpl::ParseTransitionProperty()
{
nsCSSValue value;
// 'inherit', 'initial', 'unset' and 'none' must be alone
- if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NONE,
+ nullptr)) {
// Accept a list of arbitrary identifiers. They should be
// CSS properties, but we want to accept any so that we
// accept properties that we don't know about yet, e.g.
// transition-property: invalid-property, left, opacity;
nsCSSValueList* cur = value.SetListValue();
for (;;) {
- if (!ParseVariant(cur->mValue, VARIANT_IDENTIFIER | VARIANT_ALL, nullptr)) {
+ if (!ParseSingleTokenVariant(cur->mValue,
+ VARIANT_IDENTIFIER | VARIANT_ALL,
+ nullptr)) {
return false;
}
if (cur->mValue.GetUnit() == eCSSUnit_Ident) {
@@ -14776,7 +15122,8 @@ CSSParserImpl::ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue)
RefPtr val = nsCSSValue::Array::Create(2);
- if (!ParseOneOrLargerVariant(val->Item(0), VARIANT_INTEGER, nullptr)) {
+ if (!ParseSingleTokenOneOrLargerVariant(val->Item(0), VARIANT_INTEGER,
+ nullptr)) {
return false;
}
@@ -14837,7 +15184,7 @@ CSSParserImpl::ParseAnimationOrTransitionShorthand(
// first see if 'inherit', 'initial' or 'unset' is specified. If one is,
// it can be the only thing specified, so don't attempt to parse any
// additional properties
- if (ParseVariant(tempValue, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(tempValue, VARIANT_INHERIT, nullptr)) {
for (uint32_t i = 0; i < aNumProperties; ++i) {
AppendValue(aProperties[i], tempValue);
}
@@ -14877,7 +15224,12 @@ CSSParserImpl::ParseAnimationOrTransitionShorthand(
for (uint32_t i = 0; !foundProperty && i < aNumProperties; ++i) {
if (!parsedProperty[i]) {
// if we haven't found this property yet, try to parse it
- if (ParseSingleValueProperty(tempValue, aProperties[i])) {
+ CSSParseResult result =
+ ParseSingleValueProperty(tempValue, aProperties[i]);
+ if (result == CSSParseResult::Error) {
+ return eParseAnimationOrTransitionShorthand_Error;
+ }
+ if (result == CSSParseResult::Ok) {
parsedProperty[i] = true;
cur[i] = AppendValueToList(aValues[i], cur[i], tempValue);
foundProperty = true;
@@ -15063,14 +15415,14 @@ CSSParserImpl::ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow)
if (aIsBoxShadow) {
// Optional inset keyword (ignore errors)
- ParseVariant(val->Item(IndexInset), VARIANT_KEYWORD,
- nsCSSProps::kBoxShadowTypeKTable);
+ ParseSingleTokenVariant(val->Item(IndexInset), VARIANT_KEYWORD,
+ nsCSSProps::kBoxShadowTypeKTable);
}
nsCSSValue xOrColor;
bool haveColor = false;
- if (!ParseVariant(xOrColor, VARIANT_COLOR | VARIANT_LENGTH | VARIANT_CALC,
- nullptr)) {
+ if (ParseVariant(xOrColor, VARIANT_COLOR | VARIANT_LENGTH | VARIANT_CALC,
+ nullptr) != CSSParseResult::Ok) {
return false;
}
if (xOrColor.IsLengthUnit() || xOrColor.IsCalcUnit()) {
@@ -15085,15 +15437,15 @@ CSSParserImpl::ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow)
haveColor = true;
// X coordinate mandatory after color
- if (!ParseVariant(val->Item(IndexX), VARIANT_LENGTH | VARIANT_CALC,
- nullptr)) {
+ if (ParseVariant(val->Item(IndexX), VARIANT_LENGTH | VARIANT_CALC,
+ nullptr) != CSSParseResult::Ok) {
return false;
}
}
// Y coordinate; mandatory
- if (!ParseVariant(val->Item(IndexY), VARIANT_LENGTH | VARIANT_CALC,
- nullptr)) {
+ if (ParseVariant(val->Item(IndexY), VARIANT_LENGTH | VARIANT_CALC,
+ nullptr) != CSSParseResult::Ok) {
return false;
}
@@ -15101,27 +15453,38 @@ CSSParserImpl::ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow)
// value which we must reject. If we use ParseNonNegativeVariant
// we can't tell the difference between an unspecified radius
// and a negative radius.
- if (ParseVariant(val->Item(IndexRadius), VARIANT_LENGTH | VARIANT_CALC,
- nullptr) &&
- val->Item(IndexRadius).IsLengthUnit() &&
- val->Item(IndexRadius).GetFloatValue() < 0) {
+ CSSParseResult result =
+ ParseVariant(val->Item(IndexRadius), VARIANT_LENGTH | VARIANT_CALC,
+ nullptr);
+ if (result == CSSParseResult::Error) {
return false;
+ } else if (result == CSSParseResult::Ok) {
+ if (val->Item(IndexRadius).IsLengthUnit() &&
+ val->Item(IndexRadius).GetFloatValue() < 0) {
+ return false;
+ }
}
if (aIsBoxShadow) {
// Optional spread
- ParseVariant(val->Item(IndexSpread), VARIANT_LENGTH | VARIANT_CALC, nullptr);
+ if (ParseVariant(val->Item(IndexSpread), VARIANT_LENGTH | VARIANT_CALC,
+ nullptr) == CSSParseResult::Error) {
+ return false;
+ }
}
if (!haveColor) {
// Optional color
- ParseVariant(val->Item(IndexColor), VARIANT_COLOR, nullptr);
+ if (ParseVariant(val->Item(IndexColor), VARIANT_COLOR, nullptr) ==
+ CSSParseResult::Error) {
+ return false;
+ }
}
if (aIsBoxShadow && val->Item(IndexInset).GetUnit() == eCSSUnit_Null) {
// Optional inset keyword
- ParseVariant(val->Item(IndexInset), VARIANT_KEYWORD,
- nsCSSProps::kBoxShadowTypeKTable);
+ ParseSingleTokenVariant(val->Item(IndexInset), VARIANT_KEYWORD,
+ nsCSSProps::kBoxShadowTypeKTable);
}
aValue.SetArrayValue(val, eCSSUnit_Array);
@@ -15136,7 +15499,8 @@ CSSParserImpl::ParseShadowList(nsCSSProperty aProperty)
nsCSSValue value;
// 'inherit', 'initial', 'unset' and 'none' must be alone
- if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NONE,
+ nullptr)) {
nsCSSValueList* cur = value.SetListValue();
for (;;) {
if (!ParseShadowItem(cur->mValue, isBoxShadow)) {
@@ -15188,17 +15552,22 @@ CSSParserImpl::ParsePaint(nsCSSProperty aPropID)
{
nsCSSValue x, y;
- if (!ParseVariant(x, VARIANT_HC | VARIANT_NONE | VARIANT_URL |
- VARIANT_OPENTYPE_SVG_KEYWORD,
- nsCSSProps::kContextPatternKTable)) {
+ if (ParseVariant(x, VARIANT_HC | VARIANT_NONE | VARIANT_URL |
+ VARIANT_OPENTYPE_SVG_KEYWORD,
+ nsCSSProps::kContextPatternKTable) != CSSParseResult::Ok) {
return false;
}
bool canHaveFallback = x.GetUnit() == eCSSUnit_URL ||
x.GetUnit() == eCSSUnit_Enumerated;
if (canHaveFallback) {
- if (!ParseVariant(y, VARIANT_COLOR | VARIANT_NONE, nullptr))
+ CSSParseResult result =
+ ParseVariant(y, VARIANT_COLOR | VARIANT_NONE, nullptr);
+ if (result == CSSParseResult::Error) {
+ return false;
+ } else if (result == CSSParseResult::NotFound) {
y.SetNoneValue();
+ }
}
if (!canHaveFallback) {
@@ -15217,12 +15586,13 @@ CSSParserImpl::ParseDasharray()
nsCSSValue value;
// 'inherit', 'initial', 'unset' and 'none' are only allowed on their own
- if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE |
- VARIANT_OPENTYPE_SVG_KEYWORD,
- nsCSSProps::kStrokeContextValueKTable)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NONE |
+ VARIANT_OPENTYPE_SVG_KEYWORD,
+ nsCSSProps::kStrokeContextValueKTable)) {
nsCSSValueList *cur = value.SetListValue();
for (;;) {
- if (!ParseNonNegativeVariant(cur->mValue, VARIANT_LPN, nullptr)) {
+ if (!ParseSingleTokenNonNegativeVariant(cur->mValue, VARIANT_LPN,
+ nullptr)) {
return false;
}
if (CheckEndProperty()) {
@@ -15243,7 +15613,8 @@ bool
CSSParserImpl::ParseMarker()
{
nsCSSValue marker;
- if (ParseSingleValueProperty(marker, eCSSProperty_marker_end)) {
+ if (ParseSingleValueProperty(marker, eCSSProperty_marker_end) ==
+ CSSParseResult::Ok) {
AppendValue(eCSSProperty_marker_end, marker);
AppendValue(eCSSProperty_marker_mid, marker);
AppendValue(eCSSProperty_marker_start, marker);
@@ -15272,7 +15643,7 @@ CSSParserImpl::ParsePaintOrder()
"missing paint-order values in kPaintOrderKTable");
nsCSSValue value;
- if (!ParseVariant(value, VARIANT_HK, kPaintOrderKTable)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_HK, kPaintOrderKTable)) {
return false;
}
@@ -15353,7 +15724,7 @@ bool
CSSParserImpl::ParseAll()
{
nsCSSValue value;
- if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
return false;
}
@@ -15430,7 +15801,8 @@ bool
CSSParserImpl::ParseScrollSnapType()
{
nsCSSValue value;
- if (!ParseVariant(value, VARIANT_HK, nsCSSProps::kScrollSnapTypeKTable)) {
+ if (!ParseSingleTokenVariant(value, VARIANT_HK,
+ nsCSSProps::kScrollSnapTypeKTable)) {
return false;
}
AppendValue(eCSSProperty_scroll_snap_type_x, value);
@@ -15441,7 +15813,8 @@ CSSParserImpl::ParseScrollSnapType()
bool
CSSParserImpl::ParseScrollSnapPoints(nsCSSValue& aValue, nsCSSProperty aPropID)
{
- if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT | VARIANT_NONE,
+ nullptr)) {
return true;
}
if (!GetToken(true)) {
@@ -15450,9 +15823,9 @@ CSSParserImpl::ParseScrollSnapPoints(nsCSSValue& aValue, nsCSSProperty aPropID)
if (mToken.mType == eCSSToken_Function &&
nsCSSKeywords::LookupKeyword(mToken.mIdent) == eCSSKeyword_repeat) {
nsCSSValue lengthValue;
- if (!ParseNonNegativeVariant(lengthValue,
- VARIANT_LENGTH | VARIANT_PERCENT | VARIANT_CALC,
- nullptr)) {
+ if (ParseNonNegativeVariant(lengthValue,
+ VARIANT_LENGTH | VARIANT_PERCENT | VARIANT_CALC,
+ nullptr) != CSSParseResult::Ok) {
REPORT_UNEXPECTED(PEExpectedNonnegativeNP);
SkipUntil(')');
return false;
@@ -15475,7 +15848,7 @@ CSSParserImpl::ParseScrollSnapPoints(nsCSSValue& aValue, nsCSSProperty aPropID)
bool
CSSParserImpl::ParseScrollSnapDestination(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT, nullptr)) {
return true;
}
nsCSSValue itemValue;
@@ -15491,7 +15864,8 @@ CSSParserImpl::ParseScrollSnapDestination(nsCSSValue& aValue)
bool
CSSParserImpl::ParseScrollSnapCoordinate(nsCSSValue& aValue)
{
- if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
+ if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT | VARIANT_NONE,
+ nullptr)) {
return true;
}
nsCSSValue itemValue;
@@ -15802,6 +16176,8 @@ nsCSSParser::Startup()
{
Preferences::AddBoolVarCache(&sOpentypeSVGEnabled,
"gfx.font_rendering.opentype_svg.enabled");
+ Preferences::AddBoolVarCache(&sWebkitPrefixedAliasesEnabled,
+ "layout.css.prefixes.webkit");
Preferences::AddBoolVarCache(&sUnprefixingServiceEnabled,
"layout.css.unprefixing-service.enabled");
#ifdef NIGHTLY_BUILD
@@ -15810,6 +16186,8 @@ nsCSSParser::Startup()
#endif
Preferences::AddBoolVarCache(&sMozGradientsEnabled,
"layout.css.prefixes.gradients");
+ Preferences::AddBoolVarCache(&sControlCharVisibility,
+ "layout.css.control-characters.visible");
}
nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
@@ -15885,11 +16263,12 @@ nsCSSParser::ParseSheet(const nsAString& aInput,
nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal,
uint32_t aLineNumber,
- bool aAllowUnsafeRules)
+ bool aAllowUnsafeRules,
+ LoaderReusableStyleSheets* aReusableSheets)
{
return static_cast(mImpl)->
ParseSheet(aInput, aSheetURI, aBaseURI, aSheetPrincipal, aLineNumber,
- aAllowUnsafeRules);
+ aAllowUnsafeRules, aReusableSheets);
}
nsresult
@@ -15945,6 +16324,19 @@ nsCSSParser::ParseProperty(const nsCSSProperty aPropID,
aIsImportant, aIsSVGMode);
}
+void
+nsCSSParser::ParseLonghandProperty(const nsCSSProperty aPropID,
+ const nsAString& aPropValue,
+ nsIURI* aSheetURI,
+ nsIURI* aBaseURI,
+ nsIPrincipal* aSheetPrincipal,
+ nsCSSValue& aResult)
+{
+ static_cast(mImpl)->
+ ParseLonghandProperty(aPropID, aPropValue, aSheetURI, aBaseURI,
+ aSheetPrincipal, aResult);
+}
+
void
nsCSSParser::ParseVariable(const nsAString& aVariableName,
const nsAString& aPropValue,
@@ -16141,3 +16533,12 @@ nsCSSParser::IsValueValidForProperty(const nsCSSProperty aPropID,
return static_cast(mImpl)->
IsValueValidForProperty(aPropID, aPropValue);
}
+
+/* static */
+uint8_t
+nsCSSParser::ControlCharVisibilityDefault()
+{
+ return sControlCharVisibility
+ ? NS_STYLE_CONTROL_CHARACTER_VISIBILITY_VISIBLE
+ : NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN;
+}
diff --git a/layout/style/nsCSSParser.h b/layout/style/nsCSSParser.h
index 8be66ed8f5..34ad931a1e 100644
--- a/layout/style/nsCSSParser.h
+++ b/layout/style/nsCSSParser.h
@@ -33,6 +33,7 @@ namespace css {
class Rule;
class Declaration;
class Loader;
+class LoaderReusableStyleSheets;
class StyleRule;
} // namespace css
} // namespace mozilla
@@ -79,13 +80,17 @@ public:
* @param aLineNumber the line number of the first line of the sheet.
* @param aAllowUnsafeRules see aEnableUnsafeRules in
* mozilla::css::Loader::LoadSheetSync
+ * @param aReusableSheets style sheets that can be reused by an @import.
+ * This can be nullptr.
*/
nsresult ParseSheet(const nsAString& aInput,
nsIURI* aSheetURL,
nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal,
uint32_t aLineNumber,
- bool aAllowUnsafeRules);
+ bool aAllowUnsafeRules,
+ mozilla::css::LoaderReusableStyleSheets* aReusableSheets =
+ nullptr);
// Parse HTML style attribute or its equivalent in other markup
// languages. aBaseURL is the base url to use for relative links in
@@ -132,6 +137,16 @@ public:
bool aIsImportant,
bool aIsSVGMode = false);
+ // Same as ParseProperty but returns an nsCSSValue in aResult
+ // rather than storing the property in a Declaration. aPropID
+ // must be a longhand property.
+ void ParseLonghandProperty(const nsCSSProperty aPropID,
+ const nsAString& aPropValue,
+ nsIURI* aSheetURL,
+ nsIURI* aBaseURL,
+ nsIPrincipal* aSheetPrincipal,
+ nsCSSValue& aResult);
+
// The same as ParseProperty but for a variable.
void ParseVariable(const nsAString& aVariableName,
const nsAString& aPropValue,
@@ -309,6 +324,11 @@ public:
bool IsValueValidForProperty(const nsCSSProperty aPropID,
const nsAString& aPropValue);
+ // Return the default value to be used for -moz-control-character-visibility,
+ // from preferences (cached by our Startup(), so that both nsStyleText and
+ // nsRuleNode can have fast access to it).
+ static uint8_t ControlCharVisibilityDefault();
+
protected:
// This is a CSSParserImpl*, but if we expose that type name in this
// header, we can't put the type definition (in nsCSSParser.cpp) in
diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h
index a513d549b4..1a321cbf91 100644
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -682,7 +682,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_VALUE_NONNEGATIVE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_AXIS |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
@@ -704,14 +704,14 @@ CSS_PROP_SHORTHAND(
border_block_end,
BorderBlockEnd,
CSS_PROPERTY_PARSE_FUNCTION |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS,
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
"layout.css.vertical-text.enabled")
CSS_PROP_SHORTHAND(
border-block-start,
border_block_start,
BorderBlockStart,
CSS_PROPERTY_PARSE_FUNCTION |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS,
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
"layout.css.vertical-text.enabled")
CSS_PROP_LOGICAL(
border-block-end-color,
@@ -719,7 +719,7 @@ CSS_PROP_LOGICAL(
BorderBlockEndColor,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
CSS_PROPERTY_LOGICAL_END_EDGE,
@@ -736,7 +736,7 @@ CSS_PROP_LOGICAL(
BorderBlockEndStyle,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
CSS_PROPERTY_LOGICAL_END_EDGE,
@@ -755,7 +755,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_VALUE_NONNEGATIVE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
CSS_PROPERTY_LOGICAL_END_EDGE,
@@ -772,7 +772,7 @@ CSS_PROP_LOGICAL(
BorderBlockStartColor,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
"layout.css.vertical-text.enabled",
@@ -788,7 +788,7 @@ CSS_PROP_LOGICAL(
BorderBlockStartStyle,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
"layout.css.vertical-text.enabled",
@@ -806,7 +806,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_VALUE_NONNEGATIVE |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
"layout.css.vertical-text.enabled",
@@ -2181,7 +2181,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_VALUE_NONNEGATIVE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_AXIS,
"layout.css.vertical-text.enabled",
@@ -2286,7 +2286,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
CSS_PROPERTY_LOGICAL_END_EDGE,
@@ -2306,7 +2306,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
"layout.css.vertical-text.enabled",
@@ -2436,7 +2436,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_VALUE_NONNEGATIVE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_AXIS |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
@@ -2469,7 +2469,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_VALUE_NONNEGATIVE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_AXIS,
"layout.css.vertical-text.enabled",
@@ -2515,7 +2515,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_VALUE_NONNEGATIVE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_AXIS |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
@@ -2534,7 +2534,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_VALUE_NONNEGATIVE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_AXIS,
"layout.css.vertical-text.enabled",
@@ -2585,7 +2585,7 @@ CSS_PROP_POSITION(
object_fit,
ObjectFit,
CSS_PROPERTY_PARSE_VALUE |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS,
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
"layout.css.object-fit-and-position.enabled",
VARIANT_HK,
kObjectFitKTable,
@@ -2597,7 +2597,7 @@ CSS_PROP_POSITION(
ObjectPosition,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_STORES_CALC |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS,
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
"layout.css.object-fit-and-position.enabled",
0,
kBackgroundPositionKTable,
@@ -2610,7 +2610,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
CSS_PROPERTY_LOGICAL_END_EDGE,
@@ -2628,7 +2628,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
"layout.css.vertical-text.enabled",
@@ -2645,7 +2645,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_END_EDGE,
"layout.css.vertical-text.enabled",
@@ -2662,7 +2662,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL,
"layout.css.vertical-text.enabled",
VARIANT_AHLP | VARIANT_CALC,
@@ -2761,7 +2761,7 @@ CSS_PROP_DISPLAY(
overflow_clip_box,
OverflowClipBox,
CSS_PROPERTY_PARSE_VALUE |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
"layout.css.overflow-clip-box.enabled",
VARIANT_HK,
@@ -2810,7 +2810,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS |
CSS_PROPERTY_LOGICAL_END_EDGE,
@@ -2832,7 +2832,7 @@ CSS_PROP_LOGICAL(
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_LOGICAL |
CSS_PROPERTY_LOGICAL_BLOCK_AXIS,
"layout.css.vertical-text.enabled",
@@ -3276,7 +3276,7 @@ CSS_PROP_VISIBILITY(
text_orientation,
TextOrientation,
CSS_PROPERTY_PARSE_VALUE |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS,
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
"layout.css.vertical-text.enabled",
VARIANT_HK,
kTextOrientationKTable,
@@ -3423,7 +3423,21 @@ CSS_PROP_POSITION(
nullptr,
offsetof(nsStylePosition, mOffset),
eStyleAnimType_Sides_Top)
- CSS_PROP_DISPLAY(
+#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
+CSS_PROP_DISPLAY(
+ -moz-top-layer,
+ _moz_top_layer,
+ CSS_PROP_DOMPROP_PREFIXED(TopLayer),
+ CSS_PROPERTY_INTERNAL |
+ CSS_PROPERTY_PARSE_VALUE |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
+ "",
+ VARIANT_HK,
+ kTopLayerKTable,
+ CSS_PROP_NO_OFFSET,
+ eStyleAnimType_None)
+#endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
+CSS_PROP_DISPLAY(
touch-action,
touch_action,
TouchAction,
@@ -3599,11 +3613,14 @@ CSS_PROP_POSITION(
kWidthKTable,
offsetof(nsStylePosition, mWidth),
eStyleAnimType_Coord)
+#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
CSS_PROP_USERINTERFACE(
-moz-window-dragging,
_moz_window_dragging,
CSS_PROP_DOMPROP_PREFIXED(WindowDragging),
- CSS_PROPERTY_PARSE_VALUE,
+ CSS_PROPERTY_INTERNAL |
+ CSS_PROPERTY_PARSE_VALUE |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS_AND_CHROME,
"",
VARIANT_HK,
kWindowDraggingKTable,
@@ -3613,12 +3630,15 @@ CSS_PROP_UIRESET(
-moz-window-shadow,
_moz_window_shadow,
CSS_PROP_DOMPROP_PREFIXED(WindowShadow),
- CSS_PROPERTY_PARSE_VALUE,
+ CSS_PROPERTY_INTERNAL |
+ CSS_PROPERTY_PARSE_VALUE |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS_AND_CHROME,
"",
VARIANT_HK,
kWindowShadowKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
+#endif
CSS_PROP_TEXT(
word-break,
word_break,
@@ -3667,7 +3687,7 @@ CSS_PROP_VISIBILITY(
writing_mode,
WritingMode,
CSS_PROPERTY_PARSE_VALUE |
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS,
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
"layout.css.vertical-text.enabled",
VARIANT_HK,
kWritingModeKTable,
@@ -3763,10 +3783,11 @@ CSS_PROP_FONT(
-moz-script-level,
script_level,
ScriptLevel,
- // REVIEW: no range restriction?
- // NOTE: CSSParserImpl::ParseSingleValueProperty only accepts this
- // property when mUnsafeRulesEnabled is set.
+ // We only allow 'script-level' when unsafe rules are enabled, because
+ // otherwise it could interfere with rulenode optimizations if used in
+ // a non-MathML-enabled document.
CSS_PROPERTY_INTERNAL |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_PARSE_VALUE,
"",
// script-level can take Auto, Integer and Number values, but only Auto
@@ -3780,7 +3801,6 @@ CSS_PROP_FONT(
-moz-script-size-multiplier,
script_size_multiplier,
ScriptSizeMultiplier,
- // REVIEW: no range restriction?
CSS_PROPERTY_INTERNAL |
CSS_PROPERTY_PARSE_INACCESSIBLE,
"",
@@ -3792,7 +3812,6 @@ CSS_PROP_FONT(
-moz-script-min-size,
script_min_size,
ScriptMinSize,
- // REVIEW: no range restriction?
CSS_PROPERTY_INTERNAL |
CSS_PROPERTY_PARSE_INACCESSIBLE,
"",
@@ -3815,9 +3834,8 @@ CSS_PROP_FONT(
-moz-math-display,
math_display,
MathDisplay,
- // NOTE: CSSParserImpl::ParseSingleValueProperty only accepts this
- // property when mUnsafeRulesEnabled is set.
CSS_PROPERTY_INTERNAL |
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_PARSE_VALUE,
"",
VARIANT_HK,
diff --git a/layout/style/nsCSSPropertySet.h b/layout/style/nsCSSPropertySet.h
index 6416df61e3..06ce4e2c5c 100644
--- a/layout/style/nsCSSPropertySet.h
+++ b/layout/style/nsCSSPropertySet.h
@@ -8,6 +8,7 @@
#define nsCSSPropertySet_h__
#include "mozilla/ArrayUtils.h"
+#include "mozilla/PodOperations.h"
#include "nsCSSProperty.h"
#include // for CHAR_BIT
@@ -62,6 +63,10 @@ public:
}
}
+ bool Equals(const nsCSSPropertySet& aOther) const {
+ return mozilla::PodEqual(mProperties, aOther.mProperties);
+ }
+
private:
typedef unsigned long property_set_type;
public:
diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp
index ceedcd5b16..7739e70157 100644
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -28,6 +28,35 @@ using namespace mozilla;
typedef nsCSSProps::KTableValue KTableValue;
+// MSVC before 2015 doesn't consider string literal as a constant
+// expression, thus we are not able to do this check here.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+// By wrapping internal-only properties in this macro, we are not
+// exposing them in the CSSOM. Since currently it is not necessary to
+// allow accessing them in that way, it is easier and cheaper to just
+// do this rather than exposing them conditionally.
+#define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \
+ static_assert(!((flags_) & CSS_PROPERTY_ENABLED_MASK) || pref_[0], \
+ "Internal-only property '" #name_ "' should be wrapped in " \
+ "#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL");
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
+#define CSS_PROP_LIST_EXCLUDE_INTERNAL
+#include "nsCSSPropList.h"
+#undef CSS_PROP_LIST_EXCLUDE_INTERNAL
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
+#undef CSS_PROP
+#endif
+
+#define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \
+ static_assert(!((flags_) & CSS_PROPERTY_ENABLED_IN_CHROME) || \
+ ((flags_) & CSS_PROPERTY_ENABLED_IN_UA_SHEETS), \
+ "Property '" #name_ "' is enabled in chrome, so it should " \
+ "also be enabled in UA sheets");
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
+#include "nsCSSPropList.h"
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
+#undef CSS_PROP
+
// required to make the symbol external, so that TestCSSPropertyLookup.cpp can link with it
extern const char* const kCSSRawProperties[];
@@ -55,6 +84,7 @@ static nsStaticCaseInsensitiveNameTable* gPropertyTable;
static nsStaticCaseInsensitiveNameTable* gFontDescTable;
static nsStaticCaseInsensitiveNameTable* gCounterDescTable;
static nsStaticCaseInsensitiveNameTable* gPredefinedCounterStyleTable;
+static nsDataHashtable* gPropertyIDLNameTable;
/* static */ nsCSSProperty *
nsCSSProps::gShorthandsContainingTable[eCSSProperty_COUNT_no_shorthands];
@@ -139,6 +169,7 @@ nsCSSProps::AddRefTable(void)
MOZ_ASSERT(!gFontDescTable, "pre existing array!");
MOZ_ASSERT(!gCounterDescTable, "pre existing array!");
MOZ_ASSERT(!gPredefinedCounterStyleTable, "pre existing array!");
+ MOZ_ASSERT(!gPropertyIDLNameTable, "pre existing array!");
gPropertyTable = CreateStaticTable(
kCSSRawProperties, eCSSProperty_COUNT_with_aliases);
@@ -149,6 +180,15 @@ nsCSSProps::AddRefTable(void)
kCSSRawPredefinedCounterStyles,
ArrayLength(kCSSRawPredefinedCounterStyles));
+ gPropertyIDLNameTable = new nsDataHashtable;
+ for (nsCSSProperty p = nsCSSProperty(0);
+ size_t(p) < ArrayLength(kIDLNameTable);
+ p = nsCSSProperty(p + 1)) {
+ if (kIDLNameTable[p]) {
+ gPropertyIDLNameTable->Put(nsDependentCString(kIDLNameTable[p]), p);
+ }
+ }
+
BuildShorthandsContainingTable();
static bool prefObserversInited = false;
@@ -184,11 +224,12 @@ nsCSSProps::AddRefTable(void)
#ifdef DEBUG
{
- // Assert that if CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS is used
- // on a shorthand property that all of its component longhands
- // also has the flag.
+ // Assert that if CSS_PROPERTY_ENABLED_IN_UA_SHEETS or
+ // CSS_PROPERTY_ENABLED_IN_CHROME is used on a shorthand property
+ // that all of its component longhands also have the flag.
static uint32_t flagsToCheck[] = {
- CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS
+ CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
+ CSS_PROPERTY_ENABLED_IN_CHROME
};
for (nsCSSProperty shorthand = eCSSProperty_COUNT_no_shorthands;
shorthand < eCSSProperty_COUNT;
@@ -204,7 +245,7 @@ nsCSSProps::AddRefTable(void)
++p) {
MOZ_ASSERT(nsCSSProps::PropHasFlags(*p, flag),
"all subproperties of a property with a "
- "CSS_PROPERTY_ALWAYS_ENABLED_* flag must also have "
+ "CSS_PROPERTY_ENABLED_* flag must also have "
"the flag");
}
}
@@ -429,6 +470,9 @@ nsCSSProps::ReleaseTable(void)
delete gPredefinedCounterStyleTable;
gPredefinedCounterStyleTable = nullptr;
+ delete gPropertyIDLNameTable;
+ gPropertyIDLNameTable = nullptr;
+
delete [] gShorthandsContainingPool;
gShorthandsContainingPool = nullptr;
}
@@ -478,7 +522,7 @@ nsCSSProps::LookupProperty(const nsACString& aProperty,
}
MOZ_ASSERT(eCSSAliasCount != 0,
"'res' must be an alias at this point so we better have some!");
- // We intentionally don't support eEnabledInUASheets or eEnabledInChromeOrCertifiedApp
+ // We intentionally don't support eEnabledInUASheets or eEnabledInChrome
// for aliases yet because it's unlikely there will be a need for it.
if (IsEnabled(res) || aEnabled == eIgnoreEnabledState) {
res = gAliases[res - eCSSProperty_COUNT];
@@ -512,8 +556,8 @@ nsCSSProps::LookupProperty(const nsAString& aProperty, EnabledState aEnabled)
}
MOZ_ASSERT(eCSSAliasCount != 0,
"'res' must be an alias at this point so we better have some!");
- // We intentionally don't support eEnabledInUASheets for aliases yet
- // because it's unlikely there will be a need for it.
+ // We intentionally don't support eEnabledInUASheets or eEnabledInChrome
+ // for aliases yet because it's unlikely there will be a need for it.
if (IsEnabled(res) || aEnabled == eIgnoreEnabledState) {
res = gAliases[res - eCSSProperty_COUNT];
MOZ_ASSERT(0 <= res && res < eCSSProperty_COUNT,
@@ -525,6 +569,30 @@ nsCSSProps::LookupProperty(const nsAString& aProperty, EnabledState aEnabled)
return eCSSProperty_UNKNOWN;
}
+nsCSSProperty
+nsCSSProps::LookupPropertyByIDLName(const nsACString& aPropertyIDLName,
+ EnabledState aEnabled)
+{
+ nsCSSProperty res;
+ if (!gPropertyIDLNameTable->Get(aPropertyIDLName, &res)) {
+ return eCSSProperty_UNKNOWN;
+ }
+ MOZ_ASSERT(res < eCSSProperty_COUNT);
+ if (!IsEnabled(res, aEnabled)) {
+ return eCSSProperty_UNKNOWN;
+ }
+ return res;
+}
+
+nsCSSProperty
+nsCSSProps::LookupPropertyByIDLName(const nsAString& aPropertyIDLName,
+ EnabledState aEnabled)
+{
+ MOZ_ASSERT(gPropertyIDLNameTable, "no lookup table, needs addref");
+ return LookupPropertyByIDLName(NS_ConvertUTF16toUTF8(aPropertyIDLName),
+ aEnabled);
+}
+
nsCSSFontDesc
nsCSSProps::LookupFontDesc(const nsACString& aFontDesc)
{
@@ -1855,6 +1923,12 @@ const KTableValue nsCSSProps::kTouchActionKTable[] = {
eCSSKeyword_UNKNOWN, -1
};
+const KTableValue nsCSSProps::kTopLayerKTable[] = {
+ eCSSKeyword_none, NS_STYLE_TOP_LAYER_NONE,
+ eCSSKeyword_top, NS_STYLE_TOP_LAYER_TOP,
+ eCSSKeyword_UNKNOWN, -1
+};
+
const KTableValue nsCSSProps::kTransformBoxKTable[] = {
eCSSKeyword_border_box, NS_STYLE_TRANSFORM_BOX_BORDER_BOX,
eCSSKeyword_fill_box, NS_STYLE_TRANSFORM_BOX_FILL_BOX,
@@ -3005,16 +3079,24 @@ nsCSSProps::gPropertyIndexInStruct[eCSSProperty_COUNT_no_shorthands] = {
/* static */ bool
nsCSSProps::gPropertyEnabled[eCSSProperty_COUNT_with_aliases] = {
+ // If the property has any "ENABLED_IN" flag set, it is disabled by
+ // default. Note that, if a property has pref, whatever its default
+ // value is, it will later be changed in nsCSSProps::AddRefTable().
+ // If the property has "ENABLED_IN" flags but doesn't have a pref,
+ // it is an internal property which is disabled elsewhere.
+ #define IS_ENABLED_BY_DEFAULT(flags_) \
+ (!((flags_) & CSS_PROPERTY_ENABLED_MASK))
+
#define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, \
kwtable_, stylestruct_, stylestructoffset_, animtype_) \
- true,
+ IS_ENABLED_BY_DEFAULT(flags_),
#define CSS_PROP_LIST_INCLUDE_LOGICAL
#include "nsCSSPropList.h"
#undef CSS_PROP_LIST_INCLUDE_LOGICAL
#undef CSS_PROP
#define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) \
- true,
+ IS_ENABLED_BY_DEFAULT(flags_),
#include "nsCSSPropList.h"
#undef CSS_PROP_SHORTHAND
@@ -3022,6 +3104,8 @@ nsCSSProps::gPropertyEnabled[eCSSProperty_COUNT_with_aliases] = {
true,
#include "nsCSSPropAliasList.h"
#undef CSS_PROP_ALIAS
+
+ #undef IS_ENABLED_BY_DEFAULT
};
#include "../../dom/base/PropertyUseCounterMap.inc"
diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h
index c11cc9c0b8..592d8c3733 100644
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -56,6 +56,17 @@
// Keyword used iff gfx.font_rendering.opentype_svg.enabled is true:
#define VARIANT_OPENTYPE_SVG_KEYWORD 0x40000000
+// Variants that can consume more than one token
+#define VARIANT_MULTIPLE_TOKENS \
+ (VARIANT_COLOR | /* rgb(...), hsl(...), etc. */ \
+ VARIANT_COUNTER | /* counter(...), counters(...) */ \
+ VARIANT_ATTR | /* attr(...) */ \
+ VARIANT_GRADIENT | /* linear-gradient(...), etc. */ \
+ VARIANT_TIMING_FUNCTION | /* cubic-bezier(...), steps(...) */ \
+ VARIANT_IMAGE_RECT | /* -moz-image-rect(...) */ \
+ VARIANT_CALC | /* calc(...) */ \
+ VARIANT_ELEMENT) /* -moz-element(...) */
+
// Common combinations of variants
#define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)
#define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT)
@@ -200,14 +211,23 @@ static_assert((CSS_PROPERTY_PARSE_PROPERTY_MASK &
// This property requires a stacking context.
#define CSS_PROPERTY_CREATES_STACKING_CONTEXT (1<<21)
-// This property is always enabled in UA sheets. This is meant to be used
-// together with a pref that enables the property for non-UA sheets.
-// Note that if such a property has an alias, then any use of that alias
-// in an UA sheet will still be ignored unless the pref is enabled.
-// In other words, this bit has no effect on the use of aliases.
-#define CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS (1<<22)
-
-// XXX (1<<23) will shortly be reused in bug 1069192.
+// The following two flags along with the pref defines where the this
+// property can be used:
+// * If none of the two flags is presented, the pref completely controls
+// the availability of this property. And in that case, if it has no
+// pref, this property is usable everywhere.
+// * If any of the flags is set, this property is always enabled in the
+// specific contexts regardless of the value of the pref. If there is
+// no pref for this property at all in this case, it is an internal-
+// only property, which cannot be used anywhere else, and should be
+// wrapped in "#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL".
+// Note that, these flags have no effect on the use of aliases of this
+// property.
+#define CSS_PROPERTY_ENABLED_MASK (3<<22)
+#define CSS_PROPERTY_ENABLED_IN_UA_SHEETS (1<<22)
+#define CSS_PROPERTY_ENABLED_IN_CHROME (1<<23)
+#define CSS_PROPERTY_ENABLED_IN_UA_SHEETS_AND_CHROME \
+ (CSS_PROPERTY_ENABLED_IN_UA_SHEETS | CSS_PROPERTY_ENABLED_IN_CHROME)
// This property's unitless values are pixels.
#define CSS_PROPERTY_NUMBERS_ARE_PIXELS (1<<24)
@@ -298,6 +318,8 @@ public:
eEnabledForAllContent = 0,
// Enable a property in UA sheets.
eEnabledInUASheets = 0x01,
+ // Enable a property in chrome code.
+ eEnabledInChrome = 0x02,
// Special value to unconditionally enable a property. This implies all the
// bits above, but is strictly more than just their OR-ed union.
// This just skips any test so a property will be enabled even if it would
@@ -312,6 +334,15 @@ public:
EnabledState aEnabled);
static nsCSSProperty LookupProperty(const nsACString& aProperty,
EnabledState aEnabled);
+ // As above, but looked up using a property's IDL name.
+ // eCSSPropertyExtra_variable won't be returned from these methods.
+ static nsCSSProperty LookupPropertyByIDLName(
+ const nsAString& aPropertyIDLName,
+ EnabledState aEnabled);
+ static nsCSSProperty LookupPropertyByIDLName(
+ const nsACString& aPropertyIDLName,
+ EnabledState aEnabled);
+
// Returns whether aProperty is a custom property name, i.e. begins with
// "--". This assumes that the CSS Variables pref has been enabled.
static bool IsCustomPropertyName(const nsAString& aProperty);
@@ -543,15 +574,12 @@ public:
return kIDLNameSortPositionTable[aProperty];
}
-public:
-
static bool IsEnabled(nsCSSProperty aProperty) {
MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_with_aliases,
"out of range");
return gPropertyEnabled[aProperty];
}
-private:
// A table for the use counter associated with each CSS property. If a
// property does not have a use counter defined in UseCounters.conf, then
// its associated entry is |eUseCounter_UNKNOWN|.
@@ -574,7 +602,12 @@ public:
return true;
}
if ((aEnabled & eEnabledInUASheets) &&
- PropHasFlags(aProperty, CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS))
+ PropHasFlags(aProperty, CSS_PROPERTY_ENABLED_IN_UA_SHEETS))
+ {
+ return true;
+ }
+ if ((aEnabled & eEnabledInChrome) &&
+ PropHasFlags(aProperty, CSS_PROPERTY_ENABLED_IN_CHROME))
{
return true;
}
@@ -745,6 +778,7 @@ public:
static const KTableValue kTextOverflowKTable[];
static const KTableValue kTextTransformKTable[];
static const KTableValue kTouchActionKTable[];
+ static const KTableValue kTopLayerKTable[];
static const KTableValue kTransformBoxKTable[];
static const KTableValue kTransitionTimingFunctionKTable[];
static const KTableValue kUnicodeBidiKTable[];
diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h
index ac658c422a..ed8650b4f1 100644
--- a/layout/style/nsCSSPseudoClassList.h
+++ b/layout/style/nsCSSPseudoClassList.h
@@ -122,6 +122,9 @@ CSS_PSEUDO_CLASS(mozWindowInactive, ":-moz-window-inactive", 0, "")
// according to HTML integer attribute parsing rules.
CSS_PSEUDO_CLASS(mozTableBorderNonzero, ":-moz-table-border-nonzero", 0, "")
+// Matches HTML frame/iframe elements which are mozbrowser.
+CSS_PSEUDO_CLASS(mozBrowserFrame, ":-moz-browser-frame", 0, "")
+
// Matches whatever the contextual reference elements are for the
// matching operation.
CSS_PSEUDO_CLASS(scope, ":scope", 0, "layout.css.scope-pseudo.enabled")
diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp
index 4d2aa1ae85..19c4470453 100644
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -56,6 +56,7 @@
#include "mozilla/TypedEnumBits.h"
#include "RuleProcessorCache.h"
#include "nsIDOMMutationEvent.h"
+#include "nsIMozBrowserFrame.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -1013,7 +1014,7 @@ RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
//
nsCSSRuleProcessor::nsCSSRuleProcessor(const sheet_array_type& aSheets,
- uint8_t aSheetType,
+ SheetType aSheetType,
Element* aScopeElement,
nsCSSRuleProcessor*
aPreviousCSSRuleProcessor,
@@ -1034,7 +1035,7 @@ nsCSSRuleProcessor::nsCSSRuleProcessor(const sheet_array_type& aSheets,
, mDocumentRulesAndCacheKeyValid(false)
#endif
{
- NS_ASSERTION(!!mScopeElement == (aSheetType == nsStyleSet::eScopedDocSheet),
+ NS_ASSERTION(!!mScopeElement == (aSheetType == SheetType::ScopedDoc),
"aScopeElement must be specified iff aSheetType is "
"eScopedDocSheet");
for (sheet_array_type::size_type i = mSheets.Length(); i-- != 0; ) {
@@ -2144,6 +2145,17 @@ static bool SelectorMatches(Element* aElement,
}
break;
+ case nsCSSPseudoClasses::ePseudoClass_mozBrowserFrame:
+ {
+ nsCOMPtr
+ browserFrame = do_QueryInterface(aElement);
+ if (!browserFrame ||
+ !browserFrame->GetReallyIsBrowserOrApp()) {
+ return false;
+ }
+ }
+ break;
+
case nsCSSPseudoClasses::ePseudoClass_mozDir:
case nsCSSPseudoClasses::ePseudoClass_dir:
{
@@ -3426,7 +3438,7 @@ struct CascadeEnumData {
nsTArray& aDocumentRules,
nsMediaQueryResultCacheKey& aKey,
nsDocumentRuleResultCacheKey& aDocumentKey,
- uint8_t aSheetType,
+ SheetType aSheetType,
bool aMustGatherDocumentRules)
: mPresContext(aPresContext),
mFontFaceRules(aFontFaceRules),
@@ -3464,7 +3476,7 @@ struct CascadeEnumData {
// Hooray, a manual PLDHashTable since nsClassHashtable doesn't
// provide a getter that gives me a *reference* to the value.
PLDHashTable mRulesByWeight; // of PerWeightDataListItem linked lists
- uint8_t mSheetType;
+ SheetType mSheetType;
bool mMustGatherDocumentRules;
};
diff --git a/layout/style/nsCSSRuleProcessor.h b/layout/style/nsCSSRuleProcessor.h
index 18d76f1450..022c57a7eb 100644
--- a/layout/style/nsCSSRuleProcessor.h
+++ b/layout/style/nsCSSRuleProcessor.h
@@ -15,14 +15,15 @@
#include "mozilla/Attributes.h"
#include "mozilla/EventStates.h"
#include "mozilla/MemoryReporting.h"
-#include "nsIStyleRuleProcessor.h"
-#include "nsIMediaList.h"
-#include "nsTArray.h"
+#include "mozilla/RefCountType.h"
+#include "mozilla/SheetType.h"
+#include "mozilla/UniquePtr.h"
#include "nsAutoPtr.h"
#include "nsExpirationTracker.h"
+#include "nsIMediaList.h"
+#include "nsIStyleRuleProcessor.h"
#include "nsRuleWalker.h"
-#include "mozilla/RefCountType.h"
-#include "mozilla/UniquePtr.h"
+#include "nsTArray.h"
struct CascadeEnumData;
struct ElementDependentRuleProcessorData;
@@ -59,11 +60,11 @@ public:
typedef nsTArray> sheet_array_type;
// aScopeElement must be non-null iff aSheetType is
- // nsStyleSet::eScopedDocSheet.
+ // SheetType::ScopedDoc.
// aPreviousCSSRuleProcessor is the rule processor (if any) that this
// one is replacing.
nsCSSRuleProcessor(const sheet_array_type& aSheets,
- uint8_t aSheetType,
+ mozilla::SheetType aSheetType,
mozilla::dom::Element* aScopeElement,
nsCSSRuleProcessor* aPreviousCSSRuleProcessor,
bool aIsShared = false);
@@ -262,7 +263,7 @@ private:
MozRefCountType mStyleSetRefCnt;
// type of stylesheet using this processor
- uint8_t mSheetType; // == nsStyleSet::sheetType
+ mozilla::SheetType mSheetType;
const bool mIsShared;
diff --git a/layout/style/nsCSSRules.cpp b/layout/style/nsCSSRules.cpp
index f9d8717db8..edc412bde6 100644
--- a/layout/style/nsCSSRules.cpp
+++ b/layout/style/nsCSSRules.cpp
@@ -2235,8 +2235,6 @@ nsCSSKeyframeRule::ChangeDeclaration(css::Declaration* aDeclaration)
nsIDocument* doc = GetDocument();
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
- // Be careful to not assign to an nsAutoPtr if we would be assigning
- // the thing it already holds.
if (aDeclaration != mDeclaration) {
mDeclaration = aDeclaration;
}
@@ -2739,8 +2737,6 @@ void
nsCSSPageRule::ChangeDeclaration(css::Declaration* aDeclaration)
{
mImportantRule = nullptr;
- // Be careful to not assign to an nsAutoPtr if we would be assigning
- // the thing it already holds.
if (aDeclaration != mDeclaration) {
mDeclaration = aDeclaration;
}
diff --git a/layout/style/nsCSSRules.h b/layout/style/nsCSSRules.h
index e23dc91e2c..3efc67f922 100644
--- a/layout/style/nsCSSRules.h
+++ b/layout/style/nsCSSRules.h
@@ -9,12 +9,19 @@
#ifndef nsCSSRules_h_
#define nsCSSRules_h_
+#include "Declaration.h"
+#include "StyleRule.h"
+#include "gfxFontFeatures.h"
#include "mozilla/Attributes.h"
-#include "mozilla/Move.h"
-
#include "mozilla/MemoryReporting.h"
+#include "mozilla/Move.h"
+#include "mozilla/SheetType.h"
#include "mozilla/css/GroupRule.h"
#include "mozilla/dom/FontFace.h"
+#include "nsAutoPtr.h"
+#include "nsCSSProperty.h"
+#include "nsCSSValue.h"
+#include "nsDOMCSSDeclaration.h"
#include "nsIDOMCSSConditionRule.h"
#include "nsIDOMCSSCounterStyleRule.h"
#include "nsIDOMCSSFontFaceRule.h"
@@ -22,18 +29,11 @@
#include "nsIDOMCSSGroupingRule.h"
#include "nsIDOMCSSMediaRule.h"
#include "nsIDOMCSSMozDocumentRule.h"
+#include "nsIDOMCSSPageRule.h"
#include "nsIDOMCSSSupportsRule.h"
#include "nsIDOMMozCSSKeyframeRule.h"
#include "nsIDOMMozCSSKeyframesRule.h"
-#include "nsAutoPtr.h"
-#include "nsCSSProperty.h"
-#include "nsCSSValue.h"
#include "nsTArray.h"
-#include "nsDOMCSSDeclaration.h"
-#include "Declaration.h"
-#include "nsIDOMCSSPageRule.h"
-#include "StyleRule.h"
-#include "gfxFontFeatures.h"
class nsMediaList;
@@ -287,7 +287,7 @@ protected:
// specific @font-face rules
struct nsFontFaceRuleContainer {
RefPtr mRule;
- uint8_t mSheetType;
+ mozilla::SheetType mSheetType;
};
inline nsCSSFontFaceRule*
@@ -388,12 +388,12 @@ class nsCSSKeyframeRule final : public mozilla::css::Rule,
public nsIDOMMozCSSKeyframeRule
{
public:
- // WARNING: Steals the contents of aKeys *and* aDeclaration
+ // WARNING: Steals the contents of aKeys
nsCSSKeyframeRule(InfallibleTArray& aKeys,
- nsAutoPtr&& aDeclaration,
+ mozilla::css::Declaration* aDeclaration,
uint32_t aLineNumber, uint32_t aColumnNumber)
: mozilla::css::Rule(aLineNumber, aColumnNumber)
- , mDeclaration(mozilla::Move(aDeclaration))
+ , mDeclaration(aDeclaration)
{
mKeys.SwapElements(aKeys);
}
@@ -431,7 +431,7 @@ public:
private:
nsTArray mKeys;
- nsAutoPtr mDeclaration;
+ RefPtr mDeclaration;
// lazily created when needed:
RefPtr mDOMDeclaration;
};
@@ -521,11 +521,10 @@ class nsCSSPageRule final : public mozilla::css::Rule,
public nsIDOMCSSPageRule
{
public:
- // WARNING: Steals the contents of aDeclaration
- nsCSSPageRule(nsAutoPtr&& aDeclaration,
+ nsCSSPageRule(mozilla::css::Declaration* aDeclaration,
uint32_t aLineNumber, uint32_t aColumnNumber)
: mozilla::css::Rule(aLineNumber, aColumnNumber)
- , mDeclaration(mozilla::Move(aDeclaration))
+ , mDeclaration(aDeclaration)
, mImportantRule(nullptr)
{
}
@@ -560,7 +559,7 @@ public:
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
private:
- nsAutoPtr mDeclaration;
+ RefPtr mDeclaration;
// lazily created when needed:
RefPtr mDOMDeclaration;
RefPtr mImportantRule;
diff --git a/layout/style/nsCSSValue.cpp b/layout/style/nsCSSValue.cpp
index 6364695ed3..a96a154cbc 100644
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -23,6 +23,7 @@
#include "nsPresContext.h"
#include "nsStyleUtil.h"
#include "nsDeviceContext.h"
+#include "nsStyleSet.h"
using namespace mozilla;
@@ -2369,7 +2370,6 @@ css::URLValue::URLValue(nsIURI* aURI, nsStringBuffer* aString,
mURIResolved(true)
{
MOZ_ASSERT(aOriginPrincipal, "Must have an origin principal");
- mString->AddRef();
}
css::URLValue::URLValue(nsStringBuffer* aString, nsIURI* aBaseURI,
@@ -2381,12 +2381,6 @@ css::URLValue::URLValue(nsStringBuffer* aString, nsIURI* aBaseURI,
mURIResolved(false)
{
MOZ_ASSERT(aOriginPrincipal, "Must have an origin principal");
- mString->AddRef();
-}
-
-css::URLValue::~URLValue()
-{
- mString->Release();
}
bool
@@ -2570,6 +2564,7 @@ nsCSSValueGradient::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) con
nsCSSValueTokenStream::nsCSSValueTokenStream()
: mPropertyID(eCSSProperty_UNKNOWN)
, mShorthandPropertyID(eCSSProperty_UNKNOWN)
+ , mLevel(SheetType::Count)
{
MOZ_COUNT_CTOR(nsCSSValueTokenStream);
}
diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h
index 325a85f3bf..b43bc3b20b 100644
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -10,6 +10,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
+#include "mozilla/SheetType.h"
#include "nsIPrincipal.h"
#include "nsIURI.h"
@@ -87,7 +88,7 @@ struct URLValue {
nsIPrincipal* aOriginPrincipal);
protected:
- ~URLValue();
+ ~URLValue() {};
public:
bool operator==(const URLValue& aOther) const;
@@ -108,8 +109,7 @@ private:
// null if the URI is invalid.
mutable nsCOMPtr mURI;
public:
- nsStringBuffer* mString; // Could use nsRefPtr, but it'd add useless
- // null-checks; this is never null.
+ RefPtr mString;
nsCOMPtr mReferrer;
nsCOMPtr mOriginPrincipal;
@@ -1496,6 +1496,7 @@ public:
return mPropertyID == aOther.mPropertyID &&
mShorthandPropertyID == aOther.mShorthandPropertyID &&
mTokenStream.Equals(aOther.mTokenStream) &&
+ mLevel == aOther.mLevel &&
(mBaseURI == aOther.mBaseURI ||
(mBaseURI && aOther.mBaseURI &&
NS_SUCCEEDED(mBaseURI->Equals(aOther.mBaseURI, &eq)) &&
@@ -1544,6 +1545,7 @@ public:
// mozilla::CSSStyleSheet* mSheet;
uint32_t mLineNumber;
uint32_t mLineOffset;
+ mozilla::SheetType mLevel;
// This table is used to hold a reference on to any ImageValue that results
// from re-parsing this token stream at computed value time. When properties
diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp
index a03ab434d3..8ada59c0a2 100644
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -96,7 +96,8 @@ struct nsComputedStyleMap
bool IsEnabled() const
{
- return nsCSSProps::IsEnabled(mProperty);
+ return nsCSSProps::IsEnabled(mProperty,
+ nsCSSProps::eEnabledForAllContent);
}
};
@@ -505,8 +506,8 @@ nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
for (nsRuleNode* ruleNode = sc->RuleNode();
!ruleNode->IsRoot();
ruleNode = ruleNode->GetParent()) {
- if (ruleNode->GetLevel() == nsStyleSet::eAgentSheet ||
- ruleNode->GetLevel() == nsStyleSet::eUserSheet) {
+ if (ruleNode->GetLevel() == SheetType::Agent ||
+ ruleNode->GetLevel() == SheetType::User) {
rules.AppendElement(ruleNode->GetRule());
}
}
diff --git a/layout/style/nsDOMCSSAttrDeclaration.cpp b/layout/style/nsDOMCSSAttrDeclaration.cpp
index 26882c3b66..cfbbddb6c5 100644
--- a/layout/style/nsDOMCSSAttrDeclaration.cpp
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -138,7 +138,7 @@ nsDOMCSSAttributeDeclaration::GetCSSDeclaration(Operation aOperation)
}
// cannot fail
- css::Declaration *decl = new css::Declaration();
+ RefPtr decl = new css::Declaration();
decl->InitializeEmpty();
RefPtr newRule = new css::StyleRule(nullptr, decl, 0, 0);
diff --git a/layout/style/nsDOMCSSDeclaration.cpp b/layout/style/nsDOMCSSDeclaration.cpp
index b02b98ff3e..4aa08914ae 100644
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -123,7 +123,7 @@ nsDOMCSSDeclaration::SetCssText(const nsAString& aCssText)
// rule (see stack in bug 209575).
mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
- nsAutoPtr decl(new css::Declaration());
+ RefPtr decl(new css::Declaration());
decl->InitializeEmpty();
nsCSSParser cssParser(env.mCSSLoader);
bool changed;
@@ -134,7 +134,7 @@ nsDOMCSSDeclaration::SetCssText(const nsAString& aCssText)
return result;
}
- return SetCSSDeclaration(decl.forget());
+ return SetCSSDeclaration(decl);
}
NS_IMETHODIMP
@@ -328,16 +328,13 @@ nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSProperty aPropID,
// between when we mutate the declaration and when we set the new
// rule (see stack in bug 209575).
mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
- css::Declaration* decl = olddecl->EnsureMutable();
+ RefPtr decl = olddecl->EnsureMutable();
nsCSSParser cssParser(env.mCSSLoader);
bool changed;
cssParser.ParseProperty(aPropID, aPropValue, env.mSheetURI, env.mBaseURI,
env.mPrincipal, decl, &changed, aIsImportant);
if (!changed) {
- if (decl != olddecl) {
- delete decl;
- }
// Parsing failed -- but we don't throw an exception for that.
return NS_OK;
}
@@ -369,7 +366,7 @@ nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
// between when we mutate the declaration and when we set the new
// rule (see stack in bug 209575).
mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
- css::Declaration* decl = olddecl->EnsureMutable();
+ RefPtr decl = olddecl->EnsureMutable();
nsCSSParser cssParser(env.mCSSLoader);
bool changed;
@@ -379,9 +376,6 @@ nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
env.mBaseURI, env.mPrincipal, decl,
&changed, aIsImportant);
if (!changed) {
- if (decl != olddecl) {
- delete decl;
- }
// Parsing failed -- but we don't throw an exception for that.
return NS_OK;
}
@@ -392,8 +386,8 @@ nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
nsresult
nsDOMCSSDeclaration::RemoveProperty(const nsCSSProperty aPropID)
{
- css::Declaration* decl = GetCSSDeclaration(eOperation_RemoveProperty);
- if (!decl) {
+ css::Declaration* olddecl = GetCSSDeclaration(eOperation_RemoveProperty);
+ if (!olddecl) {
return NS_OK; // no decl, so nothing to remove
}
@@ -404,7 +398,7 @@ nsDOMCSSDeclaration::RemoveProperty(const nsCSSProperty aPropID)
// rule (see stack in bug 209575).
mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
- decl = decl->EnsureMutable();
+ RefPtr decl = olddecl->EnsureMutable();
decl->RemoveProperty(aPropID);
return SetCSSDeclaration(decl);
}
@@ -415,8 +409,8 @@ nsDOMCSSDeclaration::RemoveCustomProperty(const nsAString& aPropertyName)
MOZ_ASSERT(Substring(aPropertyName, 0,
CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--"));
- css::Declaration* decl = GetCSSDeclaration(eOperation_RemoveProperty);
- if (!decl) {
+ css::Declaration* olddecl = GetCSSDeclaration(eOperation_RemoveProperty);
+ if (!olddecl) {
return NS_OK; // no decl, so nothing to remove
}
@@ -427,16 +421,8 @@ nsDOMCSSDeclaration::RemoveCustomProperty(const nsAString& aPropertyName)
// rule (see stack in bug 209575).
mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
- decl = decl->EnsureMutable();
+ RefPtr decl = olddecl->EnsureMutable();
decl->RemoveVariableDeclaration(Substring(aPropertyName,
CSS_CUSTOM_NAME_PREFIX_LENGTH));
return SetCSSDeclaration(decl);
}
-
-bool IsCSSPropertyExposedToJS(nsCSSProperty aProperty, JSContext* cx, JSObject* obj)
-{
- MOZ_ASSERT_UNREACHABLE("This is currently not used anywhere, "
- "but should be reused soon in bug 1069192");
- nsCSSProps::EnabledState enabledState = nsCSSProps::eEnabledForAllContent;
- return nsCSSProps::IsEnabled(aProperty, enabledState);
-}
diff --git a/layout/style/nsDOMCSSDeclaration.h b/layout/style/nsDOMCSSDeclaration.h
index 4f1bc88937..ced905e4b1 100644
--- a/layout/style/nsDOMCSSDeclaration.h
+++ b/layout/style/nsDOMCSSDeclaration.h
@@ -168,12 +168,4 @@ protected:
virtual ~nsDOMCSSDeclaration();
};
-bool IsCSSPropertyExposedToJS(nsCSSProperty aProperty, JSContext* cx, JSObject* obj);
-
-template
-MOZ_ALWAYS_INLINE bool IsCSSPropertyExposedToJS(JSContext* cx, JSObject* obj)
-{
- return IsCSSPropertyExposedToJS(Property, cx, obj);
-}
-
#endif // nsDOMCSSDeclaration_h___
diff --git a/layout/style/nsLayoutStylesheetCache.cpp b/layout/style/nsLayoutStylesheetCache.cpp
index 536baa6428..82254fe6c7 100644
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -157,13 +157,6 @@ nsLayoutStylesheetCache::QuirkSheet()
return gStyleCache->mQuirkSheet;
}
-CSSStyleSheet*
-nsLayoutStylesheetCache::FullScreenOverrideSheet()
-{
- EnsureGlobal();
- return gStyleCache->mFullScreenOverrideSheet;
-}
-
CSSStyleSheet*
nsLayoutStylesheetCache::SVGSheet()
{
@@ -244,6 +237,32 @@ nsLayoutStylesheetCache::ContentPreferenceSheet(nsPresContext* aPresContext)
return gStyleCache->mContentPreferenceSheet;
}
+/* static */ CSSStyleSheet*
+nsLayoutStylesheetCache::ContentEditableSheet()
+{
+ EnsureGlobal();
+
+ if (!gStyleCache->mContentEditableSheet) {
+ LoadSheetURL("resource://gre/res/contenteditable.css",
+ gStyleCache->mContentEditableSheet, true);
+ }
+
+ return gStyleCache->mContentEditableSheet;
+}
+
+/* static */ CSSStyleSheet*
+nsLayoutStylesheetCache::DesignModeSheet()
+{
+ EnsureGlobal();
+
+ if (!gStyleCache->mDesignModeSheet) {
+ LoadSheetURL("resource://gre/res/designmode.css",
+ gStyleCache->mDesignModeSheet, true);
+ }
+
+ return gStyleCache->mDesignModeSheet;
+}
+
void
nsLayoutStylesheetCache::Shutdown()
{
@@ -272,10 +291,11 @@ nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
#define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0;
MEASURE(mChromePreferenceSheet);
+ MEASURE(mContentEditableSheet);
MEASURE(mContentPreferenceSheet);
MEASURE(mCounterStylesSheet);
+ MEASURE(mDesignModeSheet);
MEASURE(mFormsSheet);
- MEASURE(mFullScreenOverrideSheet);
MEASURE(mHTMLSheet);
MEASURE(mMathMLSheet);
MEASURE(mMinimalXULSheet);
@@ -316,8 +336,6 @@ nsLayoutStylesheetCache::nsLayoutStylesheetCache()
// per-profile, since they're profile-invariant.
LoadSheetURL("resource://gre-resources/counterstyles.css",
mCounterStylesSheet, true);
- LoadSheetURL("resource://gre-resources/full-screen-override.css",
- mFullScreenOverrideSheet, true);
LoadSheetURL("chrome://global/content/minimal-xul.css",
mMinimalXULSheet, true);
LoadSheetURL("resource://gre-resources/quirk.css",
diff --git a/layout/style/nsLayoutStylesheetCache.h b/layout/style/nsLayoutStylesheetCache.h
index c8960818ed..9aebc35468 100644
--- a/layout/style/nsLayoutStylesheetCache.h
+++ b/layout/style/nsLayoutStylesheetCache.h
@@ -44,7 +44,6 @@ class nsLayoutStylesheetCache final
static mozilla::CSSStyleSheet* MinimalXULSheet();
static mozilla::CSSStyleSheet* XULSheet();
static mozilla::CSSStyleSheet* QuirkSheet();
- static mozilla::CSSStyleSheet* FullScreenOverrideSheet();
static mozilla::CSSStyleSheet* SVGSheet();
static mozilla::CSSStyleSheet* MathMLSheet();
static mozilla::CSSStyleSheet* CounterStylesSheet();
@@ -52,6 +51,8 @@ class nsLayoutStylesheetCache final
static mozilla::CSSStyleSheet* NoFramesSheet();
static mozilla::CSSStyleSheet* ChromePreferenceSheet(nsPresContext* aPresContext);
static mozilla::CSSStyleSheet* ContentPreferenceSheet(nsPresContext* aPresContext);
+ static mozilla::CSSStyleSheet* ContentEditableSheet();
+ static mozilla::CSSStyleSheet* DesignModeSheet();
static void InvalidatePreferenceSheets();
@@ -85,10 +86,11 @@ private:
static mozilla::StaticRefPtr gStyleCache;
static mozilla::css::Loader* gCSSLoader;
RefPtr mChromePreferenceSheet;
+ RefPtr mContentEditableSheet;
RefPtr mContentPreferenceSheet;
RefPtr mCounterStylesSheet;
+ RefPtr mDesignModeSheet;
RefPtr mFormsSheet;
- RefPtr mFullScreenOverrideSheet;
RefPtr mHTMLSheet;
RefPtr mMathMLSheet;
RefPtr mMinimalXULSheet;
diff --git a/layout/style/nsRuleData.h b/layout/style/nsRuleData.h
index 3fed3a556c..f4d098c8ec 100644
--- a/layout/style/nsRuleData.h
+++ b/layout/style/nsRuleData.h
@@ -13,6 +13,7 @@
#include "mozilla/CSSVariableDeclarations.h"
#include "mozilla/RuleNodeCacheConditions.h"
+#include "mozilla/SheetType.h"
#include "nsCSSProps.h"
#include "nsCSSValue.h"
#include "nsStyleStructFwd.h"
@@ -28,7 +29,7 @@ struct nsRuleData
const uint32_t mSIDs;
mozilla::RuleNodeCacheConditions mConditions;
bool mIsImportantRule;
- uint16_t mLevel; // an nsStyleSet::sheetType
+ mozilla::SheetType mLevel;
nsPresContext* const mPresContext;
nsStyleContext* const mStyleContext;
diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp
index 4428d539fd..6130c8b2ff 100644
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -66,12 +66,36 @@ using std::min;
using namespace mozilla;
using namespace mozilla::dom;
-#define NS_SET_IMAGE_REQUEST(method_, context_, request_) \
+void*
+nsConditionalResetStyleData::GetConditionalStyleData(nsStyleStructID aSID,
+ nsStyleContext* aStyleContext) const
+{
+ Entry* e = static_cast(mEntries[aSID]);
+ MOZ_ASSERT(e, "if mConditionalBits bit is set, we must have at least one "
+ "conditional style struct");
+ do {
+ if (e->mConditions.Matches(aStyleContext)) {
+ void* data = e->mStyleStruct;
+
+ // For reset structs with conditions, we cache the data on the
+ // style context.
+ // Tell the style context that it doesn't own the data
+ aStyleContext->AddStyleBit(GetBitForSID(aSID));
+ aStyleContext->SetStyle(aSID, data);
+
+ return data;
+ }
+ e = e->mNext;
+ } while (e);
+ return nullptr;
+}
+
+#define NS_SET_IMAGE_REQUEST(method_, context_, request_) \
if ((context_)->PresContext()->IsDynamic()) { \
- method_(request_); \
- } else { \
+ method_(request_); \
+ } else { \
RefPtr req = nsContentUtils::GetStaticRequest(request_); \
- method_(req); \
+ method_(req); \
}
#define NS_SET_IMAGE_REQUEST_WITH_DOC(method_, context_, requestgetter_) \
@@ -505,6 +529,10 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
}
switch (aValue.GetUnit()) {
case eCSSUnit_EM: {
+ if (aValue.GetFloatValue() == 0.0f) {
+ // Don't call SetFontSizeDependency for '0em'.
+ return 0;
+ }
// CSS2.1 specifies that this unit scales to the computed font
// size, not the em-width in the font metrics, despite the name.
aConditions.SetFontSizeDependency(aFontSize);
@@ -1466,11 +1494,11 @@ nsRuleNode::DestroyInternal(nsRuleNode ***aDestroyQueueTail)
nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
{
return new (aPresContext)
- nsRuleNode(aPresContext, nullptr, nullptr, 0xff, false);
+ nsRuleNode(aPresContext, nullptr, nullptr, SheetType::Unknown, false);
}
nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
- nsIStyleRule* aRule, uint8_t aLevel,
+ nsIStyleRule* aRule, SheetType aLevel,
bool aIsImportant)
: mPresContext(aContext),
mParent(aParent),
@@ -1505,9 +1533,9 @@ nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
// nsStyleSet::GetContext depends on there being only one animation
// rule.
- MOZ_ASSERT(IsRoot() || GetLevel() != nsStyleSet::eAnimationSheet ||
+ MOZ_ASSERT(IsRoot() || GetLevel() != SheetType::Animation ||
mParent->IsRoot() ||
- mParent->GetLevel() != nsStyleSet::eAnimationSheet,
+ mParent->GetLevel() != SheetType::Animation,
"must be only one rule at animation level");
}
@@ -1522,7 +1550,7 @@ nsRuleNode::~nsRuleNode()
}
nsRuleNode*
-nsRuleNode::Transition(nsIStyleRule* aRule, uint8_t aLevel,
+nsRuleNode::Transition(nsIStyleRule* aRule, SheetType aLevel,
bool aIsImportantRule)
{
nsRuleNode* next = nullptr;
@@ -2181,6 +2209,12 @@ nsRuleNode::ResolveVariableReferences(const nsStyleStructID aSID,
&aContext->StyleVariables()->mVariables;
nsCSSValueTokenStream* tokenStream = value->GetTokenStreamValue();
+ MOZ_ASSERT(tokenStream->mLevel != SheetType::Count,
+ "Token stream should have a defined level");
+
+ AutoRestore saveLevel(aRuleData->mLevel);
+ aRuleData->mLevel = tokenStream->mLevel;
+
// Note that ParsePropertyWithVariableReferences relies on the fact
// that the nsCSSValue in aRuleData for the property we are re-parsing
// is still the token stream value. When
@@ -2339,6 +2373,11 @@ nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
// branch that they never need to examine their rules for this particular struct type
// ever again.
PropagateDependentBit(aSID, ruleNode, startStruct);
+ // For inherited structs, mark the struct (which will be set on
+ // the context by our caller) as not being owned by the context.
+ if (!isReset) {
+ aContext->AddStyleBit(nsCachedStyleData::GetBitForSID(aSID));
+ }
return startStruct;
}
if ((!startStruct && !isReset &&
@@ -2708,11 +2747,10 @@ nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContex
/* Propagate the bit down. */ \
PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_); \
/* Tell the style context that it doesn't own the data */ \
- aContext-> \
- AddStyleBit(nsCachedStyleData::GetBitForSID(eStyleStruct_##type_)); \
+ aContext->AddStyleBit(NS_STYLE_INHERIT_BIT(type_)); \
} \
- /* Always cache inherited data on the style context */ \
- aContext->SetStyle##type_(data_); \
+ /* For inherited structs, our caller will cache the data on the */ \
+ /* style context */ \
\
return data_;
@@ -2751,8 +2789,7 @@ nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContex
mStyleData.mResetData-> \
SetStyleData(eStyleStruct_##type_, mPresContext, data_, conditions); \
/* Tell the style context that it doesn't own the data */ \
- aContext-> \
- AddStyleBit(nsCachedStyleData::GetBitForSID(eStyleStruct_##type_)); \
+ aContext->AddStyleBit(NS_STYLE_INHERIT_BIT(type_)); \
aContext->SetStyle(eStyleStruct_##type_, data_); \
} else { \
/* We can't be cached in the rule node. We have to be put right */ \
@@ -4375,7 +4412,7 @@ nsRuleNode::ComputeTextData(void* aStartStruct,
conditions,
SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
parentText->mControlCharacterVisibility,
- NS_STYLE_CONTROL_CHARACTER_VISIBILITY_VISIBLE, 0, 0, 0, 0);
+ nsCSSParser::ControlCharVisibilityDefault(), 0, 0, 0, 0);
COMPUTE_END_INHERITED(Text, text)
}
@@ -4815,8 +4852,9 @@ CountTransitionProps(const TransitionPropInfo* aInfo,
return numTransitions;
}
-static void
-ComputeTimingFunction(const nsCSSValue& aValue, nsTimingFunction& aResult)
+/* static */ void
+nsRuleNode::ComputeTimingFunction(const nsCSSValue& aValue,
+ nsTimingFunction& aResult)
{
switch (aValue.GetUnit()) {
case eCSSUnit_Enumerated:
@@ -5442,6 +5480,13 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct,
parentDisplay->mIsolation, NS_STYLE_ISOLATION_AUTO,
0, 0, 0, 0);
+ // -moz-top-layer: enum, inherit, initial
+ SetDiscrete(*aRuleData->ValueForTopLayer(), display->mTopLayer,
+ conditions,
+ SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
+ parentDisplay->mTopLayer, NS_STYLE_TOP_LAYER_NONE,
+ 0, 0, 0, 0);
+
// Backup original display value for calculation of a hypothetical
// box (CSS2 10.6.4/10.6.5), in addition to getting our style data right later.
// See nsHTMLReflowState::CalculateHypotheticalBox
@@ -5481,6 +5526,16 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct,
SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
parentDisplay->mPosition,
NS_STYLE_POSITION_STATIC, 0, 0, 0, 0);
+ // If an element is put in the top layer, while it is not absolutely
+ // positioned, the position value should be computed to 'absolute' per
+ // the Fullscreen API spec.
+ if (display->mTopLayer != NS_STYLE_TOP_LAYER_NONE &&
+ !display->IsAbsolutelyPositionedStyle()) {
+ display->mPosition = NS_STYLE_POSITION_ABSOLUTE;
+ // We cannot cache this struct because otherwise it may be used as
+ // an aStartStruct for some other elements.
+ conditions.SetUncacheable();
+ }
// clear: enum, inherit, initial
SetDiscrete(*aRuleData->ValueForClear(), display->mBreakType, conditions,
@@ -9364,15 +9419,23 @@ nsRuleNode::GetStyleData(nsStyleStructID aSID,
"if we ever call this on rule nodes that aren't used "
"directly, we should adjust handling of mDependentBits "
"in some way.");
+ MOZ_ASSERT(!aContext->GetCachedStyleData(aSID),
+ "style context should not have cached data for struct");
const void *data;
// Never use cached data for animated style inside a pseudo-element;
// see comment on cacheability in AnimValuesStyleRule::MapRuleInfoInto.
if (!(HasAnimationData() && ParentHasPseudoElementData(aContext))) {
- data = mStyleData.GetStyleData(aSID, aContext);
- if (MOZ_LIKELY(data != nullptr))
+ data = mStyleData.GetStyleData(aSID, aContext, aComputeData);
+ if (MOZ_LIKELY(data != nullptr)) {
+ // For inherited structs, mark the struct (which will be set on
+ // the context by our caller) as not being owned by the context.
+ if (!nsCachedStyleData::IsReset(aSID)) {
+ aContext->AddStyleBit(nsCachedStyleData::GetBitForSID(aSID));
+ }
return data; // We have a fully specified struct. Just return it.
+ }
}
if (MOZ_UNLIKELY(!aComputeData))
@@ -9663,8 +9726,8 @@ nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
rule->MapRuleInfoInto(&ruleData);
- if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
- ruleData.mLevel == nsStyleSet::eUserSheet) {
+ if (ruleData.mLevel == SheetType::Agent ||
+ ruleData.mLevel == SheetType::User) {
// This is a rule whose effect we want to ignore, so if any of
// the properties we care about were set, set them to the dummy
// value that they'll never otherwise get.
@@ -9786,7 +9849,7 @@ nsRuleNode::ComputePropertiesOverridingAnimation(
// property) for transitions yet (which will make their
// MapRuleInfoInto skip the properties that are currently
// animating), we should skip them explicitly.
- if (ruleData.mLevel == nsStyleSet::eTransitionSheet) {
+ if (ruleData.mLevel == SheetType::Transition) {
continue;
}
@@ -9836,3 +9899,12 @@ nsRuleNode::ParentHasPseudoElementData(nsStyleContext* aContext)
nsStyleContext* parent = aContext->GetParent();
return parent && parent->HasPseudoElementData();
}
+
+#ifdef DEBUG
+bool
+nsRuleNode::ContextHasCachedData(nsStyleContext* aContext,
+ nsStyleStructID aSID)
+{
+ return !!aContext->GetCachedStyleData(aSID);
+}
+#endif
diff --git a/layout/style/nsRuleNode.h b/layout/style/nsRuleNode.h
index 3e8014e5bf..26dbe0673f 100644
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -15,6 +15,7 @@
#include "mozilla/PodOperations.h"
#include "mozilla/RangedArray.h"
#include "mozilla/RuleNodeCacheConditions.h"
+#include "mozilla/SheetType.h"
#include "nsPresContext.h"
#include "nsStyleStruct.h"
@@ -159,22 +160,29 @@ struct nsConditionalResetStyleData
}
void* GetStyleData(nsStyleStructID aSID,
- nsStyleContext* aStyleContext) const {
+ nsStyleContext* aStyleContext,
+ bool aCanComputeData) const {
if (!(mConditionalBits & GetBitForSID(aSID))) {
return mEntries[aSID];
}
- Entry* e = static_cast(mEntries[aSID]);
- MOZ_ASSERT(e, "if mConditionalBits bit is set, we must have at least one "
- "conditional style struct");
- do {
- if (e->mConditions.Matches(aStyleContext)) {
- return e->mStyleStruct;
- }
- e = e->mNext;
- } while (e);
- return nullptr;
+ if (!aCanComputeData) {
+ // If aCanComputeData is false, then any previously-computed data
+ // would have been cached on the style context. Therefore it's
+ // unnecessary to check the conditional data. It's also
+ // incorrect, because calling e->mConditions.Matches() below could
+ // cause additional structs to be computed, which is incorrect
+ // during CalcStyleDifference.
+ return nullptr;
+ }
+ return GetConditionalStyleData(aSID, aStyleContext);
}
+private:
+ // non-inline helper for GetStyleData
+ void* GetConditionalStyleData(nsStyleStructID aSID,
+ nsStyleContext* aStyleContext) const;
+
+public:
void SetStyleData(nsStyleStructID aSID, void* aStyleStruct) {
MOZ_ASSERT(!(mConditionalBits & GetBitForSID(aSID)),
"rule node should not have unconditional and conditional style "
@@ -273,10 +281,11 @@ struct nsCachedStyleData
}
void* NS_FASTCALL GetStyleData(const nsStyleStructID aSID,
- nsStyleContext* aStyleContext) {
+ nsStyleContext* aStyleContext,
+ bool aCanComputeData) {
if (IsReset(aSID)) {
if (mResetData) {
- return mResetData->GetStyleData(aSID, aStyleContext);
+ return mResetData->GetStyleData(aSID, aStyleContext, aCanComputeData);
}
} else {
if (mInheritedData) {
@@ -308,9 +317,12 @@ struct nsCachedStyleData
mInheritedData->mStyleStructs[eStyleStruct_##name_]) : nullptr; \
}
#define STYLE_STRUCT_RESET(name_, checkdata_cb_) \
- nsStyle##name_ * NS_FASTCALL GetStyle##name_ (nsStyleContext* aContext) { \
+ nsStyle##name_ * NS_FASTCALL GetStyle##name_ (nsStyleContext* aContext, \
+ bool aCanComputeData) { \
return mResetData ? static_cast( \
- mResetData->GetStyleData(eStyleStruct_##name_, aContext)) : nullptr; \
+ mResetData->GetStyleData(eStyleStruct_##name_, aContext, \
+ aCanComputeData)) \
+ : nullptr; \
}
#include "nsStyleStructList.h"
#undef STYLE_STRUCT_RESET
@@ -418,10 +430,10 @@ private:
struct Key {
nsIStyleRule* mRule;
- uint8_t mLevel;
+ mozilla::SheetType mLevel;
bool mIsImportantRule;
- Key(nsIStyleRule* aRule, uint8_t aLevel, bool aIsImportantRule)
+ Key(nsIStyleRule* aRule, mozilla::SheetType aLevel, bool aIsImportantRule)
: mRule(aRule), mLevel(aLevel), mIsImportantRule(aIsImportantRule)
{}
@@ -800,7 +812,7 @@ protected:
private:
nsRuleNode(nsPresContext* aPresContext, nsRuleNode* aParent,
- nsIStyleRule* aRule, uint8_t aLevel, bool aIsImportant);
+ nsIStyleRule* aRule, mozilla::SheetType aLevel, bool aIsImportant);
~nsRuleNode();
public:
@@ -812,7 +824,7 @@ public:
static void EnsureInlineDisplay(uint8_t& display);
// Transition never returns null; on out of memory it'll just return |this|.
- nsRuleNode* Transition(nsIStyleRule* aRule, uint8_t aLevel,
+ nsRuleNode* Transition(nsIStyleRule* aRule, mozilla::SheetType aLevel,
bool aIsImportantRule);
nsRuleNode* GetParent() const { return mParent; }
bool IsRoot() const { return mParent == nullptr; }
@@ -823,11 +835,11 @@ public:
return const_cast(this)->RuleTree();
}
- // These uint8_ts are really nsStyleSet::sheetType values.
- uint8_t GetLevel() const {
+ mozilla::SheetType GetLevel() const {
NS_ASSERTION(!IsRoot(), "can't call on root");
- return (mDependentBits & NS_RULE_NODE_LEVEL_MASK) >>
- NS_RULE_NODE_LEVEL_SHIFT;
+ return mozilla::SheetType(
+ (mDependentBits & NS_RULE_NODE_LEVEL_MASK) >>
+ NS_RULE_NODE_LEVEL_SHIFT);
}
bool IsImportantRule() const {
NS_ASSERTION(!IsRoot(), "can't call on root");
@@ -882,12 +894,14 @@ public:
#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
template \
const nsStyle##name_* \
- GetStyle##name_(nsStyleContext* aContext) \
+ GetStyle##name_(nsStyleContext* aContext, uint64_t& aContextStyleBits) \
{ \
NS_ASSERTION(IsUsedDirectly(), \
"if we ever call this on rule nodes that aren't used " \
"directly, we should adjust handling of mDependentBits " \
"in some way."); \
+ MOZ_ASSERT(!ContextHasCachedData(aContext, eStyleStruct_##name_), \
+ "style context should not have cached data for struct"); \
\
const nsStyle##name_ *data; \
\
@@ -895,8 +909,15 @@ public:
/* see comment on cacheability in AnimValuesStyleRule::MapRuleInfoInto */ \
if (!(HasAnimationData() && ParentHasPseudoElementData(aContext))) { \
data = mStyleData.GetStyle##name_(); \
- if (MOZ_LIKELY(data != nullptr)) \
+ if (data != nullptr) { \
+ /* For inherited structs, mark the struct (which will be set on */ \
+ /* the context by our caller) as not being owned by the context. */ \
+ /* Normally this would be aContext->AddStyleBit(), but aContext is */ \
+ /* an incomplete type here, so we work around that with a param. */ \
+ aContextStyleBits |= NS_STYLE_INHERIT_BIT(name_); \
+ /* Our caller will cache the data on the style context. */ \
return data; \
+ } \
} \
\
if (!aComputeData) \
@@ -918,15 +939,18 @@ public:
"if we ever call this on rule nodes that aren't used " \
"directly, we should adjust handling of mDependentBits " \
"in some way."); \
+ MOZ_ASSERT(!ContextHasCachedData(aContext, eStyleStruct_##name_), \
+ "style context should not have cached data for struct"); \
\
const nsStyle##name_ *data; \
\
/* Never use cached data for animated style inside a pseudo-element; */ \
/* see comment on cacheability in AnimValuesStyleRule::MapRuleInfoInto */ \
if (!(HasAnimationData() && ParentHasPseudoElementData(aContext))) { \
- data = mStyleData.GetStyle##name_(aContext); \
- if (MOZ_LIKELY(data != nullptr)) \
+ data = mStyleData.GetStyle##name_(aContext, aComputeData); \
+ if (MOZ_LIKELY(data != nullptr)) { \
return data; \
+ } \
} \
\
if (!aComputeData) \
@@ -1053,6 +1077,17 @@ public:
nscolor& aResult);
static bool ParentHasPseudoElementData(nsStyleContext* aContext);
+
+ static void ComputeTimingFunction(const nsCSSValue& aValue,
+ nsTimingFunction& aResult);
+
+private:
+#ifdef DEBUG
+ // non-inline helper function to allow assertions without incomplete
+ // type errors
+ bool ContextHasCachedData(nsStyleContext* aContext, nsStyleStructID aSID);
+#endif
+
};
#endif
diff --git a/layout/style/nsRuleWalker.h b/layout/style/nsRuleWalker.h
index f2c4a7de7e..51e2228a7e 100644
--- a/layout/style/nsRuleWalker.h
+++ b/layout/style/nsRuleWalker.h
@@ -54,7 +54,7 @@ public:
bool AtRoot() { return mCurrent == mRoot; }
- void SetLevel(uint8_t aLevel, bool aImportance,
+ void SetLevel(mozilla::SheetType aLevel, bool aImportance,
bool aCheckForImportantRules) {
NS_ASSERTION(!aCheckForImportantRules || !aImportance,
"Shouldn't be checking for important rules while walking "
@@ -63,7 +63,7 @@ public:
mImportance = aImportance;
mCheckForImportantRules = aCheckForImportantRules;
}
- uint8_t GetLevel() const { return mLevel; }
+ mozilla::SheetType GetLevel() const { return mLevel; }
bool GetImportance() const { return mImportance; }
bool GetCheckForImportantRules() const { return mCheckForImportantRules; }
@@ -86,7 +86,7 @@ public:
private:
nsRuleNode* mCurrent; // Our current position. Never null.
nsRuleNode* mRoot; // The root of the tree we're walking.
- uint8_t mLevel; // an nsStyleSet::sheetType
+ mozilla::SheetType mLevel;
bool mImportance;
bool mCheckForImportantRules; // If true, check for important rules as
// we walk and set to false if we find
diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h
index bb1ab6a7e5..c586b22e62 100644
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -866,6 +866,10 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_TOUCH_ACTION_PAN_Y (1 << 3)
#define NS_STYLE_TOUCH_ACTION_MANIPULATION (1 << 4)
+// See nsStyleDisplay
+#define NS_STYLE_TOP_LAYER_NONE 0 // not in the top layer
+#define NS_STYLE_TOP_LAYER_TOP 1 // in the top layer
+
// See nsStyleDisplay
#define NS_STYLE_TRANSFORM_BOX_BORDER_BOX 0
#define NS_STYLE_TRANSFORM_BOX_FILL_BOX 1
diff --git a/layout/style/nsStyleContext.cpp b/layout/style/nsStyleContext.cpp
index 448f61617b..771a08b7d6 100644
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -408,27 +408,19 @@ nsStyleContext::HasChildThatUsesGrandancestorStyle() const
ListContainsStyleContextThatUsesGrandancestorStyle(mChild);
}
-const void* nsStyleContext::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;
-}
-
const void* nsStyleContext::StyleData(nsStyleStructID aSID)
{
const void* cachedData = GetCachedStyleData(aSID);
if (cachedData)
return cachedData; // We have computed data stored on this node in the context tree.
- return mRuleNode->GetStyleData(aSID, this, true); // Our rule node will take care of it for us.
+ // Our rule node will take care of it for us.
+ const void* newData = mRuleNode->GetStyleData(aSID, this, true);
+ if (!nsCachedStyleData::IsReset(aSID)) {
+ // always cache inherited data on the style context; the rule
+ // node set the bit in mBits for us if needed.
+ mCachedInheritedData.mStyleStructs[aSID] = const_cast(newData);
+ }
+ return newData;
}
// This is an evil evil function, since it forces you to alloc your own separate copy of
@@ -840,19 +832,22 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther,
// we worry about 'inherit' values.)
bool compare = mRuleNode != aOther->mRuleNode;
+ DebugOnly structsFound = 0;
+
// If we had any change in variable values, then we'll need to examine
// all of the other style structs too, even if the new style context has
// the same rule node as the old one.
const nsStyleVariables* thisVariables = PeekStyleVariables();
if (thisVariables) {
+ structsFound |= NS_STYLE_INHERIT_BIT(Variables);
const nsStyleVariables* otherVariables = aOther->StyleVariables();
if (thisVariables->mVariables == otherVariables->mVariables) {
- *aEqualStructs |= nsCachedStyleData::GetBitForSID(eStyleStruct_Variables);
+ *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
} else {
compare = true;
}
} else {
- *aEqualStructs |= nsCachedStyleData::GetBitForSID(eStyleStruct_Variables);
+ *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
}
DebugOnly styleStructCount = 1; // count Variables already
@@ -861,6 +856,7 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther,
PR_BEGIN_MACRO \
const nsStyle##struct_* this##struct_ = PeekStyle##struct_(); \
if (this##struct_) { \
+ structsFound |= NS_STYLE_INHERIT_BIT(struct_); \
const nsStyle##struct_* other##struct_ = aOther->Style##struct_(); \
nsChangeHint maxDifference = nsStyle##struct_::MaxDifference(); \
nsChangeHint differenceAlwaysHandledForDescendants = \
@@ -922,7 +918,7 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther,
DO_STRUCT_DIFFERENCE(SVGReset);
DO_STRUCT_DIFFERENCE(SVG);
#undef EXTRA_DIFF_ARGS
-#define EXTRA_DIFF_ARGS , this
+#define EXTRA_DIFF_ARGS , PeekStyleVisibility()
DO_STRUCT_DIFFERENCE(Position);
#undef EXTRA_DIFF_ARGS
#define EXTRA_DIFF_ARGS /* nothing */
@@ -940,6 +936,16 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther,
MOZ_ASSERT(styleStructCount == nsStyleStructID_Length,
"missing a call to DO_STRUCT_DIFFERENCE");
+#ifdef DEBUG
+ #define STYLE_STRUCT(name_, callback_) \
+ MOZ_ASSERT(!!(structsFound & NS_STYLE_INHERIT_BIT(name_)) == \
+ !!PeekStyle##name_(), \
+ "PeekStyleData results must not change in the middle of " \
+ "difference calculation.");
+ #include "nsStyleStructList.h"
+ #undef STYLE_STRUCT
+#endif
+
// We check for struct pointer equality here rather than as part of the
// DO_STRUCT_DIFFERENCE calls, since those calls can result in structs
// we previously examined and found to be null on this style context
@@ -1497,7 +1503,7 @@ nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
structs.Append(' ');
}
structs.AppendPrintf("%s=%p", StructName(i), data);
- if (HasCachedInheritedStyleData(i)) {
+ if (HasCachedDependentStyleData(i)) {
structs.AppendLiteral("(dependent)");
} else {
structs.AppendLiteral("(owned)");
diff --git a/layout/style/nsStyleContext.h b/layout/style/nsStyleContext.h
index 2c73dfa54b..c1998a972c 100644
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -282,11 +282,14 @@ public:
#undef STYLE_STRUCT_INHERITED
/**
- * Returns whether this style context has cached, inherited style data for a
- * given style struct.
+ * Returns whether this style context has cached style data for a
+ * given style struct and it does NOT own that struct. This can
+ * happen because it was inherited from the parent style context, or
+ * because it was stored conditionally on the rule node.
*/
- bool HasCachedInheritedStyleData(nsStyleStructID aSID)
- { return mBits & nsCachedStyleData::GetBitForSID(aSID); }
+ bool HasCachedDependentStyleData(nsStyleStructID aSID) {
+ return mBits & nsCachedStyleData::GetBitForSID(aSID);
+ }
nsRuleNode* RuleNode() { return mRuleNode; }
void AddStyleBit(const uint64_t& aBit) { mBits |= aBit; }
@@ -453,6 +456,28 @@ public:
int32_t& LoggingDepth();
#endif
+ /**
+ * 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;
+ }
+
private:
// Private destructor, to discourage deletion outside of Release():
~nsStyleContext();
@@ -469,10 +494,6 @@ private:
static bool ListContainsStyleContextThatUsesGrandancestorStyle(
const nsStyleContext* aHead);
- // Helper function that GetStyleData and GetUniqueStyleData use. Only
- // returns the structs we cache ourselves; never consults the ruletree.
- inline const void* GetCachedStyleData(nsStyleStructID aSID);
-
#ifdef DEBUG
struct AutoCheckDependency {
@@ -511,9 +532,20 @@ private:
mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]); \
if (cachedData) /* Have it cached already, yay */ \
return cachedData; \
+ if (!aComputeData) { \
+ /* We always cache inherited structs on the context when we */ \
+ /* compute them. */ \
+ return nullptr; \
+ } \
/* Have the rulenode deal */ \
AUTO_CHECK_DEPENDENCY(eStyleStruct_##name_); \
- return mRuleNode->GetStyle##name_(this); \
+ const nsStyle##name_ * newData = \
+ mRuleNode->GetStyle##name_(this, mBits); \
+ /* always cache inherited data on the style context; the rule */ \
+ /* node set the bit in mBits for us if needed. */ \
+ mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] = \
+ const_cast(newData); \
+ return newData; \
}
#define STYLE_STRUCT_RESET(name_, checkdata_cb_) \
template \
@@ -591,8 +623,15 @@ private:
// sometimes allocate the mCachedResetData.
nsResetStyleData* mCachedResetData; // Cached reset style data.
nsInheritedStyleData mCachedInheritedData; // Cached inherited style data
- uint64_t mBits; // Which structs are inherited from the
- // parent context or owned by mRuleNode.
+
+ // mBits stores a number of things:
+ // - It records (using the style struct bits) which structs are
+ // inherited from the parent context or owned by mRuleNode (i.e.,
+ // not owned by the style context).
+ // - It also stores the additional bits listed at the top of
+ // nsStyleStruct.h.
+ uint64_t mBits;
+
uint32_t mRefCnt;
#ifdef DEBUG
diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp
index 594bf9a04e..62b3909009 100644
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -13,6 +13,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/CSSStyleSheet.h"
+#include "mozilla/EnumeratedRange.h"
#include "mozilla/EventStates.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/RuleProcessorCache.h"
@@ -143,18 +144,18 @@ nsDisableTextZoomStyleRule::List(FILE* out, int32_t aIndent) const
}
#endif
-static const nsStyleSet::sheetType gCSSSheetTypes[] = {
+static const SheetType gCSSSheetTypes[] = {
// From lowest to highest in cascading order.
- nsStyleSet::eAgentSheet,
- nsStyleSet::eUserSheet,
- nsStyleSet::eDocSheet,
- nsStyleSet::eScopedDocSheet,
- nsStyleSet::eOverrideSheet
+ SheetType::Agent,
+ SheetType::User,
+ SheetType::Doc,
+ SheetType::ScopedDoc,
+ SheetType::Override
};
-static bool IsCSSSheetType(nsStyleSet::sheetType aSheetType)
+static bool IsCSSSheetType(SheetType aSheetType)
{
- for (nsStyleSet::sheetType type : gCSSSheetTypes) {
+ for (SheetType type : gCSSSheetTypes) {
if (type == aSheetType) {
return true;
}
@@ -177,7 +178,7 @@ nsStyleSet::nsStyleSet()
nsStyleSet::~nsStyleSet()
{
- for (sheetType type : gCSSSheetTypes) {
+ for (SheetType type : gCSSSheetTypes) {
for (uint32_t i = 0, n = mSheets[type].Length(); i < n; i++) {
static_cast(mSheets[type][i])->DropStyleSet(this);
}
@@ -185,12 +186,12 @@ nsStyleSet::~nsStyleSet()
// drop reference to cached rule processors
nsCSSRuleProcessor* rp;
- rp = static_cast(mRuleProcessors[eAgentSheet].get());
+ rp = static_cast(mRuleProcessors[SheetType::Agent].get());
if (rp) {
MOZ_ASSERT(rp->IsShared());
rp->ReleaseStyleSetRef();
}
- rp = static_cast(mRuleProcessors[eUserSheet].get());
+ rp = static_cast(mRuleProcessors[SheetType::User].get());
if (rp) {
MOZ_ASSERT(rp->IsShared());
rp->ReleaseStyleSetRef();
@@ -202,17 +203,17 @@ nsStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
- for (int i = 0; i < eSheetTypeCount; i++) {
- if (mRuleProcessors[i]) {
+ for (SheetType type : MakeEnumeratedRange(SheetType::Count)) {
+ if (mRuleProcessors[type]) {
bool shared = false;
- if (i == eAgentSheet || i == eUserSheet) {
+ if (type == SheetType::Agent || type == SheetType::User) {
// The only two origins we consider caching rule processors for.
nsCSSRuleProcessor* rp =
- static_cast(mRuleProcessors[i].get());
+ static_cast(mRuleProcessors[type].get());
shared = rp->IsShared();
}
if (!shared) {
- n += mRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
+ n += mRuleProcessors[type]->SizeOfIncludingThis(aMallocSizeOf);
}
}
// mSheets is a C-style array of nsCOMArrays. We do not own the sheets in
@@ -220,7 +221,7 @@ nsStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
// document owns them) so we do not count the sheets here (we pass nullptr
// as the aSizeOfElementIncludingThis argument). All we're doing here is
// counting the size of the nsCOMArrays' buffers.
- n += mSheets[i].SizeOfExcludingThis(nullptr, aMallocSizeOf);
+ n += mSheets[type].SizeOfExcludingThis(nullptr, aMallocSizeOf);
}
for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
@@ -246,12 +247,12 @@ nsStyleSet::Init(nsPresContext *aPresContext)
// Make an explicit GatherRuleProcessors call for the levels that
// don't have style sheets. The other levels will have their calls
- // triggered by DirtyRuleProcessors. (We should probably convert the
- // ePresHintSheet and eStyleAttrSheet levels to work like this as
- // well, and not implement nsIStyleSheet.)
- GatherRuleProcessors(eAnimationSheet);
- GatherRuleProcessors(eTransitionSheet);
- GatherRuleProcessors(eSVGAttrAnimationSheet);
+ // triggered by DirtyRuleProcessors.
+ GatherRuleProcessors(SheetType::PresHint);
+ GatherRuleProcessors(SheetType::SVGAttrAnimation);
+ GatherRuleProcessors(SheetType::StyleAttr);
+ GatherRuleProcessors(SheetType::Animation);
+ GatherRuleProcessors(SheetType::Transition);
}
nsresult
@@ -387,8 +388,10 @@ SortStyleSheetsByScope(nsTArray& aSheets)
}
nsresult
-nsStyleSet::GatherRuleProcessors(sheetType aType)
+nsStyleSet::GatherRuleProcessors(SheetType aType)
{
+ NS_ENSURE_FALSE(mInShutdown, NS_ERROR_FAILURE);
+
// We might be in GatherRuleProcessors because we are dropping a sheet,
// resulting in an nsCSSSelector being destroyed. Tell the
// RestyleManager for each document we're used in so that they can
@@ -399,7 +402,7 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
}
nsCOMPtr oldRuleProcessor(mRuleProcessors[aType]);
nsTArray> oldScopedDocRuleProcessors;
- if (aType == eAgentSheet || aType == eUserSheet) {
+ if (aType == SheetType::Agent || aType == SheetType::User) {
// drop reference to cached rule processor
nsCSSRuleProcessor* rp =
static_cast(mRuleProcessors[aType].get());
@@ -409,7 +412,7 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
}
}
mRuleProcessors[aType] = nullptr;
- if (aType == eScopedDocSheet) {
+ if (aType == SheetType::ScopedDoc) {
for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
nsIStyleRuleProcessor* processor = mScopedDocSheetRuleProcessors[i].get();
Element* scope =
@@ -420,9 +423,9 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
// Clear mScopedDocSheetRuleProcessors, but save it.
oldScopedDocRuleProcessors.SwapElements(mScopedDocSheetRuleProcessors);
}
- if (mAuthorStyleDisabled && (aType == eDocSheet ||
- aType == eScopedDocSheet ||
- aType == eStyleAttrSheet)) {
+ if (mAuthorStyleDisabled && (aType == SheetType::Doc ||
+ aType == SheetType::ScopedDoc ||
+ aType == SheetType::StyleAttr)) {
// Don't regather if this level is disabled. Note that we gather
// preshint sheets no matter what, but then skip them for some
// elements later if mAuthorStyleDisabled.
@@ -431,24 +434,24 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
switch (aType) {
// handle the types for which have a rule processor that does not
// implement the style sheet interface.
- case eAnimationSheet:
+ case SheetType::Animation:
MOZ_ASSERT(mSheets[aType].IsEmpty());
mRuleProcessors[aType] = PresContext()->AnimationManager();
return NS_OK;
- case eTransitionSheet:
+ case SheetType::Transition:
MOZ_ASSERT(mSheets[aType].IsEmpty());
mRuleProcessors[aType] = PresContext()->TransitionManager();
return NS_OK;
- case eStyleAttrSheet:
+ case SheetType::StyleAttr:
MOZ_ASSERT(mSheets[aType].IsEmpty());
mRuleProcessors[aType] = PresContext()->Document()->GetInlineStyleSheet();
return NS_OK;
- case ePresHintSheet:
+ case SheetType::PresHint:
MOZ_ASSERT(mSheets[aType].IsEmpty());
mRuleProcessors[aType] =
PresContext()->Document()->GetAttributeStyleSheet();
return NS_OK;
- case eSVGAttrAnimationSheet:
+ case SheetType::SVGAttrAnimation:
MOZ_ASSERT(mSheets[aType].IsEmpty());
mRuleProcessors[aType] =
PresContext()->Document()->GetSVGAttrAnimationRuleProcessor();
@@ -457,9 +460,9 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
// keep going
break;
}
- if (aType == eScopedDocSheet) {
+ if (aType == SheetType::ScopedDoc) {
// Create a rule processor for each scope.
- uint32_t count = mSheets[eScopedDocSheet].Count();
+ uint32_t count = mSheets[SheetType::ScopedDoc].Count();
if (count) {
// Gather the scoped style sheets into an array as
// CSSStyleSheets, and mark all of their scope elements
@@ -467,7 +470,7 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
nsTArray sheets(count);
for (uint32_t i = 0; i < count; i++) {
RefPtr sheet =
- do_QueryObject(mSheets[eScopedDocSheet].ObjectAt(i));
+ do_QueryObject(mSheets[SheetType::ScopedDoc].ObjectAt(i));
sheets.AppendElement(sheet);
Element* scope = sheet->GetScopeElement();
@@ -509,8 +512,7 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
sheetsForScope.AppendElements(sheets.Elements() + start, end - start);
nsCSSRuleProcessor* oldRP = oldScopedRuleProcessorHash.Get(scope);
mScopedDocSheetRuleProcessors.AppendElement
- (new nsCSSRuleProcessor(sheetsForScope, uint8_t(aType), scope,
- oldRP));
+ (new nsCSSRuleProcessor(sheetsForScope, aType, scope, oldRP));
start = end;
} while (start < count);
@@ -519,8 +521,8 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
}
if (mSheets[aType].Count()) {
switch (aType) {
- case eAgentSheet:
- case eUserSheet: {
+ case SheetType::Agent:
+ case SheetType::User: {
// levels containing non-scoped CSS style sheets whose rule processors
// we want to re-use
nsCOMArray& sheets = mSheets[aType];
@@ -537,7 +539,7 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
nsCSSRuleProcessor* rp =
RuleProcessorCache::GetRuleProcessor(cssSheetsRaw, PresContext());
if (!rp) {
- rp = new nsCSSRuleProcessor(cssSheets, uint8_t(aType), nullptr,
+ rp = new nsCSSRuleProcessor(cssSheets, aType, nullptr,
static_cast(
oldRuleProcessor.get()),
true /* aIsShared */);
@@ -553,8 +555,8 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
rp->AddStyleSetRef();
break;
}
- case eDocSheet:
- case eOverrideSheet: {
+ case SheetType::Doc:
+ case SheetType::Override: {
// levels containing non-scoped CSS stylesheets whose rule processors
// we don't want to re-use
nsCOMArray& sheets = mSheets[aType];
@@ -565,7 +567,7 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
cssSheets.AppendElement(cssSheet);
}
mRuleProcessors[aType] =
- new nsCSSRuleProcessor(cssSheets, uint8_t(aType), nullptr,
+ new nsCSSRuleProcessor(cssSheets, aType, nullptr,
static_cast(
oldRuleProcessor.get()));
} break;
@@ -591,7 +593,7 @@ IsScopedStyleSheet(nsIStyleSheet* aSheet)
}
nsresult
-nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
+nsStyleSet::AppendStyleSheet(SheetType aType, nsIStyleSheet *aSheet)
{
NS_PRECONDITION(aSheet, "null arg");
NS_ASSERTION(aSheet->IsApplicable(),
@@ -608,7 +610,7 @@ nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
}
nsresult
-nsStyleSet::PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
+nsStyleSet::PrependStyleSheet(SheetType aType, nsIStyleSheet *aSheet)
{
NS_PRECONDITION(aSheet, "null arg");
NS_ASSERTION(aSheet->IsApplicable(),
@@ -625,7 +627,7 @@ nsStyleSet::PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
}
nsresult
-nsStyleSet::RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
+nsStyleSet::RemoveStyleSheet(SheetType aType, nsIStyleSheet *aSheet)
{
NS_PRECONDITION(aSheet, "null arg");
NS_ASSERTION(aSheet->IsComplete(),
@@ -640,7 +642,7 @@ nsStyleSet::RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
}
nsresult
-nsStyleSet::ReplaceSheets(sheetType aType,
+nsStyleSet::ReplaceSheets(SheetType aType,
const nsCOMArray &aNewSheets)
{
bool cssSheetType = IsCSSSheetType(aType);
@@ -664,7 +666,7 @@ nsStyleSet::ReplaceSheets(sheetType aType,
}
nsresult
-nsStyleSet::InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet,
+nsStyleSet::InsertStyleSheetBefore(SheetType aType, nsIStyleSheet *aNewSheet,
nsIStyleSheet *aReferenceSheet)
{
NS_PRECONDITION(aNewSheet && aReferenceSheet, "null arg");
@@ -686,13 +688,19 @@ nsStyleSet::InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet,
return DirtyRuleProcessors(aType);
}
+static inline uint32_t
+DirtyBit(SheetType aType)
+{
+ return 1 << uint32_t(aType);
+}
+
nsresult
-nsStyleSet::DirtyRuleProcessors(sheetType aType)
+nsStyleSet::DirtyRuleProcessors(SheetType aType)
{
if (!mBatching)
return GatherRuleProcessors(aType);
- mDirty |= 1 << aType;
+ mDirty |= DirtyBit(aType);
return NS_OK;
}
@@ -708,9 +716,9 @@ nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
if (aStyleDisabled == !mAuthorStyleDisabled) {
mAuthorStyleDisabled = aStyleDisabled;
BeginUpdate();
- mDirty |= 1 << eDocSheet |
- 1 << eScopedDocSheet |
- 1 << eStyleAttrSheet;
+ mDirty |= DirtyBit(SheetType::Doc) |
+ DirtyBit(SheetType::ScopedDoc) |
+ DirtyBit(SheetType::StyleAttr);
return EndUpdate();
}
return NS_OK;
@@ -725,9 +733,9 @@ nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument)
NS_ASSERTION(aSheet->IsApplicable(),
"Inapplicable sheet being placed in style set");
- sheetType type = IsScopedStyleSheet(aSheet) ?
- eScopedDocSheet :
- eDocSheet;
+ SheetType type = IsScopedStyleSheet(aSheet) ?
+ SheetType::ScopedDoc :
+ SheetType::Doc;
nsCOMArray& sheets = mSheets[type];
bool present = sheets.RemoveObject(aSheet);
@@ -769,7 +777,8 @@ nsStyleSet::RemoveDocStyleSheet(nsIStyleSheet *aSheet)
{
RefPtr cssSheet = do_QueryObject(aSheet);
bool isScoped = cssSheet && cssSheet->GetScopeElement();
- return RemoveStyleSheet(isScoped ? eScopedDocSheet : eDocSheet, aSheet);
+ return RemoveStyleSheet(isScoped ? SheetType::ScopedDoc : SheetType::Doc,
+ aSheet);
}
// Batching
@@ -788,9 +797,9 @@ nsStyleSet::EndUpdate()
return NS_OK;
}
- for (int i = 0; i < eSheetTypeCount; ++i) {
- if (mDirty & (1 << i)) {
- nsresult rv = GatherRuleProcessors(sheetType(i));
+ for (SheetType type : MakeEnumeratedRange(SheetType::Count)) {
+ if (mDirty & DirtyBit(type)) {
+ nsresult rv = GatherRuleProcessors(type);
NS_ENSURE_SUCCESS(rv, rv);
}
}
@@ -812,7 +821,7 @@ static inline bool
IsMoreSpecificThanAnimation(nsRuleNode *aRuleNode)
{
return !aRuleNode->IsRoot() &&
- (aRuleNode->GetLevel() == nsStyleSet::eTransitionSheet ||
+ (aRuleNode->GetLevel() == SheetType::Transition ||
aRuleNode->IsImportantRule());
}
@@ -824,7 +833,7 @@ GetAnimationRule(nsRuleNode *aRuleNode)
n = n->GetParent();
}
- if (n->IsRoot() || n->GetLevel() != nsStyleSet::eAnimationSheet) {
+ if (n->IsRoot() || n->GetLevel() != SheetType::Animation) {
return nullptr;
}
@@ -846,17 +855,17 @@ ReplaceAnimationRule(nsRuleNode *aOldRuleNode,
if (aOldAnimRule) {
MOZ_ASSERT(n->GetRule() == aOldAnimRule, "wrong rule");
- MOZ_ASSERT(n->GetLevel() == nsStyleSet::eAnimationSheet,
+ MOZ_ASSERT(n->GetLevel() == SheetType::Animation,
"wrong level");
n = n->GetParent();
}
MOZ_ASSERT(!IsMoreSpecificThanAnimation(n) &&
- (n->IsRoot() || n->GetLevel() != nsStyleSet::eAnimationSheet),
+ (n->IsRoot() || n->GetLevel() != SheetType::Animation),
"wrong level");
if (aNewAnimRule) {
- n = n->Transition(aNewAnimRule, nsStyleSet::eAnimationSheet, false);
+ n = n->Transition(aNewAnimRule, SheetType::Animation, false);
n->SetIsAnimationRule();
}
@@ -1111,30 +1120,30 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
// this will be either the root or one of the restriction rules.
nsRuleNode* lastRestrictionRN = aRuleWalker->CurrentNode();
- aRuleWalker->SetLevel(eAgentSheet, false, true);
- if (mRuleProcessors[eAgentSheet])
- (*aCollectorFunc)(mRuleProcessors[eAgentSheet], aData);
+ aRuleWalker->SetLevel(SheetType::Agent, false, true);
+ if (mRuleProcessors[SheetType::Agent])
+ (*aCollectorFunc)(mRuleProcessors[SheetType::Agent], aData);
nsRuleNode* lastAgentRN = aRuleWalker->CurrentNode();
bool haveImportantUARules = !aRuleWalker->GetCheckForImportantRules();
- aRuleWalker->SetLevel(eUserSheet, false, true);
+ aRuleWalker->SetLevel(SheetType::User, false, true);
bool skipUserStyles =
aElement && aElement->IsInNativeAnonymousSubtree();
- if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
- (*aCollectorFunc)(mRuleProcessors[eUserSheet], aData);
+ if (!skipUserStyles && mRuleProcessors[SheetType::User]) // NOTE: different
+ (*aCollectorFunc)(mRuleProcessors[SheetType::User], aData);
nsRuleNode* lastUserRN = aRuleWalker->CurrentNode();
bool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
- aRuleWalker->SetLevel(ePresHintSheet, false, false);
- if (mRuleProcessors[ePresHintSheet])
- (*aCollectorFunc)(mRuleProcessors[ePresHintSheet], aData);
+ aRuleWalker->SetLevel(SheetType::PresHint, false, false);
+ if (mRuleProcessors[SheetType::PresHint])
+ (*aCollectorFunc)(mRuleProcessors[SheetType::PresHint], aData);
- aRuleWalker->SetLevel(eSVGAttrAnimationSheet, false, false);
- if (mRuleProcessors[eSVGAttrAnimationSheet])
- (*aCollectorFunc)(mRuleProcessors[eSVGAttrAnimationSheet], aData);
+ aRuleWalker->SetLevel(SheetType::SVGAttrAnimation, false, false);
+ if (mRuleProcessors[SheetType::SVGAttrAnimation])
+ (*aCollectorFunc)(mRuleProcessors[SheetType::SVGAttrAnimation], aData);
nsRuleNode* lastSVGAttrAnimationRN = aRuleWalker->CurrentNode();
- aRuleWalker->SetLevel(eDocSheet, false, true);
+ aRuleWalker->SetLevel(SheetType::Doc, false, true);
bool cutOffInheritance = false;
if (mBindingManager && aElement) {
// We can supply additional document-level sheets that should be walked.
@@ -1143,8 +1152,8 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
&cutOffInheritance);
}
if (!skipUserStyles && !cutOffInheritance && // NOTE: different
- mRuleProcessors[eDocSheet])
- (*aCollectorFunc)(mRuleProcessors[eDocSheet], aData);
+ mRuleProcessors[SheetType::Doc])
+ (*aCollectorFunc)(mRuleProcessors[SheetType::Doc], aData);
nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
bool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
nsTArray lastScopedRNs;
@@ -1155,7 +1164,7 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
lastScopedRNs.SetLength(mScopedDocSheetRuleProcessors.Length());
haveImportantScopedRules.SetLength(mScopedDocSheetRuleProcessors.Length());
for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
- aRuleWalker->SetLevel(eScopedDocSheet, false, true);
+ aRuleWalker->SetLevel(SheetType::ScopedDoc, false, true);
nsCSSRuleProcessor* processor =
static_cast(mScopedDocSheetRuleProcessors[i].get());
aData->mScope = processor->GetScopeElement();
@@ -1167,25 +1176,25 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
aData->mScope = nullptr;
}
nsRuleNode* lastScopedRN = aRuleWalker->CurrentNode();
- aRuleWalker->SetLevel(eStyleAttrSheet, false, true);
- if (mRuleProcessors[eStyleAttrSheet])
- (*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
+ aRuleWalker->SetLevel(SheetType::StyleAttr, false, true);
+ if (mRuleProcessors[SheetType::StyleAttr])
+ (*aCollectorFunc)(mRuleProcessors[SheetType::StyleAttr], aData);
nsRuleNode* lastStyleAttrRN = aRuleWalker->CurrentNode();
bool haveImportantStyleAttrRules = !aRuleWalker->GetCheckForImportantRules();
- aRuleWalker->SetLevel(eOverrideSheet, false, true);
- if (mRuleProcessors[eOverrideSheet])
- (*aCollectorFunc)(mRuleProcessors[eOverrideSheet], aData);
+ aRuleWalker->SetLevel(SheetType::Override, false, true);
+ if (mRuleProcessors[SheetType::Override])
+ (*aCollectorFunc)(mRuleProcessors[SheetType::Override], aData);
nsRuleNode* lastOvrRN = aRuleWalker->CurrentNode();
bool haveImportantOverrideRules = !aRuleWalker->GetCheckForImportantRules();
// This needs to match IsMoreSpecificThanAnimation() above.
- aRuleWalker->SetLevel(eAnimationSheet, false, false);
- (*aCollectorFunc)(mRuleProcessors[eAnimationSheet], aData);
+ aRuleWalker->SetLevel(SheetType::Animation, false, false);
+ (*aCollectorFunc)(mRuleProcessors[SheetType::Animation], aData);
if (haveAnyImportantScopedRules) {
for (uint32_t i = lastScopedRNs.Length(); i-- != 0; ) {
- aRuleWalker->SetLevel(eScopedDocSheet, true, false);
+ aRuleWalker->SetLevel(SheetType::ScopedDoc, true, false);
nsRuleNode* startRN = lastScopedRNs[i];
nsRuleNode* endRN = i == 0 ? lastDocRN : lastScopedRNs[i - 1];
if (haveImportantScopedRules[i]) {
@@ -1205,7 +1214,7 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
#endif
if (haveImportantDocRules) {
- aRuleWalker->SetLevel(eDocSheet, true, false);
+ aRuleWalker->SetLevel(SheetType::Doc, true, false);
AddImportantRules(lastDocRN, lastSVGAttrAnimationRN, aRuleWalker); // doc
}
#ifdef DEBUG
@@ -1215,7 +1224,7 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
#endif
if (haveImportantStyleAttrRules) {
- aRuleWalker->SetLevel(eStyleAttrSheet, true, false);
+ aRuleWalker->SetLevel(SheetType::StyleAttr, true, false);
AddImportantRules(lastStyleAttrRN, lastScopedRN, aRuleWalker); // style attr
}
#ifdef DEBUG
@@ -1225,7 +1234,7 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
#endif
if (haveImportantOverrideRules) {
- aRuleWalker->SetLevel(eOverrideSheet, true, false);
+ aRuleWalker->SetLevel(SheetType::Override, true, false);
AddImportantRules(lastOvrRN, lastStyleAttrRN, aRuleWalker); // override
}
#ifdef DEBUG
@@ -1239,7 +1248,7 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
#endif
if (haveImportantUserRules) {
- aRuleWalker->SetLevel(eUserSheet, true, false);
+ aRuleWalker->SetLevel(SheetType::User, true, false);
AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
}
#ifdef DEBUG
@@ -1249,7 +1258,7 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
#endif
if (haveImportantUARules) {
- aRuleWalker->SetLevel(eAgentSheet, true, false);
+ aRuleWalker->SetLevel(SheetType::Agent, true, false);
AddImportantRules(lastAgentRN, lastRestrictionRN, aRuleWalker); //agent
}
#ifdef DEBUG
@@ -1265,8 +1274,8 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
#ifdef DEBUG
nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
#endif
- aRuleWalker->SetLevel(eTransitionSheet, false, false);
- (*aCollectorFunc)(mRuleProcessors[eTransitionSheet], aData);
+ aRuleWalker->SetLevel(SheetType::Transition, false, false);
+ (*aCollectorFunc)(mRuleProcessors[SheetType::Transition], aData);
#ifdef DEBUG
AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
#endif
@@ -1282,18 +1291,18 @@ nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
{
NS_ASSERTION(mBatching == 0, "rule processors out of date");
- if (mRuleProcessors[eAgentSheet])
- (*aFunc)(mRuleProcessors[eAgentSheet], aData);
+ if (mRuleProcessors[SheetType::Agent])
+ (*aFunc)(mRuleProcessors[SheetType::Agent], aData);
bool skipUserStyles = aData->mElement->IsInNativeAnonymousSubtree();
- if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
- (*aFunc)(mRuleProcessors[eUserSheet], aData);
+ if (!skipUserStyles && mRuleProcessors[SheetType::User]) // NOTE: different
+ (*aFunc)(mRuleProcessors[SheetType::User], aData);
- if (mRuleProcessors[ePresHintSheet])
- (*aFunc)(mRuleProcessors[ePresHintSheet], aData);
+ if (mRuleProcessors[SheetType::PresHint])
+ (*aFunc)(mRuleProcessors[SheetType::PresHint], aData);
- if (mRuleProcessors[eSVGAttrAnimationSheet])
- (*aFunc)(mRuleProcessors[eSVGAttrAnimationSheet], aData);
+ if (mRuleProcessors[SheetType::SVGAttrAnimation])
+ (*aFunc)(mRuleProcessors[SheetType::SVGAttrAnimation], aData);
bool cutOffInheritance = false;
if (mBindingManager) {
@@ -1305,19 +1314,19 @@ nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
}
}
if (!skipUserStyles && !cutOffInheritance) {
- if (mRuleProcessors[eDocSheet]) // NOTE: different
- (*aFunc)(mRuleProcessors[eDocSheet], aData);
+ if (mRuleProcessors[SheetType::Doc]) // NOTE: different
+ (*aFunc)(mRuleProcessors[SheetType::Doc], aData);
if (aData->mElement->IsElementInStyleScope()) {
for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++)
(*aFunc)(mScopedDocSheetRuleProcessors[i], aData);
}
}
- if (mRuleProcessors[eStyleAttrSheet])
- (*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
- if (mRuleProcessors[eOverrideSheet])
- (*aFunc)(mRuleProcessors[eOverrideSheet], aData);
- (*aFunc)(mRuleProcessors[eAnimationSheet], aData);
- (*aFunc)(mRuleProcessors[eTransitionSheet], aData);
+ if (mRuleProcessors[SheetType::StyleAttr])
+ (*aFunc)(mRuleProcessors[SheetType::StyleAttr], aData);
+ if (mRuleProcessors[SheetType::Override])
+ (*aFunc)(mRuleProcessors[SheetType::Override], aData);
+ (*aFunc)(mRuleProcessors[SheetType::Animation], aData);
+ (*aFunc)(mRuleProcessors[SheetType::Transition], aData);
}
static void
@@ -1391,7 +1400,7 @@ nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
// FIXME: Perhaps this should be passed in, but it probably doesn't
// matter.
- ruleWalker.SetLevel(eDocSheet, false, false);
+ ruleWalker.SetLevel(SheetType::Doc, false, false);
for (uint32_t i = 0; i < aRules.Length(); i++) {
ruleWalker.ForwardOnPossiblyCSSRule(aRules.ElementAt(i));
}
@@ -1415,7 +1424,7 @@ nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
// resulting context. It's also the right thing for the one case (the
// transition manager's cover rule) where we put the result of this
// function in the style context tree.
- ruleWalker.SetLevel(eTransitionSheet, false, false);
+ ruleWalker.SetLevel(SheetType::Transition, false, false);
for (int32_t i = 0; i < aRules.Count(); i++) {
ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
}
@@ -1450,37 +1459,37 @@ nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
struct RuleNodeInfo {
nsIStyleRule* mRule;
- uint8_t mLevel;
+ SheetType mLevel;
bool mIsImportant;
bool mIsAnimationRule;
};
struct CascadeLevel {
- uint8_t mLevel;
+ SheetType mLevel;
bool mIsImportant;
bool mCheckForImportantRules;
nsRestyleHint mLevelReplacementHint;
};
static const CascadeLevel gCascadeLevels[] = {
- { nsStyleSet::eAgentSheet, false, false, nsRestyleHint(0) },
- { nsStyleSet::eUserSheet, false, false, nsRestyleHint(0) },
- { nsStyleSet::ePresHintSheet, false, false, nsRestyleHint(0) },
- { nsStyleSet::eSVGAttrAnimationSheet, false, false, eRestyle_SVGAttrAnimations },
- { nsStyleSet::eDocSheet, false, false, nsRestyleHint(0) },
- { nsStyleSet::eScopedDocSheet, false, false, nsRestyleHint(0) },
- { nsStyleSet::eStyleAttrSheet, false, true, eRestyle_StyleAttribute |
- eRestyle_StyleAttribute_Animations },
- { nsStyleSet::eOverrideSheet, false, false, nsRestyleHint(0) },
- { nsStyleSet::eAnimationSheet, false, false, eRestyle_CSSAnimations },
- { nsStyleSet::eScopedDocSheet, true, false, nsRestyleHint(0) },
- { nsStyleSet::eDocSheet, true, false, nsRestyleHint(0) },
- { nsStyleSet::eStyleAttrSheet, true, false, eRestyle_StyleAttribute |
- eRestyle_StyleAttribute_Animations },
- { nsStyleSet::eOverrideSheet, true, false, nsRestyleHint(0) },
- { nsStyleSet::eUserSheet, true, false, nsRestyleHint(0) },
- { nsStyleSet::eAgentSheet, true, false, nsRestyleHint(0) },
- { nsStyleSet::eTransitionSheet, false, false, eRestyle_CSSTransitions },
+ { SheetType::Agent, false, false, nsRestyleHint(0) },
+ { SheetType::User, false, false, nsRestyleHint(0) },
+ { SheetType::PresHint, false, false, nsRestyleHint(0) },
+ { SheetType::SVGAttrAnimation, false, false, eRestyle_SVGAttrAnimations },
+ { SheetType::Doc, false, false, nsRestyleHint(0) },
+ { SheetType::ScopedDoc, false, false, nsRestyleHint(0) },
+ { SheetType::StyleAttr, false, true, eRestyle_StyleAttribute |
+ eRestyle_StyleAttribute_Animations },
+ { SheetType::Override, false, false, nsRestyleHint(0) },
+ { SheetType::Animation, false, false, eRestyle_CSSAnimations },
+ { SheetType::ScopedDoc, true, false, nsRestyleHint(0) },
+ { SheetType::Doc, true, false, nsRestyleHint(0) },
+ { SheetType::StyleAttr, true, false, eRestyle_StyleAttribute |
+ eRestyle_StyleAttribute_Animations },
+ { SheetType::Override, true, false, nsRestyleHint(0) },
+ { SheetType::User, true, false, nsRestyleHint(0) },
+ { SheetType::Agent, true, false, nsRestyleHint(0) },
+ { SheetType::Transition, false, false, eRestyle_CSSTransitions },
};
nsRuleNode*
@@ -1545,7 +1554,7 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement,
if (doReplace) {
switch (level->mLevel) {
- case nsStyleSet::eAnimationSheet: {
+ case SheetType::Animation: {
if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
aPseudoType == nsCSSPseudoElements::ePseudo_before ||
aPseudoType == nsCSSPseudoElements::ePseudo_after) {
@@ -1558,7 +1567,7 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement,
}
break;
}
- case nsStyleSet::eTransitionSheet: {
+ case SheetType::Transition: {
if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
aPseudoType == nsCSSPseudoElements::ePseudo_before ||
aPseudoType == nsCSSPseudoElements::ePseudo_after) {
@@ -1571,22 +1580,22 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement,
}
break;
}
- case nsStyleSet::eSVGAttrAnimationSheet: {
+ case SheetType::SVGAttrAnimation: {
SVGAttrAnimationRuleProcessor* ruleProcessor =
static_cast(
- mRuleProcessors[eSVGAttrAnimationSheet].get());
+ mRuleProcessors[SheetType::SVGAttrAnimation].get());
if (ruleProcessor &&
aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
ruleProcessor->ElementRulesMatching(aElement, &ruleWalker);
}
break;
}
- case nsStyleSet::eStyleAttrSheet: {
+ case SheetType::StyleAttr: {
if (!level->mIsImportant) {
// First time through, we handle the non-!important rule.
nsHTMLCSSStyleSheet* ruleProcessor =
static_cast(
- mRuleProcessors[eStyleAttrSheet].get());
+ mRuleProcessors[SheetType::StyleAttr].get());
if (ruleProcessor) {
lastScopedRN = ruleWalker.CurrentNode();
if (aPseudoType ==
@@ -1766,7 +1775,7 @@ nsStyleSet::WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType,
nsRuleWalker* aRuleWalker)
{
// This needs to match GetPseudoRestriction in nsRuleNode.cpp.
- aRuleWalker->SetLevel(eAgentSheet, false, false);
+ aRuleWalker->SetLevel(SheetType::Agent, false, false);
if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter)
aRuleWalker->Forward(mFirstLetterRule);
else if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLine)
@@ -1778,7 +1787,7 @@ nsStyleSet::WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType,
void
nsStyleSet::WalkDisableTextZoomRule(Element* aElement, nsRuleWalker* aRuleWalker)
{
- aRuleWalker->SetLevel(eAgentSheet, false, false);
+ aRuleWalker->SetLevel(SheetType::Agent, false, false);
if (aElement->IsSVGElement(nsGkAtoms::text))
aRuleWalker->Forward(mDisableTextZoomStyleRule);
}
@@ -2019,7 +2028,7 @@ nsStyleSet::AppendFontFaceRules(nsTArray& aArray)
nsPresContext* presContext = PresContext();
for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
- if (gCSSSheetTypes[i] == eScopedDocSheet)
+ if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
continue;
nsCSSRuleProcessor *ruleProc = static_cast
(mRuleProcessors[gCSSSheetTypes[i]].get());
@@ -2037,7 +2046,7 @@ nsStyleSet::KeyframesRuleForName(const nsString& aName)
nsPresContext* presContext = PresContext();
for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
- if (gCSSSheetTypes[i] == eScopedDocSheet)
+ if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
continue;
nsCSSRuleProcessor *ruleProc = static_cast
(mRuleProcessors[gCSSSheetTypes[i]].get());
@@ -2059,7 +2068,7 @@ nsStyleSet::CounterStyleRuleForName(const nsAString& aName)
nsPresContext* presContext = PresContext();
for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
- if (gCSSSheetTypes[i] == eScopedDocSheet)
+ if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
continue;
nsCSSRuleProcessor *ruleProc = static_cast
(mRuleProcessors[gCSSSheetTypes[i]].get());
@@ -2135,7 +2144,7 @@ nsStyleSet::AppendPageRules(nsTArray& aArray)
nsPresContext* presContext = PresContext();
for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
- if (gCSSSheetTypes[i] == eScopedDocSheet)
+ if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
continue;
nsCSSRuleProcessor* ruleProc = static_cast
(mRuleProcessors[gCSSSheetTypes[i]].get());
@@ -2435,16 +2444,14 @@ nsStyleSet::MediumFeaturesChanged()
// We can't use WalkRuleProcessors without a content node.
nsPresContext* presContext = PresContext();
bool stylesChanged = false;
- for (uint32_t i = 0; i < ArrayLength(mRuleProcessors); ++i) {
- nsIStyleRuleProcessor *processor = mRuleProcessors[i];
+ for (nsIStyleRuleProcessor* processor : mRuleProcessors) {
if (!processor) {
continue;
}
bool thisChanged = processor->MediumFeaturesChanged(presContext);
stylesChanged = stylesChanged || thisChanged;
}
- for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); ++i) {
- nsIStyleRuleProcessor *processor = mScopedDocSheetRuleProcessors[i];
+ for (nsIStyleRuleProcessor* processor : mScopedDocSheetRuleProcessors) {
bool thisChanged = processor->MediumFeaturesChanged(presContext);
stylesChanged = stylesChanged || thisChanged;
}
@@ -2500,7 +2507,7 @@ nsStyleSet::InitialStyleRule()
}
bool
-nsStyleSet::HasRuleProcessorUsedByMultipleStyleSets(sheetType aSheetType)
+nsStyleSet::HasRuleProcessorUsedByMultipleStyleSets(SheetType aSheetType)
{
MOZ_ASSERT(size_t(aSheetType) < ArrayLength(mRuleProcessors));
if (!IsCSSSheetType(aSheetType) || !mRuleProcessors[aSheetType]) {
diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h
index eb463d4c12..1978c6bcbb 100644
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -14,7 +14,9 @@
#include "mozilla/Attributes.h"
#include "mozilla/CSSStyleSheet.h"
+#include "mozilla/EnumeratedArray.h"
#include "mozilla/MemoryReporting.h"
+#include "mozilla/SheetType.h"
#include "nsIStyleRuleProcessor.h"
#include "nsBindingManager.h"
@@ -304,46 +306,26 @@ class nsStyleSet final
mBindingManager = aBindingManager;
}
- // The "origins" of the CSS cascade, from lowest precedence to
- // highest (for non-!important rules).
- enum sheetType {
- eAgentSheet, // CSS
- eUserSheet, // CSS
- ePresHintSheet,
- eSVGAttrAnimationSheet,
- eDocSheet, // CSS
- eScopedDocSheet,
- eStyleAttrSheet,
- eOverrideSheet, // CSS
- eAnimationSheet,
- eTransitionSheet,
- eSheetTypeCount
- // be sure to keep the number of bits in |mDirty| below and in
- // NS_RULE_NODE_LEVEL_MASK updated when changing the number of sheet
- // types
- };
-
// APIs to manipulate the style sheet lists. The sheets in each
// list are stored with the most significant sheet last.
- nsresult AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
- nsresult PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
- nsresult RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
- nsresult ReplaceSheets(sheetType aType,
+ nsresult AppendStyleSheet(mozilla::SheetType aType, nsIStyleSheet *aSheet);
+ nsresult PrependStyleSheet(mozilla::SheetType aType, nsIStyleSheet *aSheet);
+ nsresult RemoveStyleSheet(mozilla::SheetType aType, nsIStyleSheet *aSheet);
+ nsresult ReplaceSheets(mozilla::SheetType aType,
const nsCOMArray &aNewSheets);
- nsresult InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet,
+ nsresult InsertStyleSheetBefore(mozilla::SheetType aType,
+ nsIStyleSheet *aNewSheet,
nsIStyleSheet *aReferenceSheet);
- nsresult DirtyRuleProcessors(sheetType aType);
-
// Enable/Disable entire author style level (Doc, ScopedDoc & PresHint levels)
bool GetAuthorStyleDisabled();
nsresult SetAuthorStyleDisabled(bool aStyleDisabled);
- int32_t SheetCount(sheetType aType) const {
+ int32_t SheetCount(mozilla::SheetType aType) const {
return mSheets[aType].Count();
}
- nsIStyleSheet* StyleSheetAt(sheetType aType, int32_t aIndex) const {
+ nsIStyleSheet* StyleSheetAt(mozilla::SheetType aType, int32_t aIndex) const {
return mSheets[aType].ObjectAt(aIndex);
}
@@ -403,21 +385,23 @@ class nsStyleSet final
nsIStyleRule* InitialStyleRule();
- bool HasRuleProcessorUsedByMultipleStyleSets(sheetType aSheetType);
+ bool HasRuleProcessorUsedByMultipleStyleSets(mozilla::SheetType aSheetType);
// Tells the RestyleManager for the document using this style set
// to drop any nsCSSSelector pointers it has.
void ClearSelectors();
- private:
+private:
nsStyleSet(const nsStyleSet& aCopy) = delete;
nsStyleSet& operator=(const nsStyleSet& aCopy) = delete;
// Run mark-and-sweep GC on mRuleTree and mOldRuleTrees, based on mRoots.
void GCRuleTrees();
+ nsresult DirtyRuleProcessors(mozilla::SheetType aType);
+
// Update the rule processor list after a change to the style sheet list.
- nsresult GatherRuleProcessors(sheetType aType);
+ nsresult GatherRuleProcessors(mozilla::SheetType aType);
void AddImportantRules(nsRuleNode* aCurrLevelNode,
nsRuleNode* aLastPrevLevelNode,
@@ -485,11 +469,13 @@ class nsStyleSet final
// The arrays for ePresHintSheet, eStyleAttrSheet, eTransitionSheet,
// eAnimationSheet and eSVGAttrAnimationSheet are always empty.
// (FIXME: We should reduce the storage needed for them.)
- nsCOMArray mSheets[eSheetTypeCount];
+ mozilla::EnumeratedArray> mSheets;
// mRuleProcessors[eScopedDocSheet] is always null; rule processors
// for scoped style sheets are stored in mScopedDocSheetRuleProcessors.
- nsCOMPtr mRuleProcessors[eSheetTypeCount];
+ mozilla::EnumeratedArray> mRuleProcessors;
// Rule processors for HTML5 scoped style sheets, one per scope.
nsTArray > mScopedDocSheetRuleProcessors;
@@ -507,7 +493,7 @@ class nsStyleSet final
unsigned mInReconstruct : 1;
unsigned mInitFontFeatureValuesLookup : 1;
unsigned mNeedsRestyleAfterEnsureUniqueInner : 1;
- unsigned mDirty : 10; // one dirty bit is used per sheet type
+ unsigned mDirty : int(mozilla::SheetType::Count); // one bit per sheet type
uint32_t mUnusedRuleNodeCount; // used to batch rule node GC
nsTArray mRoots; // style contexts with no parent
diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp
index 9c12a6f3ce..bcb7772804 100644
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -16,6 +16,7 @@
#include "nsPresContext.h"
#include "nsIWidget.h"
#include "nsCRTGlue.h"
+#include "nsCSSParser.h"
#include "nsCSSProps.h"
#include "nsCOMPtr.h"
@@ -1501,7 +1502,7 @@ IsAutonessEqual(const nsStyleSides& aSides1, const nsStyleSides& aSides2)
nsChangeHint
nsStylePosition::CalcDifference(const nsStylePosition& aOther,
- nsStyleContext* aContext) const
+ const nsStyleVisibility* aOldStyleVisibility) const
{
nsChangeHint hint = nsChangeHint(0);
@@ -1599,23 +1600,43 @@ nsStylePosition::CalcDifference(const nsStylePosition& aOther,
bool heightChanged = mHeight != aOther.mHeight ||
mMinHeight != aOther.mMinHeight ||
mMaxHeight != aOther.mMaxHeight;
- bool isVertical = WritingMode(aContext).IsVertical();
- if (isVertical ? widthChanged : heightChanged) {
- // Block-size changes can affect descendant intrinsic sizes due to replaced
- // elements with percentage bsizes in descendants which also have
- // percentage bsizes. This is handled via nsChangeHint_UpdateComputedBSize
- // which clears intrinsic sizes for frames that have such replaced elements.
- NS_UpdateHint(hint, nsChangeHint_NeedReflow |
- nsChangeHint_UpdateComputedBSize |
- nsChangeHint_ReflowChangesSizeOrPosition);
- }
- if (isVertical ? heightChanged : widthChanged) {
- // None of our inline-size differences can affect descendant intrinsic
- // sizes and none of them need to force children to reflow.
- NS_UpdateHint(hint, NS_SubtractHint(nsChangeHint_AllReflowHints,
- NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
- nsChangeHint_NeedDirtyReflow)));
+ // If aOldStyleVisibility is null, we don't need to bother with any of
+ // these tests, since we know that the element never had its
+ // nsStyleVisibility accessed, which means it couldn't have done
+ // layout.
+ // Note that we pass an nsStyleVisibility here because we don't want
+ // to cause a new struct to be computed during
+ // nsStyleContext::CalcStyleDifference, which can lead to incorrect
+ // style data.
+ // It doesn't matter whether we're looking at the old or new
+ // visibility struct, since a change between vertical and horizontal
+ // writing-mode will cause a reframe, and it's easier to pass the old.
+ if (aOldStyleVisibility) {
+ bool isVertical = WritingMode(aOldStyleVisibility).IsVertical();
+ if (isVertical ? widthChanged : heightChanged) {
+ // Block-size changes can affect descendant intrinsic sizes due to
+ // replaced elements with percentage bsizes in descendants which
+ // also have percentage bsizes. This is handled via
+ // nsChangeHint_UpdateComputedBSize which clears intrinsic sizes
+ // for frames that have such replaced elements.
+ NS_UpdateHint(hint, nsChangeHint_NeedReflow |
+ nsChangeHint_UpdateComputedBSize |
+ nsChangeHint_ReflowChangesSizeOrPosition);
+ }
+
+ if (isVertical ? heightChanged : widthChanged) {
+ // None of our inline-size differences can affect descendant
+ // intrinsic sizes and none of them need to force children to
+ // reflow.
+ NS_UpdateHint(hint, NS_SubtractHint(nsChangeHint_AllReflowHints,
+ NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
+ nsChangeHint_NeedDirtyReflow)));
+ }
+ } else {
+ if (widthChanged || heightChanged) {
+ NS_UpdateHint(hint, nsChangeHint_NeutralChange);
+ }
}
// If any of the offsets have changed, then return the respective hints
@@ -2641,6 +2662,7 @@ nsStyleDisplay::nsStyleDisplay()
mMixBlendMode = NS_STYLE_BLEND_NORMAL;
mIsolation = NS_STYLE_ISOLATION_AUTO;
mTouchAction = NS_STYLE_TOUCH_ACTION_AUTO;
+ mTopLayer = NS_STYLE_TOP_LAYER_NONE;
mScrollBehavior = NS_STYLE_SCROLL_BEHAVIOR_AUTO;
mScrollSnapTypeX = NS_STYLE_SCROLL_SNAP_TYPE_NONE;
mScrollSnapTypeY = NS_STYLE_SCROLL_SNAP_TYPE_NONE;
@@ -2695,6 +2717,7 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
, mOrient(aSource.mOrient)
, mMixBlendMode(aSource.mMixBlendMode)
, mIsolation(aSource.mIsolation)
+ , mTopLayer(aSource.mTopLayer)
, mWillChangeBitField(aSource.mWillChangeBitField)
, mWillChange(aSource.mWillChange)
, mTouchAction(aSource.mTouchAction)
@@ -2752,6 +2775,7 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
|| mScrollSnapPointsX != aOther.mScrollSnapPointsX
|| mScrollSnapPointsY != aOther.mScrollSnapPointsY
|| mScrollSnapDestination != aOther.mScrollSnapDestination
+ || mTopLayer != aOther.mTopLayer
|| mResize != aOther.mResize)
NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
@@ -3442,7 +3466,7 @@ nsStyleText::nsStyleText(void)
mRubyPosition = NS_STYLE_RUBY_POSITION_OVER;
mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO;
mTextCombineUpright = NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE;
- mControlCharacterVisibility = NS_STYLE_CONTROL_CHARACTER_VISIBILITY_VISIBLE;
+ mControlCharacterVisibility = nsCSSParser::ControlCharVisibilityDefault();
mLetterSpacing.SetNormalValue();
mLineHeight.SetNormalValue();
diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h
index 7183ba6bc9..20be200e84 100644
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -14,6 +14,7 @@
#include "mozilla/ArenaObjectID.h"
#include "mozilla/Attributes.h"
#include "mozilla/CSSVariableValues.h"
+#include "mozilla/SheetType.h"
#include "nsColor.h"
#include "nsCoord.h"
#include "nsMargin.h"
@@ -35,6 +36,7 @@ class nsIURI;
class nsStyleContext;
class nsTextFrame;
class imgIContainer;
+struct nsStyleVisibility;
// Includes nsStyleStructID.
#include "nsStyleStructFwd.h"
@@ -89,6 +91,10 @@ class imgIContainer;
// Additional bits for nsRuleNode's mNoneBits:
#define NS_RULE_NODE_HAS_ANIMATION_DATA 0x80000000
+static_assert(int(mozilla::SheetType::Count) - 1 <=
+ (NS_RULE_NODE_LEVEL_MASK >> NS_RULE_NODE_LEVEL_SHIFT),
+ "NS_RULE_NODE_LEVEL_MASK cannot fit SheetType");
+
// The lifetime of these objects is managed by the presshell's arena.
struct nsStyleFont {
@@ -2015,6 +2021,7 @@ struct nsStyleDisplay {
uint8_t mOrient; // [reset] see nsStyleConsts.h
uint8_t mMixBlendMode; // [reset] see nsStyleConsts.h
uint8_t mIsolation; // [reset] see nsStyleConsts.h
+ uint8_t mTopLayer; // [reset] see nsStyleConsts.h
uint8_t mWillChangeBitField; // [reset] see nsStyleConsts.h. Stores a
// bitfield representation of the properties
// that are frequently queried. This should
@@ -2262,7 +2269,7 @@ struct nsStylePosition {
}
nsChangeHint CalcDifference(const nsStylePosition& aOther,
- nsStyleContext* aContext) const;
+ const nsStyleVisibility* aOldStyleVisibility) const;
static nsChangeHint MaxDifference() {
return NS_CombineHint(NS_STYLE_HINT_REFLOW,
nsChangeHint(nsChangeHint_RecomputePosition |
diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp
index d28fd772ab..9a50e2b408 100644
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -145,12 +145,14 @@ CSSTransition::QueueEvents()
if (!presContext) {
return;
}
- nsTransitionManager* manager = presContext->TransitionManager();
- manager->QueueEvent(
- TransitionEventInfo(owningElement, TransitionProperty(),
- mEffect->Timing().mIterationDuration,
- owningPseudoType));
+ nsTransitionManager* manager = presContext->TransitionManager();
+ manager->QueueEvent(TransitionEventInfo(owningElement, owningPseudoType,
+ TransitionProperty(),
+ mEffect->Timing()
+ .mIterationDuration,
+ AnimationTimeToTimeStamp(EffectEnd()),
+ this));
}
bool
diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h
index aa8e806bb5..592369e7dc 100644
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -59,7 +59,7 @@ struct ElementPropertyTransition : public dom::KeyframeEffectReadOnly
// mProperties[0].mSegments[0].mFromValue, except when this transition
// started as the reversal of another in-progress transition.
// Needed so we can handle two reverses in a row.
- mozilla::StyleAnimationValue mStartForReversingTest;
+ StyleAnimationValue mStartForReversingTest;
// Likewise, the portion (in value space) of the "full" reversed
// transition that we're actually covering. For example, if a :hover
// effect has a transition that moves the element 10px to the right
@@ -195,14 +195,21 @@ protected:
} // namespace dom
struct TransitionEventInfo {
- nsCOMPtr mElement;
+ RefPtr mElement;
+ RefPtr mAnimation;
InternalTransitionEvent mEvent;
+ TimeStamp mTimeStamp;
- TransitionEventInfo(nsIContent *aElement, nsCSSProperty aProperty,
+ TransitionEventInfo(dom::Element* aElement,
+ nsCSSPseudoElements::Type aPseudoType,
+ nsCSSProperty aProperty,
TimeDuration aDuration,
- nsCSSPseudoElements::Type aPseudoType)
+ const TimeStamp& aTimeStamp,
+ dom::Animation* aAnimation)
: mElement(aElement)
+ , mAnimation(aAnimation)
, mEvent(true, eTransitionEnd)
+ , mTimeStamp(aTimeStamp)
{
// XXX Looks like nobody initialize WidgetEvent::time
mEvent.propertyName =
@@ -213,9 +220,11 @@ struct TransitionEventInfo {
// InternalTransitionEvent doesn't support copy-construction, so we need
// to ourselves in order to work with nsTArray
- TransitionEventInfo(const TransitionEventInfo &aOther)
+ TransitionEventInfo(const TransitionEventInfo& aOther)
: mElement(aOther.mElement)
+ , mAnimation(aOther.mAnimation)
, mEvent(true, eTransitionEnd)
+ , mTimeStamp(aOther.mTimeStamp)
{
mEvent.AssignTransitionEventData(aOther.mEvent, false);
}
@@ -295,6 +304,7 @@ public:
}
void DispatchEvents() { mEventDispatcher.DispatchEvents(mPresContext); }
+ void SortEvents() { mEventDispatcher.SortEvents(); }
void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
protected:
diff --git a/layout/style/test/ListCSSProperties.cpp b/layout/style/test/ListCSSProperties.cpp
index 12e6e0c8c1..64d587c182 100644
--- a/layout/style/test/ListCSSProperties.cpp
+++ b/layout/style/test/ListCSSProperties.cpp
@@ -113,7 +113,10 @@ const char *gInaccessibleProperties[] = {
"-moz-script-size-multiplier",
"-moz-script-min-size",
"-moz-math-variant",
- "-moz-math-display" // parsed by UA sheets only
+ "-moz-math-display", // parsed by UA sheets only
+ "-moz-top-layer", // parsed by UA sheets only
+ "-moz-window-dragging", // chrome-only internal properties
+ "-moz-window-shadow" // chrome-only internal properties
};
inline int
diff --git a/layout/style/test/mochitest.ini b/layout/style/test/mochitest.ini
index 6aed36a953..8ea3e306cd 100644
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -37,6 +37,10 @@ generated-files = css_properties.js
[test_all_shorthand.html]
[test_animations.html]
skip-if = toolkit == 'android'
+[test_animations_async_tests.html]
+support-files = ../../reftests/fonts/Ahem.ttf file_animations_async_tests.html
+[test_animations_dynamic_changes.html]
+[test_animations_event_order.html]
[test_animations_omta.html]
[test_animations_omta_start.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1041017
@@ -46,6 +50,9 @@ support-files = file_animations_pausing.html
support-files = file_animations_playbackrate.html
[test_any_dynamic.html]
[test_at_rule_parse_serialize.html]
+[test_attribute_selector_eof_behavior.html]
+[test_background_blend_mode.html]
+[test_box_size_keywords.html]
[test_bug73586.html]
[test_bug74880.html]
[test_bug98997.html]
@@ -90,6 +97,7 @@ support-files = bug453896_iframe.html
[test_bug517224.html]
support-files = bug517224.sjs
[test_bug524175.html]
+[test_bug525952.html]
[test_bug534804.html]
[test_bug573255.html]
[test_bug580685.html]
@@ -102,8 +110,12 @@ support-files = bug517224.sjs
[test_bug645998.html]
support-files = file_bug645998-1.css file_bug645998-2.css
[test_bug716226.html]
+[test_bug732153.html]
+[test_bug732209.html]
+support-files = bug732209-css.sjs
[test_bug765590.html]
[test_bug771043.html]
+[test_bug795520.html]
[test_bug798567.html]
[test_bug798843_pref.html]
[test_bug829816.html]
@@ -126,15 +138,18 @@ skip-if = toolkit == 'android'
[test_computed_style_prefs.html]
[test_condition_text.html]
[test_condition_text_assignment.html]
-[test_default_computed_style.html]
+[test_counter_descriptor_storage.html]
+[test_counter_style.html]
[test_css_cross_domain.html]
skip-if = toolkit == 'android' #bug 536603
[test_css_eof_handling.html]
[test_css_escape_api.html]
[test_css_function_mismatched_parenthesis.html]
+[test_css_loader_crossorigin_data_url.html]
[test_css_supports.html]
[test_css_supports_variables.html]
[test_default_bidi_css.html]
+[test_default_computed_style.html]
[test_descriptor_storage.html]
[test_descriptor_syntax_errors.html]
[test_dont_use_document_colors.html]
@@ -157,8 +172,8 @@ support-files = flexbox_layout_testcases.js
[test_font_loading_api.html]
support-files = BitPattern.woff
[test_garbage_at_end_of_declarations.html]
-[test_grid_item_shorthands.html]
[test_grid_container_shorthands.html]
+[test_grid_item_shorthands.html]
[test_grid_shorthand_serialization.html]
[test_group_insertRule.html]
[test_hover_quirk.html]
@@ -171,6 +186,9 @@ skip-if = toolkit == 'android'
skip-if = toolkit == 'android'
[test_initial_storage.html]
[test_keyframes_rules.html]
+[test_load_events_on_stylesheets.html]
+[test_logical_properties.html]
+skip-if = (toolkit == 'gonk' && debug) # Bug 1186224
[test_media_queries.html]
skip-if = (toolkit == 'gonk' && debug) || android_version == '10' || android_version == '18' #debug-only failure; timed out #Android 2.3 and 4.3 aws only; bug 1030419
[test_media_queries_dynamic.html]
@@ -179,6 +197,7 @@ skip-if = (toolkit == 'gonk' && debug) || android_version == '10' || android_ver
[test_moz_device_pixel_ratio.html]
[test_namespace_rule.html]
[test_of_type_selectors.xhtml]
+[test_page_parser.html]
[test_parse_eof.html]
[test_parse_ident.html]
[test_parse_rule.html]
@@ -186,9 +205,11 @@ skip-if = (toolkit == 'gonk' && debug) || android_version == '10' || android_ver
[test_parser_diagnostics_unprintables.html]
[test_pixel_lengths.html]
[test_pointer-events.html]
+[test_position_float_display.html]
[test_position_sticky.html]
support-files = file_position_sticky.html
[test_priority_preservation.html]
+[test_property_database.html]
[test_property_syntax_errors.html]
[test_pseudoelement_state.html]
skip-if = (toolkit == 'gonk' && debug) || e10s #debug-only failure
@@ -204,6 +225,7 @@ skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(monosp
[test_selectors.html]
skip-if = (toolkit == 'gonk' && debug) || toolkit == 'android' #bug 775227 #debug-only failure; timed out
[test_selectors_on_anonymous_content.html]
+[test_setPropertyWithNull.html]
[test_shorthand_property_getters.html]
[test_specified_value_serialization.html]
[test_style_attribute_quirks.html]
@@ -221,11 +243,12 @@ skip-if = android_version == '10' #Android 2.3 aws only; bug 1030432
[test_transitions_computed_value_combinations.html]
[test_transitions_events.html]
[test_transitions.html]
+skip-if = (android_version == '18' && debug) # bug 1159532
+[test_transitions_bug537151.html]
+[test_transitions_dynamic_changes.html]
[test_transitions_per_property.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 775227 # b2g(times out, needs more time + various failures) b2g-debug(times out, needs more time + various failures) b2g-desktop(times out, needs more time + various failures)
[test_transitions_step_functions.html]
-[test_transitions_dynamic_changes.html]
-[test_transitions_bug537151.html]
[test_unclosed_parentheses.html]
[test_units_angle.html]
[test_units_frequency.html]
@@ -257,22 +280,3 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(bug 870262,
skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(bug 870262, :visited support) b2g-debug(bug 870262, :visited support) b2g-desktop(bug 870262, :visited support)
[test_visited_reftests.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(bug 870262, :visited support) b2g-debug(bug 870262, :visited support) b2g-desktop(bug 870262, :visited support)
-[test_bug525952.html]
-[test_load_events_on_stylesheets.html]
-[test_logical_properties.html]
-[test_page_parser.html]
-[test_bug732153.html]
-[test_bug732209.html]
-support-files = bug732209-css.sjs
-[test_bug795520.html]
-[test_background_blend_mode.html]
-[test_property_database.html]
-[test_counter_style.html]
-[test_counter_descriptor_storage.html]
-[test_position_float_display.html]
-[test_animations_async_tests.html]
-support-files = ../../reftests/fonts/Ahem.ttf file_animations_async_tests.html
-[test_setPropertyWithNull.html]
-[test_attribute_selector_eof_behavior.html]
-[test_css_loader_crossorigin_data_url.html]
-[test_attribute_selector_eof_behavior.html]
diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js
index 38b1023de7..290588704a 100644
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -71,6 +71,7 @@ var validGradientAndElementValues = [
"linear-gradient(red -99px, yellow, green, blue 120%)",
"linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
"linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+ "linear-gradient(red, green calc(50% + 20px), blue)",
"linear-gradient(to top, red, blue)",
"linear-gradient(to bottom, red, blue)",
@@ -231,6 +232,9 @@ var validGradientAndElementValues = [
"-moz-radial-gradient(.414rad bottom, red, blue)",
"-moz-radial-gradient(cover, red, blue)",
+ "-moz-radial-gradient(cover circle, red, blue)",
+ "-moz-radial-gradient(contain, red, blue)",
+ "-moz-radial-gradient(contain ellipse, red, blue)",
"-moz-radial-gradient(circle, red, blue)",
"-moz-radial-gradient(ellipse closest-corner, red, blue)",
"-moz-radial-gradient(farthest-side circle, red, blue)",
@@ -354,6 +358,10 @@ var invalidGradientAndElementValues = [
"-moz-linear-gradient(10 10px -45deg, red, blue) repeat",
"-moz-linear-gradient(10px 10 -45deg, red, blue) repeat",
"linear-gradient(red -99, yellow, green, blue 120%)",
+ /* Invalid color, calc() or -moz-image-rect() function */
+ "linear-gradient(red, rgb(0, rubbish, 0) 50%, red)",
+ "linear-gradient(red, red calc(50% + rubbish), red)",
+ "linear-gradient(to top calc(50% + rubbish), red, blue)",
/* Old syntax */
"-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, from(blue), to(red))",
"-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
@@ -588,6 +596,108 @@ var unbalancedGradientAndElementValues = [
"-moz-element(#a()",
];
+if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) {
+ // Extend gradient lists with valid/invalid webkit-prefixed expressions:
+ validGradientAndElementValues.push(
+ // Basic linear-gradient syntax (valid when prefixed or unprefixed):
+ "-webkit-linear-gradient(red, green, blue)",
+
+ // Angled linear-gradients (valid when prefixed or unprefixed):
+ "-webkit-linear-gradient(135deg, red, blue)",
+ "-webkit-linear-gradient(280deg, red 60%, blue)",
+
+ // Basic radial-gradient syntax (valid when prefixed or unprefixed):
+ "-webkit-radial-gradient(circle, white, black)",
+ "-webkit-radial-gradient(circle, white, black)",
+ "-webkit-radial-gradient(ellipse closest-side, white, black)",
+ "-webkit-radial-gradient(circle farthest-corner, white, black)",
+
+ // Contain/cover keywords (valid only for -moz/-webkit prefixed):
+ "-webkit-radial-gradient(cover, red, blue)",
+ "-webkit-radial-gradient(cover circle, red, blue)",
+ "-webkit-radial-gradient(contain, red, blue)",
+ "-webkit-radial-gradient(contain ellipse, red, blue)",
+
+ // Initial side/corner/point (valid only for -moz/-webkit prefixed):
+ "-webkit-linear-gradient(left, red, blue)",
+ "-webkit-linear-gradient(right top, red, blue)",
+ "-webkit-linear-gradient(top right, red, blue)",
+ "-webkit-radial-gradient(right, red, blue)",
+ "-webkit-radial-gradient(left bottom, red, blue)",
+ "-webkit-radial-gradient(bottom left, red, blue)",
+ "-webkit-radial-gradient(center, red, blue)",
+ "-webkit-radial-gradient(center right, red, blue)",
+ "-webkit-radial-gradient(center center, red, blue)",
+ "-webkit-radial-gradient(center top, red, blue)",
+ "-webkit-radial-gradient(left 50%, red, blue)",
+ "-webkit-radial-gradient(20px top, red, blue)",
+ "-webkit-radial-gradient(20em 30%, red, blue)",
+
+ // Point + keyword-sized shape (valid only for -moz/-webkit prefixed):
+ "-webkit-radial-gradient(center, circle closest-corner, red, blue)",
+ "-webkit-radial-gradient(10px 20px, cover circle, red, blue)",
+ "-webkit-radial-gradient(5em 50%, ellipse contain, red, blue)",
+
+ // Repeating examples:
+ "-webkit-repeating-linear-gradient(red 10%, blue 30%)",
+ "-webkit-repeating-linear-gradient(30deg, pink 20px, orange 70px)",
+ "-webkit-repeating-linear-gradient(left, red, blue)",
+ "-webkit-repeating-linear-gradient(left, red 10%, blue 30%)",
+ "-webkit-repeating-radial-gradient(circle, red, blue 10%, red 20%)",
+ "-webkit-repeating-radial-gradient(circle farthest-corner, gray 10px, yellow 20px)",
+ "-webkit-repeating-radial-gradient(top left, circle, red, blue 4%, red 8%)"
+ );
+
+ invalidGradientAndElementValues.push(
+ // Syntax that's invalid for all types of gradients:
+ // * empty gradient expressions:
+ "-webkit-linear-gradient()",
+ "-webkit-radial-gradient()",
+ "-webkit-repeating-linear-gradient()",
+ "-webkit-repeating-radial-gradient()",
+
+ // Linear syntax that's invalid for both -webkit & unprefixed, but valid
+ // for -moz:
+ // * initial