michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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 CSS style rules (selectors+declaration) and CSS michael@0: * selectors michael@0: */ michael@0: michael@0: #ifndef mozilla_css_StyleRule_h__ michael@0: #define mozilla_css_StyleRule_h__ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/css/Rule.h" michael@0: michael@0: #include "nsString.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsCSSPseudoElements.h" michael@0: #include "nsCSSPseudoClasses.h" michael@0: michael@0: class nsIAtom; michael@0: class nsCSSStyleSheet; michael@0: struct nsCSSSelectorList; michael@0: class nsCSSCompressedDataBlock; michael@0: michael@0: struct nsAtomList { michael@0: public: michael@0: nsAtomList(nsIAtom* aAtom); michael@0: nsAtomList(const nsString& aAtomValue); michael@0: ~nsAtomList(void); michael@0: michael@0: /** Do a deep clone. Should be used only on the first in the linked list. */ michael@0: nsAtomList* Clone() const { return Clone(true); } michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: nsCOMPtr mAtom; michael@0: nsAtomList* mNext; michael@0: private: michael@0: nsAtomList* Clone(bool aDeep) const; michael@0: michael@0: nsAtomList(const nsAtomList& aCopy) MOZ_DELETE; michael@0: nsAtomList& operator=(const nsAtomList& aCopy) MOZ_DELETE; michael@0: }; michael@0: michael@0: struct nsPseudoClassList { michael@0: public: michael@0: nsPseudoClassList(nsCSSPseudoClasses::Type aType); michael@0: nsPseudoClassList(nsCSSPseudoClasses::Type aType, const char16_t *aString); michael@0: nsPseudoClassList(nsCSSPseudoClasses::Type aType, const int32_t *aIntPair); michael@0: nsPseudoClassList(nsCSSPseudoClasses::Type aType, michael@0: nsCSSSelectorList *aSelectorList /* takes ownership */); michael@0: ~nsPseudoClassList(void); michael@0: michael@0: /** Do a deep clone. Should be used only on the first in the linked list. */ michael@0: nsPseudoClassList* Clone() const { return Clone(true); } michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: union { michael@0: // For a given value of mType, we have either: michael@0: // a. no value, which means mMemory is always null michael@0: // (if none of the conditions for (b), (c), or (d) is true) michael@0: // b. a string value, which means mString/mMemory is non-null michael@0: // (if nsCSSPseudoClasses::HasStringArg(mType)) michael@0: // c. an integer pair value, which means mNumbers/mMemory is non-null michael@0: // (if nsCSSPseudoClasses::HasNthPairArg(mType)) michael@0: // d. a selector list, which means mSelectors is non-null michael@0: // (if nsCSSPseudoClasses::HasSelectorListArg(mType)) michael@0: void* mMemory; // mString and mNumbers use NS_Alloc/NS_Free michael@0: char16_t* mString; michael@0: int32_t* mNumbers; michael@0: nsCSSSelectorList* mSelectors; michael@0: } u; michael@0: nsCSSPseudoClasses::Type mType; michael@0: nsPseudoClassList* mNext; michael@0: private: michael@0: nsPseudoClassList* Clone(bool aDeep) const; michael@0: michael@0: nsPseudoClassList(const nsPseudoClassList& aCopy) MOZ_DELETE; michael@0: nsPseudoClassList& operator=(const nsPseudoClassList& aCopy) MOZ_DELETE; michael@0: }; michael@0: michael@0: #define NS_ATTR_FUNC_SET 0 // [attr] michael@0: #define NS_ATTR_FUNC_EQUALS 1 // [attr=value] michael@0: #define NS_ATTR_FUNC_INCLUDES 2 // [attr~=value] (space separated) michael@0: #define NS_ATTR_FUNC_DASHMATCH 3 // [attr|=value] ('-' truncated) michael@0: #define NS_ATTR_FUNC_BEGINSMATCH 4 // [attr^=value] (begins with) michael@0: #define NS_ATTR_FUNC_ENDSMATCH 5 // [attr$=value] (ends with) michael@0: #define NS_ATTR_FUNC_CONTAINSMATCH 6 // [attr*=value] (contains substring) michael@0: michael@0: struct nsAttrSelector { michael@0: public: michael@0: nsAttrSelector(int32_t aNameSpace, const nsString& aAttr); michael@0: nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction, michael@0: const nsString& aValue, bool aCaseSensitive); michael@0: nsAttrSelector(int32_t aNameSpace, nsIAtom* aLowercaseAttr, michael@0: nsIAtom* aCasedAttr, uint8_t aFunction, michael@0: const nsString& aValue, bool aCaseSensitive); michael@0: ~nsAttrSelector(void); michael@0: michael@0: /** Do a deep clone. Should be used only on the first in the linked list. */ michael@0: nsAttrSelector* Clone() const { return Clone(true); } michael@0: michael@0: nsString mValue; michael@0: nsAttrSelector* mNext; michael@0: nsCOMPtr mLowercaseAttr; michael@0: nsCOMPtr mCasedAttr; michael@0: int32_t mNameSpace; michael@0: uint8_t mFunction; michael@0: bool mCaseSensitive; // If we are in an HTML document, michael@0: // is the value case sensitive? michael@0: private: michael@0: nsAttrSelector* Clone(bool aDeep) const; michael@0: michael@0: nsAttrSelector(const nsAttrSelector& aCopy) MOZ_DELETE; michael@0: nsAttrSelector& operator=(const nsAttrSelector& aCopy) MOZ_DELETE; michael@0: }; michael@0: michael@0: struct nsCSSSelector { michael@0: public: michael@0: nsCSSSelector(void); michael@0: ~nsCSSSelector(void); michael@0: michael@0: /** Do a deep clone. Should be used only on the first in the linked list. */ michael@0: nsCSSSelector* Clone() const { return Clone(true, true); } michael@0: michael@0: void Reset(void); michael@0: void SetNameSpace(int32_t aNameSpace); michael@0: void SetTag(const nsString& aTag); michael@0: void AddID(const nsString& aID); michael@0: void AddClass(const nsString& aClass); michael@0: void AddPseudoClass(nsCSSPseudoClasses::Type aType); michael@0: void AddPseudoClass(nsCSSPseudoClasses::Type aType, const char16_t* aString); michael@0: void AddPseudoClass(nsCSSPseudoClasses::Type aType, const int32_t* aIntPair); michael@0: // takes ownership of aSelectorList michael@0: void AddPseudoClass(nsCSSPseudoClasses::Type aType, michael@0: nsCSSSelectorList* aSelectorList); michael@0: void AddAttribute(int32_t aNameSpace, const nsString& aAttr); michael@0: void AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc, michael@0: const nsString& aValue, bool aCaseSensitive); michael@0: void SetOperator(char16_t aOperator); michael@0: michael@0: inline bool HasTagSelector() const { michael@0: return !!mCasedTag; michael@0: } michael@0: michael@0: inline bool IsPseudoElement() const { michael@0: return mLowercaseTag && !mCasedTag; michael@0: } michael@0: michael@0: // Calculate the specificity of this selector (not including its mNext!). michael@0: int32_t CalcWeight() const; michael@0: michael@0: void ToString(nsAString& aString, nsCSSStyleSheet* aSheet, michael@0: bool aAppend = false) const; michael@0: michael@0: private: michael@0: void AddPseudoClassInternal(nsPseudoClassList *aPseudoClass); michael@0: nsCSSSelector* Clone(bool aDeepNext, bool aDeepNegations) const; michael@0: michael@0: void AppendToStringWithoutCombinators(nsAString& aString, michael@0: nsCSSStyleSheet* aSheet) const; michael@0: void AppendToStringWithoutCombinatorsOrNegations(nsAString& aString, michael@0: nsCSSStyleSheet* aSheet, michael@0: bool aIsNegated) michael@0: const; michael@0: // Returns true if this selector can have a namespace specified (which michael@0: // happens if and only if the default namespace would apply to this michael@0: // selector). michael@0: bool CanBeNamespaced(bool aIsNegated) const; michael@0: // Calculate the specificity of this selector (not including its mNext michael@0: // or its mNegations). michael@0: int32_t CalcWeightWithoutNegations() const; michael@0: michael@0: public: michael@0: // Get and set the selector's pseudo type michael@0: nsCSSPseudoElements::Type PseudoType() const { michael@0: return static_cast(mPseudoType); michael@0: } michael@0: void SetPseudoType(nsCSSPseudoElements::Type aType) { michael@0: NS_ASSERTION(static_cast(aType) >= INT16_MIN && michael@0: static_cast(aType) <= INT16_MAX, michael@0: "Out of bounds - this will overflow mPseudoType"); michael@0: mPseudoType = static_cast(aType); michael@0: } michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: // For case-sensitive documents, mLowercaseTag is the same as mCasedTag, michael@0: // but in case-insensitive documents (HTML) mLowercaseTag is lowercase. michael@0: // Also, for pseudo-elements mCasedTag will be null but mLowercaseTag michael@0: // contains their name. michael@0: nsCOMPtr mLowercaseTag; michael@0: nsCOMPtr mCasedTag; michael@0: nsAtomList* mIDList; michael@0: nsAtomList* mClassList; michael@0: nsPseudoClassList* mPseudoClassList; // atom for the pseudo, string for michael@0: // the argument to functional pseudos michael@0: nsAttrSelector* mAttrList; michael@0: nsCSSSelector* mNegations; michael@0: nsCSSSelector* mNext; michael@0: int32_t mNameSpace; michael@0: char16_t mOperator; michael@0: private: michael@0: // int16_t to make sure it packs well with mOperator michael@0: int16_t mPseudoType; michael@0: michael@0: nsCSSSelector(const nsCSSSelector& aCopy) MOZ_DELETE; michael@0: nsCSSSelector& operator=(const nsCSSSelector& aCopy) MOZ_DELETE; michael@0: }; michael@0: michael@0: /** michael@0: * A selector list is the unit of selectors that each style rule has. michael@0: * For example, "P B, H1 B { ... }" would be a selector list with two michael@0: * items (where each |nsCSSSelectorList| object's |mSelectors| has michael@0: * an |mNext| for the P or H1). We represent them as linked lists. michael@0: */ michael@0: class inDOMUtils; michael@0: michael@0: struct nsCSSSelectorList { michael@0: nsCSSSelectorList(void); michael@0: ~nsCSSSelectorList(void); michael@0: michael@0: /** michael@0: * Create a new selector and push it onto the beginning of |mSelectors|, michael@0: * setting its |mNext| to the current value of |mSelectors|. If there is an michael@0: * earlier selector, set its |mOperator| to |aOperator|; else |aOperator| michael@0: * must be char16_t(0). michael@0: * Returns the new selector. michael@0: * The list owns the new selector. michael@0: * The caller is responsible for updating |mWeight|. michael@0: */ michael@0: nsCSSSelector* AddSelector(char16_t aOperator); michael@0: michael@0: /** michael@0: * Should be used only on the first in the list michael@0: */ michael@0: void ToString(nsAString& aResult, nsCSSStyleSheet* aSheet); michael@0: michael@0: /** michael@0: * Do a deep clone. Should be used only on the first in the list. michael@0: */ michael@0: nsCSSSelectorList* Clone() const { return Clone(true); } michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: nsCSSSelector* mSelectors; michael@0: int32_t mWeight; michael@0: nsCSSSelectorList* mNext; michael@0: protected: michael@0: friend class inDOMUtils; michael@0: nsCSSSelectorList* Clone(bool aDeep) const; michael@0: michael@0: private: michael@0: nsCSSSelectorList(const nsCSSSelectorList& aCopy) MOZ_DELETE; michael@0: nsCSSSelectorList& operator=(const nsCSSSelectorList& aCopy) MOZ_DELETE; michael@0: }; michael@0: michael@0: // 464bab7a-2fce-4f30-ab44-b7a5f3aae57d michael@0: #define NS_CSS_STYLE_RULE_IMPL_CID \ michael@0: { 0x464bab7a, 0x2fce, 0x4f30, \ michael@0: { 0xab, 0x44, 0xb7, 0xa5, 0xf3, 0xaa, 0xe5, 0x7d } } michael@0: michael@0: namespace mozilla { michael@0: namespace css { michael@0: michael@0: class Declaration; michael@0: class DOMCSSStyleRule; michael@0: michael@0: class StyleRule; michael@0: michael@0: class ImportantRule : public nsIStyleRule { michael@0: public: michael@0: ImportantRule(Declaration *aDeclaration); michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsIStyleRule interface michael@0: virtual void MapRuleInfoInto(nsRuleData* aRuleData) MOZ_OVERRIDE; michael@0: #ifdef DEBUG michael@0: virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: protected: michael@0: virtual ~ImportantRule(); michael@0: michael@0: // Not an owning reference; the StyleRule that owns this michael@0: // ImportantRule also owns the mDeclaration, and any rule node michael@0: // pointing to this rule keeps that StyleRule alive as well. michael@0: Declaration* mDeclaration; michael@0: michael@0: friend class StyleRule; michael@0: }; michael@0: michael@0: class StyleRule MOZ_FINAL : public Rule michael@0: { michael@0: public: michael@0: StyleRule(nsCSSSelectorList* aSelector, michael@0: Declaration *aDeclaration); michael@0: private: michael@0: // for |Clone| michael@0: StyleRule(const StyleRule& aCopy); michael@0: // for |DeclarationChanged| michael@0: StyleRule(StyleRule& aCopy, michael@0: Declaration *aDeclaration); michael@0: public: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_RULE_IMPL_CID) michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // null for style attribute michael@0: nsCSSSelectorList* Selector() { return mSelector; } michael@0: michael@0: uint32_t GetLineNumber() const { return mLineNumber; } michael@0: uint32_t GetColumnNumber() const { return mColumnNumber; } michael@0: void SetLineNumberAndColumnNumber(uint32_t aLineNumber, michael@0: uint32_t aColumnNumber) michael@0: { mLineNumber = aLineNumber; mColumnNumber = aColumnNumber; } michael@0: michael@0: Declaration* GetDeclaration() const { return mDeclaration; } michael@0: michael@0: /** michael@0: * Return a new |nsIStyleRule| instance that replaces the current michael@0: * one, with |aDecl| replacing the previous declaration. Due to the michael@0: * |nsIStyleRule| contract of immutability, this must be called if michael@0: * the declaration is modified. michael@0: * michael@0: * |DeclarationChanged| handles replacing the object in the container michael@0: * sheet or group rule if |aHandleContainer| is true. michael@0: */ michael@0: already_AddRefed michael@0: DeclarationChanged(Declaration* aDecl, bool aHandleContainer); michael@0: michael@0: nsIStyleRule* GetImportantRule() const { return mImportantRule; } michael@0: michael@0: /** michael@0: * The rule processor must call this method before calling michael@0: * nsRuleWalker::Forward on this rule during rule matching. michael@0: */ michael@0: void RuleMatched(); michael@0: michael@0: // hooks for DOM rule michael@0: void GetCssText(nsAString& aCssText); michael@0: void SetCssText(const nsAString& aCssText); michael@0: void GetSelectorText(nsAString& aSelectorText); michael@0: void SetSelectorText(const nsAString& aSelectorText); michael@0: michael@0: virtual int32_t GetType() const; michael@0: michael@0: virtual already_AddRefed Clone() const; michael@0: michael@0: virtual nsIDOMCSSRule* GetDOMRule(); michael@0: michael@0: virtual nsIDOMCSSRule* GetExistingDOMRule(); michael@0: michael@0: // The new mapping function. michael@0: virtual void MapRuleInfoInto(nsRuleData* aRuleData) MOZ_OVERRIDE; michael@0: michael@0: #ifdef DEBUG michael@0: virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: ~StyleRule(); michael@0: michael@0: private: michael@0: nsCSSSelectorList* mSelector; // null for style attribute michael@0: Declaration* mDeclaration; michael@0: ImportantRule* mImportantRule; // initialized by RuleMatched michael@0: DOMCSSStyleRule* mDOMRule; michael@0: // Keep the same type so that MSVC packs them. michael@0: uint32_t mLineNumber; michael@0: uint32_t mColumnNumber : 31; michael@0: uint32_t mWasMatched : 1; michael@0: michael@0: private: michael@0: StyleRule& operator=(const StyleRule& aCopy) MOZ_DELETE; michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(StyleRule, NS_CSS_STYLE_RULE_IMPL_CID) michael@0: michael@0: } // namespace css michael@0: } // namespace mozilla michael@0: michael@0: #endif /* mozilla_css_StyleRule_h__ */