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