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: * a node in the lexicographic tree of rules that match an element, michael@0: * responsible for converting the rules' information into computed style michael@0: */ michael@0: michael@0: #ifndef nsRuleNode_h___ michael@0: #define nsRuleNode_h___ michael@0: michael@0: #include "nsPresContext.h" michael@0: #include "nsStyleStruct.h" michael@0: michael@0: #include michael@0: michael@0: class nsStyleContext; michael@0: struct nsRuleData; michael@0: class nsIStyleRule; michael@0: struct nsCSSValueList; michael@0: michael@0: class nsCSSValue; michael@0: struct nsCSSRect; michael@0: michael@0: class nsStyleCoord; michael@0: struct nsCSSValuePairList; michael@0: michael@0: template michael@0: class FixedStyleStructArray michael@0: { michael@0: private: michael@0: void* mArray[Count]; michael@0: public: michael@0: void*& operator[](nsStyleStructID aIndex) { michael@0: NS_ABORT_IF_FALSE(MinIndex <= aIndex && aIndex < (MinIndex + Count), michael@0: "out of range"); michael@0: return mArray[aIndex - MinIndex]; michael@0: } michael@0: michael@0: const void* operator[](nsStyleStructID aIndex) const { michael@0: NS_ABORT_IF_FALSE(MinIndex <= aIndex && aIndex < (MinIndex + Count), michael@0: "out of range"); michael@0: return mArray[aIndex - MinIndex]; michael@0: } michael@0: }; michael@0: michael@0: struct nsInheritedStyleData michael@0: { michael@0: FixedStyleStructArray mStyleStructs; michael@0: michael@0: void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW { michael@0: return aContext->AllocateFromShell(sz); michael@0: } michael@0: michael@0: void DestroyStructs(uint64_t aBits, nsPresContext* aContext) { michael@0: #define STYLE_STRUCT_INHERITED(name, checkdata_cb) \ michael@0: void *name##Data = mStyleStructs[eStyleStruct_##name]; \ michael@0: if (name##Data && !(aBits & NS_STYLE_INHERIT_BIT(name))) \ michael@0: static_cast(name##Data)->Destroy(aContext); michael@0: #define STYLE_STRUCT_RESET(name, checkdata_cb) michael@0: michael@0: #include "nsStyleStructList.h" michael@0: michael@0: #undef STYLE_STRUCT_INHERITED michael@0: #undef STYLE_STRUCT_RESET michael@0: } michael@0: michael@0: void Destroy(uint64_t aBits, nsPresContext* aContext) { michael@0: DestroyStructs(aBits, aContext); michael@0: aContext->FreeToShell(sizeof(nsInheritedStyleData), this); michael@0: } michael@0: michael@0: nsInheritedStyleData() { michael@0: for (nsStyleStructID i = nsStyleStructID_Inherited_Start; michael@0: i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count; michael@0: i = nsStyleStructID(i + 1)) { michael@0: mStyleStructs[i] = nullptr; michael@0: } michael@0: } michael@0: }; michael@0: michael@0: struct nsResetStyleData michael@0: { michael@0: FixedStyleStructArray mStyleStructs; michael@0: michael@0: nsResetStyleData() michael@0: { michael@0: for (nsStyleStructID i = nsStyleStructID_Reset_Start; michael@0: i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count; michael@0: i = nsStyleStructID(i + 1)) { michael@0: mStyleStructs[i] = nullptr; michael@0: } michael@0: } michael@0: michael@0: void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW { michael@0: return aContext->AllocateFromShell(sz); michael@0: } michael@0: michael@0: void Destroy(uint64_t aBits, nsPresContext* aContext) { michael@0: #define STYLE_STRUCT_RESET(name, checkdata_cb) \ michael@0: void *name##Data = mStyleStructs[eStyleStruct_##name]; \ michael@0: if (name##Data && !(aBits & NS_STYLE_INHERIT_BIT(name))) \ michael@0: static_cast(name##Data)->Destroy(aContext); michael@0: #define STYLE_STRUCT_INHERITED(name, checkdata_cb) michael@0: michael@0: #include "nsStyleStructList.h" michael@0: michael@0: #undef STYLE_STRUCT_RESET michael@0: #undef STYLE_STRUCT_INHERITED michael@0: michael@0: aContext->FreeToShell(sizeof(nsResetStyleData), this); michael@0: } michael@0: }; michael@0: michael@0: struct nsCachedStyleData michael@0: { michael@0: nsInheritedStyleData* mInheritedData; michael@0: nsResetStyleData* mResetData; michael@0: michael@0: static bool IsReset(const nsStyleStructID aSID) { michael@0: NS_ABORT_IF_FALSE(0 <= aSID && aSID < nsStyleStructID_Length, michael@0: "must be an inherited or reset SID"); michael@0: return nsStyleStructID_Reset_Start <= aSID; michael@0: } michael@0: michael@0: static bool IsInherited(const nsStyleStructID aSID) { michael@0: return !IsReset(aSID); michael@0: } michael@0: michael@0: static uint32_t GetBitForSID(const nsStyleStructID aSID) { michael@0: return 1 << aSID; michael@0: } michael@0: michael@0: void* NS_FASTCALL GetStyleData(const nsStyleStructID aSID) { michael@0: if (IsReset(aSID)) { michael@0: if (mResetData) { michael@0: return mResetData->mStyleStructs[aSID]; michael@0: } michael@0: } else { michael@0: if (mInheritedData) { michael@0: return mInheritedData->mStyleStructs[aSID]; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: void NS_FASTCALL SetStyleData(const nsStyleStructID aSID, michael@0: nsPresContext *aPresContext, void *aData) { michael@0: if (IsReset(aSID)) { michael@0: if (!mResetData) { michael@0: mResetData = new (aPresContext) nsResetStyleData; michael@0: } michael@0: mResetData->mStyleStructs[aSID] = aData; michael@0: } else { michael@0: if (!mInheritedData) { michael@0: mInheritedData = new (aPresContext) nsInheritedStyleData; michael@0: } michael@0: mInheritedData->mStyleStructs[aSID] = aData; michael@0: } michael@0: } michael@0: michael@0: // Typesafe and faster versions of the above michael@0: #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \ michael@0: nsStyle##name_ * NS_FASTCALL GetStyle##name_ () { \ michael@0: return mInheritedData ? static_cast( \ michael@0: mInheritedData->mStyleStructs[eStyleStruct_##name_]) : nullptr; \ michael@0: } michael@0: #define STYLE_STRUCT_RESET(name_, checkdata_cb_) \ michael@0: nsStyle##name_ * NS_FASTCALL GetStyle##name_ () { \ michael@0: return mResetData ? static_cast( \ michael@0: mResetData->mStyleStructs[eStyleStruct_##name_]) : nullptr; \ michael@0: } michael@0: #include "nsStyleStructList.h" michael@0: #undef STYLE_STRUCT_RESET michael@0: #undef STYLE_STRUCT_INHERITED michael@0: michael@0: void Destroy(uint64_t aBits, nsPresContext* aContext) { michael@0: if (mResetData) michael@0: mResetData->Destroy(aBits, aContext); michael@0: if (mInheritedData) michael@0: mInheritedData->Destroy(aBits, aContext); michael@0: mResetData = nullptr; michael@0: mInheritedData = nullptr; michael@0: } michael@0: michael@0: nsCachedStyleData() :mInheritedData(nullptr), mResetData(nullptr) {} michael@0: ~nsCachedStyleData() {} michael@0: }; michael@0: michael@0: /** michael@0: * nsRuleNode is a node in a lexicographic tree (the "rule tree") michael@0: * indexed by style rules (implementations of nsIStyleRule). michael@0: * michael@0: * The rule tree is owned by the nsStyleSet and is destroyed when the michael@0: * presentation of the document goes away. It is garbage-collected michael@0: * (using mark-and-sweep garbage collection) during the lifetime of the michael@0: * document (when dynamic changes cause the destruction of enough style michael@0: * contexts). Rule nodes are marked if they are pointed to by a style michael@0: * context or one of their descendants is. michael@0: * michael@0: * An nsStyleContext, which represents the computed style data for an michael@0: * element, points to an nsRuleNode. The path from the root of the rule michael@0: * tree to the nsStyleContext's mRuleNode gives the list of the rules michael@0: * matched, from least important in the cascading order to most michael@0: * important in the cascading order. michael@0: * michael@0: * The reason for using a lexicographic tree is that it allows for michael@0: * sharing of style data, which saves both memory (for storing the michael@0: * computed style data) and time (for computing them). This sharing michael@0: * depends on the computed style data being stored in structs (nsStyle*) michael@0: * that contain only properties that are inherited by default michael@0: * ("inherited structs") or structs that contain only properties that michael@0: * are not inherited by default ("reset structs"). The optimization michael@0: * depends on the normal case being that style rules specify relatively michael@0: * few properties and even that elements generally have relatively few michael@0: * properties specified. This allows sharing in the following ways: michael@0: * 1. [mainly reset structs] When a style data struct will contain the michael@0: * same computed value for any elements that match the same set of michael@0: * rules (common for reset structs), it can be stored on the michael@0: * nsRuleNode instead of on the nsStyleContext. michael@0: * 2. [only? reset structs] When (1) occurs, and an nsRuleNode doesn't michael@0: * have any rules that change the values in the struct, the michael@0: * nsRuleNode can share that struct with its parent nsRuleNode. michael@0: * 3. [mainly inherited structs] When an element doesn't match any michael@0: * rules that change the value of a property (or, in the edge case, michael@0: * when all the values specified are 'inherit'), the nsStyleContext michael@0: * can use the same nsStyle* struct as its parent nsStyleContext. michael@0: * michael@0: * Since the data represented by an nsIStyleRule are immutable, the data michael@0: * represented by an nsRuleNode are also immutable. michael@0: */ michael@0: michael@0: enum nsFontSizeType { michael@0: eFontSize_HTML = 1, michael@0: eFontSize_CSS = 2 michael@0: }; michael@0: michael@0: class nsRuleNode { michael@0: public: michael@0: enum RuleDetail { michael@0: eRuleNone, // No props have been specified at all. michael@0: eRulePartialReset, // At least one prop with a non-"inherit" value michael@0: // has been specified. No props have been michael@0: // specified with an "inherit" value. At least michael@0: // one prop remains unspecified. michael@0: eRulePartialMixed, // At least one prop with a non-"inherit" value michael@0: // has been specified. Some props may also have michael@0: // been specified with an "inherit" value. At michael@0: // least one prop remains unspecified. michael@0: eRulePartialInherited, // Only props with "inherit" values have michael@0: // have been specified. At least one prop michael@0: // remains unspecified. michael@0: eRuleFullReset, // All props have been specified. None has an michael@0: // "inherit" value. michael@0: eRuleFullMixed, // All props have been specified. At least one has michael@0: // a non-"inherit" value. michael@0: eRuleFullInherited // All props have been specified with "inherit" michael@0: // values. michael@0: }; michael@0: michael@0: private: michael@0: nsPresContext* const mPresContext; // Our pres context. michael@0: michael@0: nsRuleNode* const mParent; // A pointer to the parent node in the tree. michael@0: // This enables us to walk backwards from the michael@0: // most specific rule matched to the least michael@0: // specific rule (which is the optimal order to michael@0: // use for lookups of style properties. michael@0: nsIStyleRule* const mRule; // [STRONG] A pointer to our specific rule. michael@0: michael@0: nsRuleNode* mNextSibling; // This value should be used only by the michael@0: // parent, since the parent may store michael@0: // children in a hash, which means this michael@0: // pointer is not meaningful. Order of michael@0: // siblings is also not meaningful. michael@0: michael@0: struct Key { michael@0: nsIStyleRule* mRule; michael@0: uint8_t mLevel; michael@0: bool mIsImportantRule; michael@0: michael@0: Key(nsIStyleRule* aRule, uint8_t aLevel, bool aIsImportantRule) michael@0: : mRule(aRule), mLevel(aLevel), mIsImportantRule(aIsImportantRule) michael@0: {} michael@0: michael@0: bool operator==(const Key& aOther) const michael@0: { michael@0: return mRule == aOther.mRule && michael@0: mLevel == aOther.mLevel && michael@0: mIsImportantRule == aOther.mIsImportantRule; michael@0: } michael@0: michael@0: bool operator!=(const Key& aOther) const michael@0: { michael@0: return !(*this == aOther); michael@0: } michael@0: }; michael@0: michael@0: static PLDHashNumber michael@0: ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey); michael@0: michael@0: static bool michael@0: ChildrenHashMatchEntry(PLDHashTable *aTable, michael@0: const PLDHashEntryHdr *aHdr, michael@0: const void *aKey); michael@0: michael@0: static const PLDHashTableOps ChildrenHashOps; michael@0: michael@0: static PLDHashOperator michael@0: EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr, michael@0: uint32_t number, void *arg); michael@0: michael@0: Key GetKey() const { michael@0: return Key(mRule, GetLevel(), IsImportantRule()); michael@0: } michael@0: michael@0: // The children of this node are stored in either a hashtable or list michael@0: // that maps from rules to our nsRuleNode children. When matching michael@0: // rules, we use this mapping to transition from node to node michael@0: // (constructing new nodes as needed to flesh out the tree). michael@0: michael@0: union { michael@0: void* asVoid; michael@0: nsRuleNode* asList; michael@0: PLDHashTable* asHash; michael@0: } mChildren; // Accessed only through the methods below. michael@0: michael@0: enum { michael@0: kTypeMask = 0x1, michael@0: kListType = 0x0, michael@0: kHashType = 0x1 michael@0: }; michael@0: enum { michael@0: // Maximum to have in a list before converting to a hashtable. michael@0: // XXX Need to optimize this. michael@0: kMaxChildrenInList = 32 michael@0: }; michael@0: michael@0: bool HaveChildren() const { michael@0: return mChildren.asVoid != nullptr; michael@0: } michael@0: bool ChildrenAreHashed() { michael@0: return (intptr_t(mChildren.asVoid) & kTypeMask) == kHashType; michael@0: } michael@0: nsRuleNode* ChildrenList() { michael@0: return mChildren.asList; michael@0: } michael@0: nsRuleNode** ChildrenListPtr() { michael@0: return &mChildren.asList; michael@0: } michael@0: PLDHashTable* ChildrenHash() { michael@0: return (PLDHashTable*) (intptr_t(mChildren.asHash) & ~intptr_t(kTypeMask)); michael@0: } michael@0: void SetChildrenList(nsRuleNode *aList) { michael@0: NS_ASSERTION(!(intptr_t(aList) & kTypeMask), michael@0: "pointer not 2-byte aligned"); michael@0: mChildren.asList = aList; michael@0: } michael@0: void SetChildrenHash(PLDHashTable *aHashtable) { michael@0: NS_ASSERTION(!(intptr_t(aHashtable) & kTypeMask), michael@0: "pointer not 2-byte aligned"); michael@0: mChildren.asHash = (PLDHashTable*)(intptr_t(aHashtable) | kHashType); michael@0: } michael@0: void ConvertChildrenToHash(); michael@0: michael@0: nsCachedStyleData mStyleData; // Any data we cached on the rule node. michael@0: michael@0: uint32_t mDependentBits; // Used to cache the fact that we can look up michael@0: // cached data under a parent rule. michael@0: michael@0: uint32_t mNoneBits; // Used to cache the fact that the branch to this michael@0: // node specifies no non-inherited data for a michael@0: // given struct type. (This usually implies that michael@0: // the entire branch specifies no non-inherited michael@0: // data, although not necessarily, if a michael@0: // non-inherited value is overridden by an michael@0: // explicit 'inherit' value.) For example, if an michael@0: // entire rule branch specifies no color michael@0: // information, then a bit will be set along every michael@0: // rule node on that branch, so that you can break michael@0: // out of the rule tree early and just inherit michael@0: // from the parent style context. The presence of michael@0: // this bit means we should just get inherited michael@0: // data from the parent style context, and it is michael@0: // never used for reset structs since their michael@0: // Compute*Data functions don't initialize from michael@0: // inherited data. michael@0: michael@0: // Reference count. This just counts the style contexts that reference this michael@0: // rulenode. And children the rulenode has had. When this goes to 0 or michael@0: // stops being 0, we notify the style set. michael@0: // Note, in particular, that when a child is removed mRefCnt is NOT michael@0: // decremented. This is on purpose; the notifications to the style set are michael@0: // only used to determine when it's worth running GC on the ruletree, and michael@0: // this setup makes it so we only count unused ruletree leaves for purposes michael@0: // of deciding when to GC. We could more accurately count unused rulenodes michael@0: // by releasing/addrefing our parent when our refcount transitions to or from michael@0: // 0, but it doesn't seem worth it to do that. michael@0: uint32_t mRefCnt; michael@0: michael@0: public: michael@0: // Overloaded new operator. Initializes the memory to 0 and relies on an arena michael@0: // (which comes from the presShell) to perform the allocation. michael@0: void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW; michael@0: void Destroy() { DestroyInternal(nullptr); } michael@0: michael@0: // Implemented in nsStyleSet.h, since it needs to know about nsStyleSet. michael@0: inline void AddRef(); michael@0: michael@0: // Implemented in nsStyleSet.h, since it needs to know about nsStyleSet. michael@0: inline void Release(); michael@0: michael@0: protected: michael@0: void DestroyInternal(nsRuleNode ***aDestroyQueueTail); michael@0: void PropagateDependentBit(nsStyleStructID aSID, nsRuleNode* aHighestNode, michael@0: void* aStruct); michael@0: void PropagateNoneBit(uint32_t aBit, nsRuleNode* aHighestNode); michael@0: michael@0: const void* SetDefaultOnRoot(const nsStyleStructID aSID, michael@0: nsStyleContext* aContext); michael@0: michael@0: /** michael@0: * Resolves any property values in aRuleData for a given style struct that michael@0: * have eCSSUnit_TokenStream values, by resolving them against the computed michael@0: * variable values on the style context and re-parsing the property. michael@0: * michael@0: * @return Whether any properties with eCSSUnit_TokenStream values were michael@0: * encountered. michael@0: */ michael@0: static bool ResolveVariableReferences(const nsStyleStructID aSID, michael@0: nsRuleData* aRuleData, michael@0: nsStyleContext* aContext); michael@0: michael@0: const void* michael@0: WalkRuleTree(const nsStyleStructID aSID, nsStyleContext* aContext); michael@0: michael@0: const void* michael@0: ComputeDisplayData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeVisibilityData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeFontData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeColorData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeBackgroundData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeMarginData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeBorderData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputePaddingData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeOutlineData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeListData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputePositionData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeTableData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeTableBorderData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeContentData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeQuotesData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeTextData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeTextResetData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeUserInterfaceData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, michael@0: nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeUIResetData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeXULData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeColumnData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeSVGData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeSVGResetData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: const void* michael@0: ComputeVariablesData(void* aStartStruct, michael@0: const nsRuleData* aRuleData, michael@0: nsStyleContext* aContext, nsRuleNode* aHighestNode, michael@0: RuleDetail aRuleDetail, michael@0: const bool aCanStoreInRuleTree); michael@0: michael@0: // helpers for |ComputeFontData| that need access to |mNoneBits|: michael@0: static void SetFontSize(nsPresContext* aPresContext, michael@0: const nsRuleData* aRuleData, michael@0: const nsStyleFont* aFont, michael@0: const nsStyleFont* aParentFont, michael@0: nscoord* aSize, michael@0: const nsFont& aSystemFont, michael@0: nscoord aParentSize, michael@0: nscoord aScriptLevelAdjustedParentSize, michael@0: bool aUsedStartStruct, michael@0: bool aAtRoot, michael@0: bool& aCanStoreInRuleTree); michael@0: michael@0: static void SetFont(nsPresContext* aPresContext, michael@0: nsStyleContext* aContext, michael@0: uint8_t aGenericFontID, michael@0: const nsRuleData* aRuleData, michael@0: const nsStyleFont* aParentFont, michael@0: nsStyleFont* aFont, michael@0: bool aStartStruct, michael@0: bool& aCanStoreInRuleTree); michael@0: michael@0: static void SetGenericFont(nsPresContext* aPresContext, michael@0: nsStyleContext* aContext, michael@0: uint8_t aGenericFontID, michael@0: nsStyleFont* aFont); michael@0: michael@0: void AdjustLogicalBoxProp(nsStyleContext* aContext, michael@0: const nsCSSValue& aLTRSource, michael@0: const nsCSSValue& aRTLSource, michael@0: const nsCSSValue& aLTRLogicalValue, michael@0: const nsCSSValue& aRTLLogicalValue, michael@0: mozilla::css::Side aSide, michael@0: nsCSSRect& aValueRect, michael@0: bool& aCanStoreInRuleTree); michael@0: michael@0: inline RuleDetail CheckSpecifiedProperties(const nsStyleStructID aSID, michael@0: const nsRuleData* aRuleData); michael@0: michael@0: already_AddRefed michael@0: GetShadowData(const nsCSSValueList* aList, michael@0: nsStyleContext* aContext, michael@0: bool aIsBoxShadow, michael@0: bool& aCanStoreInRuleTree); michael@0: bool SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter, michael@0: const nsCSSValue& aValue, michael@0: nsStyleContext* aStyleContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree); michael@0: michael@0: private: michael@0: nsRuleNode(nsPresContext* aPresContext, nsRuleNode* aParent, michael@0: nsIStyleRule* aRule, uint8_t aLevel, bool aIsImportant); michael@0: ~nsRuleNode(); michael@0: michael@0: public: michael@0: static nsRuleNode* CreateRootNode(nsPresContext* aPresContext); michael@0: michael@0: static void EnsureBlockDisplay(uint8_t& display, michael@0: bool aConvertListItem = false); michael@0: michael@0: // Transition never returns null; on out of memory it'll just return |this|. michael@0: nsRuleNode* Transition(nsIStyleRule* aRule, uint8_t aLevel, michael@0: bool aIsImportantRule); michael@0: nsRuleNode* GetParent() const { return mParent; } michael@0: bool IsRoot() const { return mParent == nullptr; } michael@0: michael@0: // These uint8_ts are really nsStyleSet::sheetType values. michael@0: uint8_t GetLevel() const { michael@0: NS_ASSERTION(!IsRoot(), "can't call on root"); michael@0: return (mDependentBits & NS_RULE_NODE_LEVEL_MASK) >> michael@0: NS_RULE_NODE_LEVEL_SHIFT; michael@0: } michael@0: bool IsImportantRule() const { michael@0: NS_ASSERTION(!IsRoot(), "can't call on root"); michael@0: return (mDependentBits & NS_RULE_NODE_IS_IMPORTANT) != 0; michael@0: } michael@0: michael@0: /** michael@0: * Has this rule node at some time in its lifetime been the mRuleNode michael@0: * of some style context (as opposed to only being the ancestor of michael@0: * some style context's mRuleNode)? michael@0: */ michael@0: void SetUsedDirectly(); michael@0: bool IsUsedDirectly() const { michael@0: return (mDependentBits & NS_RULE_NODE_USED_DIRECTLY) != 0; michael@0: } michael@0: michael@0: // NOTE: Does not |AddRef|. Null only for the root. michael@0: nsIStyleRule* GetRule() const { return mRule; } michael@0: // NOTE: Does not |AddRef|. Never null. michael@0: nsPresContext* PresContext() const { return mPresContext; } michael@0: michael@0: const void* GetStyleData(nsStyleStructID aSID, michael@0: nsStyleContext* aContext, michael@0: bool aComputeData); michael@0: michael@0: #define STYLE_STRUCT(name_, checkdata_cb_) \ michael@0: const nsStyle##name_* GetStyle##name_(nsStyleContext* aContext, \ michael@0: bool aComputeData); michael@0: #include "nsStyleStructList.h" michael@0: #undef STYLE_STRUCT michael@0: michael@0: /* michael@0: * Garbage collection. Mark walks up the tree, marking any unmarked michael@0: * ancestors until it reaches a marked one. Sweep recursively sweeps michael@0: * the children, destroys any that are unmarked, and clears marks, michael@0: * returning true if the node on which it was called was destroyed. michael@0: */ michael@0: void Mark(); michael@0: bool Sweep(); michael@0: michael@0: static bool michael@0: HasAuthorSpecifiedRules(nsStyleContext* aStyleContext, michael@0: uint32_t ruleTypeMask, michael@0: bool aAuthorColorsAllowed); michael@0: michael@0: // Expose this so media queries can use it michael@0: static nscoord CalcLengthWithInitialFont(nsPresContext* aPresContext, michael@0: const nsCSSValue& aValue); michael@0: // Expose this so nsTransformFunctions can use it. michael@0: static nscoord CalcLength(const nsCSSValue& aValue, michael@0: nsStyleContext* aStyleContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree); michael@0: michael@0: struct ComputedCalc { michael@0: nscoord mLength; michael@0: float mPercent; michael@0: michael@0: ComputedCalc(nscoord aLength, float aPercent) michael@0: : mLength(aLength), mPercent(aPercent) {} michael@0: }; michael@0: static ComputedCalc michael@0: SpecifiedCalcToComputedCalc(const nsCSSValue& aValue, michael@0: nsStyleContext* aStyleContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree); michael@0: michael@0: // Compute the value of an nsStyleCoord that IsCalcUnit(). michael@0: // (Values that don't require aPercentageBasis should be handled michael@0: // inside nsRuleNode rather than through this API.) michael@0: static nscoord ComputeComputedCalc(const nsStyleCoord& aCoord, michael@0: nscoord aPercentageBasis); michael@0: michael@0: // Compute the value of an nsStyleCoord that is either a coord, a michael@0: // percent, or a calc expression. michael@0: static nscoord ComputeCoordPercentCalc(const nsStyleCoord& aCoord, michael@0: nscoord aPercentageBasis); michael@0: michael@0: // Return whether the rule tree for which this node is the root has michael@0: // cached data such that we need to do dynamic change handling for michael@0: // changes that change the results of media queries or require michael@0: // rebuilding all style data. michael@0: bool TreeHasCachedData() const { michael@0: NS_ASSERTION(IsRoot(), "should only be called on root of rule tree"); michael@0: return HaveChildren() || mStyleData.mInheritedData || mStyleData.mResetData; michael@0: } michael@0: michael@0: bool NodeHasCachedData(const nsStyleStructID aSID) { michael@0: return !!mStyleData.GetStyleData(aSID); michael@0: } michael@0: michael@0: static void ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList, michael@0: nsTArray& aFeatureSettings); michael@0: michael@0: static nscoord CalcFontPointSize(int32_t aHTMLSize, int32_t aBasePointSize, michael@0: nsPresContext* aPresContext, michael@0: nsFontSizeType aFontSizeType = eFontSize_HTML); michael@0: michael@0: static nscoord FindNextSmallerFontSize(nscoord aFontSize, int32_t aBasePointSize, michael@0: nsPresContext* aPresContext, michael@0: nsFontSizeType aFontSizeType = eFontSize_HTML); michael@0: michael@0: static nscoord FindNextLargerFontSize(nscoord aFontSize, int32_t aBasePointSize, michael@0: nsPresContext* aPresContext, michael@0: nsFontSizeType aFontSizeType = eFontSize_HTML); michael@0: michael@0: /** michael@0: * @param aValue The color value, returned from nsCSSParser::ParseColorString michael@0: * @param aPresContext Presentation context whose preferences are used michael@0: * for certain enumerated colors michael@0: * @param aStyleContext Style context whose color is used for 'currentColor' michael@0: * michael@0: * @note aPresContext and aStyleContext may be null, but in that case, fully michael@0: * opaque black will be returned for the values that rely on these michael@0: * objects to compute the color. (For example, -moz-hyperlinktext.) michael@0: * michael@0: * @return false if we fail to extract a color; this will not happen if both michael@0: * aPresContext and aStyleContext are non-null michael@0: */ michael@0: static bool ComputeColor(const nsCSSValue& aValue, michael@0: nsPresContext* aPresContext, michael@0: nsStyleContext* aStyleContext, michael@0: nscolor& aResult); michael@0: }; michael@0: michael@0: #endif