nsIMediaList.h 9.9 KB

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