michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * representation of media lists used when linking to style sheets or by michael@0: * @media rules michael@0: */ michael@0: michael@0: #ifndef nsIMediaList_h_ michael@0: #define nsIMediaList_h_ michael@0: michael@0: #include "nsIDOMMediaList.h" michael@0: #include "nsTArray.h" michael@0: #include "nsIAtom.h" michael@0: #include "nsCSSValue.h" michael@0: #include "nsWrapperCache.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/ErrorResult.h" michael@0: michael@0: class nsPresContext; michael@0: class nsCSSStyleSheet; michael@0: class nsAString; michael@0: struct nsMediaFeature; michael@0: michael@0: struct nsMediaExpression { michael@0: enum Range { eMin, eMax, eEqual }; michael@0: michael@0: const nsMediaFeature *mFeature; michael@0: Range mRange; michael@0: nsCSSValue mValue; michael@0: michael@0: // aActualValue must be obtained from mFeature->mGetter michael@0: bool Matches(nsPresContext* aPresContext, michael@0: const nsCSSValue& aActualValue) const; michael@0: }; michael@0: michael@0: /** michael@0: * An nsMediaQueryResultCacheKey records what feature/value combinations michael@0: * a set of media query results are valid for. This allows the caller michael@0: * to quickly learn whether a prior result of media query evaluation is michael@0: * still valid (e.g., due to a window size change) without rerunning all michael@0: * of the evaluation and rebuilding the list of rules. michael@0: * michael@0: * This object may not be used after any media rules in any of the michael@0: * sheets it was given to have been modified. However, this is michael@0: * generally not a problem since ClearRuleCascades is called on the michael@0: * sheet whenever this happens, and these objects are stored inside the michael@0: * rule cascades. (FIXME: We're not actually doing this all the time.) michael@0: * michael@0: * The implementation could be further optimized in the future to store michael@0: * ranges (combinations of less-than, less-than-or-equal, greater-than, michael@0: * greater-than-or-equal, equal, not-equal, present, not-present) for michael@0: * each feature rather than simply storing the list of expressions. michael@0: * However, this requires combining any such ranges. michael@0: */ michael@0: class nsMediaQueryResultCacheKey { michael@0: public: michael@0: nsMediaQueryResultCacheKey(nsIAtom* aMedium) michael@0: : mMedium(aMedium) michael@0: {} michael@0: michael@0: /** michael@0: * Record that aExpression was tested while building the cached set michael@0: * that this cache key is for, and that aExpressionMatches was whether michael@0: * it matched. michael@0: */ michael@0: void AddExpression(const nsMediaExpression* aExpression, michael@0: bool aExpressionMatches); michael@0: bool Matches(nsPresContext* aPresContext) const; michael@0: private: michael@0: struct ExpressionEntry { michael@0: // FIXME: if we were better at maintaining invariants about clearing michael@0: // rule cascades when media lists change, this could be a |const michael@0: // nsMediaExpression*| instead. michael@0: nsMediaExpression mExpression; michael@0: bool mExpressionMatches; michael@0: }; michael@0: struct FeatureEntry { michael@0: const nsMediaFeature *mFeature; michael@0: InfallibleTArray mExpressions; michael@0: }; michael@0: nsCOMPtr mMedium; michael@0: nsTArray mFeatureCache; michael@0: }; michael@0: michael@0: class nsMediaQuery { michael@0: public: michael@0: nsMediaQuery() michael@0: : mNegated(false) michael@0: , mHasOnly(false) michael@0: , mTypeOmitted(false) michael@0: , mHadUnknownExpression(false) michael@0: { michael@0: } michael@0: michael@0: private: michael@0: // for Clone only michael@0: nsMediaQuery(const nsMediaQuery& aOther) michael@0: : mNegated(aOther.mNegated) michael@0: , mHasOnly(aOther.mHasOnly) michael@0: , mTypeOmitted(aOther.mTypeOmitted) michael@0: , mHadUnknownExpression(aOther.mHadUnknownExpression) michael@0: , mMediaType(aOther.mMediaType) michael@0: , mExpressions(aOther.mExpressions) michael@0: { michael@0: MOZ_ASSERT(mExpressions.Length() == aOther.mExpressions.Length()); michael@0: } michael@0: michael@0: public: michael@0: michael@0: void SetNegated() { mNegated = true; } michael@0: void SetHasOnly() { mHasOnly = true; } michael@0: void SetTypeOmitted() { mTypeOmitted = true; } michael@0: void SetHadUnknownExpression() { mHadUnknownExpression = true; } michael@0: void SetType(nsIAtom* aMediaType) { michael@0: NS_ASSERTION(aMediaType, michael@0: "expected non-null"); michael@0: mMediaType = aMediaType; michael@0: } michael@0: michael@0: // Return a new nsMediaExpression in the array for the caller to fill michael@0: // in. The caller must either fill it in completely, or call michael@0: // SetHadUnknownExpression on this nsMediaQuery. michael@0: // Returns null on out-of-memory. michael@0: nsMediaExpression* NewExpression() { return mExpressions.AppendElement(); } michael@0: michael@0: void AppendToString(nsAString& aString) const; michael@0: michael@0: nsMediaQuery* Clone() const; michael@0: michael@0: // Does this query apply to the presentation? michael@0: // If |aKey| is non-null, add cache information to it. michael@0: bool Matches(nsPresContext* aPresContext, michael@0: nsMediaQueryResultCacheKey* aKey) const; michael@0: michael@0: private: michael@0: bool mNegated; michael@0: bool mHasOnly; // only needed for serialization michael@0: bool mTypeOmitted; // only needed for serialization michael@0: bool mHadUnknownExpression; michael@0: nsCOMPtr mMediaType; michael@0: nsTArray mExpressions; michael@0: }; michael@0: michael@0: class nsMediaList MOZ_FINAL : public nsIDOMMediaList michael@0: , public nsWrapperCache michael@0: { michael@0: public: michael@0: typedef mozilla::ErrorResult ErrorResult; michael@0: michael@0: nsMediaList(); michael@0: michael@0: virtual JSObject* michael@0: WrapObject(JSContext* aCx) MOZ_OVERRIDE; michael@0: nsISupports* GetParentObject() const michael@0: { michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsMediaList) michael@0: michael@0: NS_DECL_NSIDOMMEDIALIST michael@0: michael@0: void GetText(nsAString& aMediaText); michael@0: void SetText(const nsAString& aMediaText); michael@0: michael@0: // Does this query apply to the presentation? michael@0: // If |aKey| is non-null, add cache information to it. michael@0: bool Matches(nsPresContext* aPresContext, michael@0: nsMediaQueryResultCacheKey* aKey); michael@0: michael@0: nsresult SetStyleSheet(nsCSSStyleSheet* aSheet); michael@0: void AppendQuery(nsAutoPtr& aQuery) { michael@0: // Takes ownership of aQuery michael@0: mArray.AppendElement(aQuery.forget()); michael@0: } michael@0: michael@0: already_AddRefed Clone(); michael@0: michael@0: nsMediaQuery* MediumAt(int32_t aIndex) { return mArray[aIndex]; } michael@0: void Clear() { mArray.Clear(); } michael@0: michael@0: // WebIDL michael@0: // XPCOM GetMediaText and SetMediaText are fine. michael@0: uint32_t Length() { return mArray.Length(); } michael@0: void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aReturn); michael@0: // XPCOM Item is fine. michael@0: void DeleteMedium(const nsAString& aMedium, ErrorResult& aRv) michael@0: { michael@0: aRv = DeleteMedium(aMedium); michael@0: } michael@0: void AppendMedium(const nsAString& aMedium, ErrorResult& aRv) michael@0: { michael@0: aRv = AppendMedium(aMedium); michael@0: } michael@0: michael@0: protected: michael@0: ~nsMediaList(); michael@0: michael@0: nsresult Delete(const nsAString & aOldMedium); michael@0: nsresult Append(const nsAString & aOldMedium); michael@0: michael@0: InfallibleTArray > mArray; michael@0: // not refcounted; sheet will let us know when it goes away michael@0: // mStyleSheet is the sheet that needs to be dirtied when this medialist michael@0: // changes michael@0: nsCSSStyleSheet* mStyleSheet; michael@0: }; michael@0: #endif /* !defined(nsIMediaList_h_) */