Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /*
8 : * representation of media lists used when linking to style sheets or by
9 : * @media rules
10 : */
11 :
12 : #ifndef nsMediaList_h_
13 : #define nsMediaList_h_
14 :
15 : #include "nsAutoPtr.h"
16 : #include "nsTArray.h"
17 : #include "nsIAtom.h"
18 : #include "nsCSSValue.h"
19 : #include "mozilla/Attributes.h"
20 : #include "mozilla/dom/MediaList.h"
21 :
22 : class nsPresContext;
23 : class nsAString;
24 : struct nsMediaFeature;
25 :
26 : namespace mozilla {
27 : namespace css {
28 : class DocumentRule;
29 : } // namespace css
30 : } // namespace mozilla
31 :
32 551 : struct nsMediaExpression {
33 : enum Range { eMin, eMax, eEqual };
34 :
35 : const nsMediaFeature *mFeature;
36 : Range mRange;
37 : nsCSSValue mValue;
38 :
39 : // aActualValue must be obtained from mFeature->mGetter
40 : bool Matches(nsPresContext* aPresContext,
41 : const nsCSSValue& aActualValue) const;
42 :
43 0 : bool operator==(const nsMediaExpression& aOther) const {
44 0 : return mFeature == aOther.mFeature && // pointer equality fine (atom-like)
45 0 : mRange == aOther.mRange &&
46 0 : mValue == aOther.mValue;
47 : }
48 : bool operator!=(const nsMediaExpression& aOther) const {
49 : return !(*this == aOther);
50 : }
51 : };
52 :
53 : /**
54 : * An nsMediaQueryResultCacheKey records what feature/value combinations
55 : * a set of media query results are valid for. This allows the caller
56 : * to quickly learn whether a prior result of media query evaluation is
57 : * still valid (e.g., due to a window size change) without rerunning all
58 : * of the evaluation and rebuilding the list of rules.
59 : *
60 : * This object may not be used after any media rules in any of the
61 : * sheets it was given to have been modified. However, this is
62 : * generally not a problem since ClearRuleCascades is called on the
63 : * sheet whenever this happens, and these objects are stored inside the
64 : * rule cascades. (FIXME: We're not actually doing this all the time.)
65 : *
66 : * The implementation could be further optimized in the future to store
67 : * ranges (combinations of less-than, less-than-or-equal, greater-than,
68 : * greater-than-or-equal, equal, not-equal, present, not-present) for
69 : * each feature rather than simply storing the list of expressions.
70 : * However, this requires combining any such ranges.
71 : */
72 11 : class nsMediaQueryResultCacheKey {
73 : public:
74 42 : explicit nsMediaQueryResultCacheKey(nsIAtom* aMedium)
75 42 : : mMedium(aMedium)
76 42 : {}
77 :
78 : /**
79 : * Record that aExpression was tested while building the cached set
80 : * that this cache key is for, and that aExpressionMatches was whether
81 : * it matched.
82 : */
83 : void AddExpression(const nsMediaExpression* aExpression,
84 : bool aExpressionMatches);
85 : bool Matches(nsPresContext* aPresContext) const;
86 5 : bool HasFeatureConditions() const {
87 5 : return !mFeatureCache.IsEmpty();
88 : }
89 :
90 : /**
91 : * An operator== that implements list equality, which isn't quite as
92 : * good as set equality, but catches the trivial equality cases.
93 : */
94 0 : bool operator==(const nsMediaQueryResultCacheKey& aOther) const {
95 0 : return mMedium == aOther.mMedium &&
96 0 : mFeatureCache == aOther.mFeatureCache;
97 : }
98 0 : bool operator!=(const nsMediaQueryResultCacheKey& aOther) const {
99 0 : return !(*this == aOther);
100 : }
101 : private:
102 381 : struct ExpressionEntry {
103 : // FIXME: if we were better at maintaining invariants about clearing
104 : // rule cascades when media lists change, this could be a |const
105 : // nsMediaExpression*| instead.
106 : nsMediaExpression mExpression;
107 : bool mExpressionMatches;
108 :
109 0 : bool operator==(const ExpressionEntry& aOther) const {
110 0 : return mExpression == aOther.mExpression &&
111 0 : mExpressionMatches == aOther.mExpressionMatches;
112 : }
113 : bool operator!=(const ExpressionEntry& aOther) const {
114 : return !(*this == aOther);
115 : }
116 : };
117 59 : struct FeatureEntry {
118 : const nsMediaFeature *mFeature;
119 : InfallibleTArray<ExpressionEntry> mExpressions;
120 :
121 0 : bool operator==(const FeatureEntry& aOther) const {
122 0 : return mFeature == aOther.mFeature &&
123 0 : mExpressions == aOther.mExpressions;
124 : }
125 : bool operator!=(const FeatureEntry& aOther) const {
126 : return !(*this == aOther);
127 : }
128 : };
129 : nsCOMPtr<nsIAtom> mMedium;
130 : nsTArray<FeatureEntry> mFeatureCache;
131 : };
132 :
133 : /**
134 : * nsDocumentRuleResultCacheKey is analagous to nsMediaQueryResultCacheKey
135 : * and stores the result of matching the @-moz-document rules from a set
136 : * of style sheets. nsCSSRuleProcessor builds up an
137 : * nsDocumentRuleResultCacheKey as it visits the @-moz-document rules
138 : * while building its RuleCascadeData.
139 : *
140 : * Rather than represent the result using a list of both the matching and
141 : * non-matching rules, we just store the matched rules. The assumption is
142 : * that in situations where we have a large number of rules -- such as the
143 : * thousands added by AdBlock Plus -- that only a small number will be
144 : * matched. Thus to check if the nsDocumentRuleResultCacheKey matches a
145 : * given nsPresContext, we also need the entire list of @-moz-document
146 : * rules to know which rules must not match.
147 : */
148 35 : class nsDocumentRuleResultCacheKey
149 : {
150 : public:
151 : #ifdef DEBUG
152 74 : nsDocumentRuleResultCacheKey()
153 74 : : mFinalized(false) {}
154 : #endif
155 :
156 : bool AddMatchingRule(mozilla::css::DocumentRule* aRule);
157 : bool Matches(nsPresContext* aPresContext,
158 : const nsTArray<mozilla::css::DocumentRule*>& aRules) const;
159 :
160 0 : bool operator==(const nsDocumentRuleResultCacheKey& aOther) const {
161 0 : MOZ_ASSERT(mFinalized);
162 0 : MOZ_ASSERT(aOther.mFinalized);
163 0 : return mMatchingRules == aOther.mMatchingRules;
164 : }
165 0 : bool operator!=(const nsDocumentRuleResultCacheKey& aOther) const {
166 0 : return !(*this == aOther);
167 : }
168 :
169 10 : void Swap(nsDocumentRuleResultCacheKey& aOther) {
170 10 : mMatchingRules.SwapElements(aOther.mMatchingRules);
171 : #ifdef DEBUG
172 10 : std::swap(mFinalized, aOther.mFinalized);
173 : #endif
174 10 : }
175 :
176 : void Finalize();
177 :
178 : #ifdef DEBUG
179 : void List(FILE* aOut = stdout, int32_t aIndex = 0) const;
180 : #endif
181 :
182 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
183 :
184 : private:
185 : nsTArray<mozilla::css::DocumentRule*> mMatchingRules;
186 : #ifdef DEBUG
187 : bool mFinalized;
188 : #endif
189 : };
190 :
191 0 : class nsMediaQuery {
192 : public:
193 51 : nsMediaQuery()
194 51 : : mNegated(false)
195 : , mHasOnly(false)
196 : , mTypeOmitted(false)
197 51 : , mHadUnknownExpression(false)
198 : {
199 51 : }
200 :
201 : private:
202 : // for Clone only
203 0 : nsMediaQuery(const nsMediaQuery& aOther)
204 0 : : mNegated(aOther.mNegated)
205 0 : , mHasOnly(aOther.mHasOnly)
206 0 : , mTypeOmitted(aOther.mTypeOmitted)
207 0 : , mHadUnknownExpression(aOther.mHadUnknownExpression)
208 : , mMediaType(aOther.mMediaType)
209 0 : , mExpressions(aOther.mExpressions)
210 : {
211 0 : MOZ_ASSERT(mExpressions.Length() == aOther.mExpressions.Length());
212 0 : }
213 :
214 : public:
215 :
216 2 : void SetNegated() { mNegated = true; }
217 0 : void SetHasOnly() { mHasOnly = true; }
218 35 : void SetTypeOmitted() { mTypeOmitted = true; }
219 0 : void SetHadUnknownExpression() { mHadUnknownExpression = true; }
220 51 : void SetType(nsIAtom* aMediaType) {
221 51 : NS_ASSERTION(aMediaType,
222 : "expected non-null");
223 51 : mMediaType = aMediaType;
224 51 : }
225 :
226 : // Return a new nsMediaExpression in the array for the caller to fill
227 : // in. The caller must either fill it in completely, or call
228 : // SetHadUnknownExpression on this nsMediaQuery.
229 : // Returns null on out-of-memory.
230 45 : nsMediaExpression* NewExpression() { return mExpressions.AppendElement(); }
231 :
232 : void AppendToString(nsAString& aString) const;
233 :
234 : nsMediaQuery* Clone() const;
235 :
236 : // Does this query apply to the presentation?
237 : // If |aKey| is non-null, add cache information to it.
238 : bool Matches(nsPresContext* aPresContext,
239 : nsMediaQueryResultCacheKey* aKey) const;
240 :
241 : private:
242 : bool mNegated;
243 : bool mHasOnly; // only needed for serialization
244 : bool mTypeOmitted; // only needed for serialization
245 : bool mHadUnknownExpression;
246 : nsCOMPtr<nsIAtom> mMediaType;
247 : nsTArray<nsMediaExpression> mExpressions;
248 : };
249 :
250 : class nsMediaList final : public mozilla::dom::MediaList
251 : {
252 : public:
253 : nsMediaList();
254 :
255 : void GetText(nsAString& aMediaText) final;
256 : void SetText(const nsAString& aMediaText) final;
257 :
258 4 : bool Matches(nsPresContext* aPresContext) const final {
259 4 : return Matches(aPresContext, nullptr);
260 : }
261 :
262 : // Does this query apply to the presentation?
263 : // If |aKey| is non-null, add cache information to it.
264 : bool Matches(nsPresContext* aPresContext,
265 : nsMediaQueryResultCacheKey* aKey) const;
266 :
267 : #ifdef DEBUG
268 0 : bool IsServo() const final { return false; }
269 : #endif
270 :
271 51 : void AppendQuery(nsAutoPtr<nsMediaQuery>& aQuery) {
272 : // Takes ownership of aQuery
273 51 : mArray.AppendElement(aQuery.forget());
274 51 : }
275 :
276 : already_AddRefed<mozilla::dom::MediaList> Clone() final;
277 :
278 : nsMediaQuery* MediumAt(int32_t aIndex) { return mArray[aIndex]; }
279 3 : void Clear() { mArray.Clear(); }
280 :
281 : // WebIDL
282 0 : uint32_t Length() final { return mArray.Length(); }
283 : void IndexedGetter(uint32_t aIndex, bool& aFound,
284 : nsAString& aReturn) final;
285 :
286 : protected:
287 : ~nsMediaList();
288 :
289 : nsresult Delete(const nsAString & aOldMedium) final;
290 : nsresult Append(const nsAString & aOldMedium) final;
291 :
292 : InfallibleTArray<nsAutoPtr<nsMediaQuery> > mArray;
293 : };
294 : #endif /* !defined(nsMediaList_h_) */
|