diff --git a/mozilla/content/base/src/nsStyleSet.cpp b/mozilla/content/base/src/nsStyleSet.cpp index f0424339ab9..fc50f5d143c 100644 --- a/mozilla/content/base/src/nsStyleSet.cpp +++ b/mozilla/content/base/src/nsStyleSet.cpp @@ -113,6 +113,7 @@ public: PRBool aForceUnique = PR_FALSE); NS_IMETHOD ClearRuleTree(); + virtual nsresult GetRuleTree(nsIRuleNode** aResult); NS_IMETHOD ReParentStyleContext(nsIPresContext* aPresContext, nsIStyleContext* aStyleContext, @@ -971,6 +972,14 @@ StyleSetImpl::ClearRuleTree() return NS_OK; } +nsresult +StyleSetImpl::GetRuleTree(nsIRuleNode** aResult) +{ + *aResult = mRuleTree; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + NS_IMETHODIMP StyleSetImpl::ReParentStyleContext(nsIPresContext* aPresContext, nsIStyleContext* aStyleContext, diff --git a/mozilla/content/html/style/public/nsIRuleNode.h b/mozilla/content/html/style/public/nsIRuleNode.h index 32ba56be6dd..51012c11a9d 100644 --- a/mozilla/content/html/style/public/nsIRuleNode.h +++ b/mozilla/content/html/style/public/nsIRuleNode.h @@ -396,6 +396,7 @@ public: NS_IMETHOD GetPresContext(nsIPresContext** aResult)=0; NS_IMETHOD ClearCachedData(nsIStyleRule* aRule)=0; + NS_IMETHOD ClearCachedDataInSubtree(nsIStyleRule* aRule)=0; virtual const nsStyleStruct* GetStyleData(nsStyleStructID aSID, nsIStyleContext* aContext)=0; diff --git a/mozilla/content/html/style/src/nsRuleNode.cpp b/mozilla/content/html/style/src/nsRuleNode.cpp index c3661105260..b90a42c2789 100644 --- a/mozilla/content/html/style/src/nsRuleNode.cpp +++ b/mozilla/content/html/style/src/nsRuleNode.cpp @@ -418,8 +418,10 @@ nsRuleNode::ClearCachedData(nsIStyleRule* aRule) while (curr) { if (curr->mRule == aRule) { // We have a match. Blow away all data stored at this node. - if (mStyleData.mResetData || mStyleData.mInheritedData) - mStyleData.Destroy(0, mPresContext); + if (curr->mStyleData.mResetData || curr->mStyleData.mInheritedData) + curr->mStyleData.Destroy(0, mPresContext); + curr->mNoneBits &= ~NS_STYLE_INHERIT_MASK; + curr->mInheritBits &= ~NS_STYLE_INHERIT_MASK; break; } curr = curr->mParent; @@ -428,6 +430,31 @@ nsRuleNode::ClearCachedData(nsIStyleRule* aRule) return NS_OK; } +PRBool PR_CALLBACK ClearCachedDataHelper(nsHashKey* aKey, void* aData, void* aClosure) +{ + nsIRuleNode* ruleNode = (nsIRuleNode*)aData; + nsIStyleRule* rule = (nsIStyleRule*)aClosure; + ruleNode->ClearCachedDataInSubtree(rule); + return PR_TRUE; +} + +NS_IMETHODIMP +nsRuleNode::ClearCachedDataInSubtree(nsIStyleRule* aRule) +{ + if (mRule == aRule) { + // We have a match. Blow away all data stored at this node. + if (mStyleData.mResetData || mStyleData.mInheritedData) + mStyleData.Destroy(0, mPresContext); + mNoneBits &= ~NS_STYLE_INHERIT_MASK; + mInheritBits &= ~NS_STYLE_INHERIT_MASK; + } + + if (mChildren) + mChildren->Enumerate(ClearCachedDataHelper, (void*)aRule); + + return NS_OK; +} + NS_IMETHODIMP nsRuleNode::GetPresContext(nsIPresContext** aResult) { diff --git a/mozilla/content/html/style/src/nsRuleNode.h b/mozilla/content/html/style/src/nsRuleNode.h index f92a8c0c698..71f80f8f969 100644 --- a/mozilla/content/html/style/src/nsRuleNode.h +++ b/mozilla/content/html/style/src/nsRuleNode.h @@ -232,6 +232,7 @@ public: NS_IMETHOD IsRoot(PRBool* aResult); NS_IMETHOD GetRule(nsIStyleRule** aResult); NS_IMETHOD ClearCachedData(nsIStyleRule* aRule); + NS_IMETHOD ClearCachedDataInSubtree(nsIStyleRule* aRule); NS_IMETHOD GetPresContext(nsIPresContext** aResult); const nsStyleStruct* GetStyleData(nsStyleStructID aSID, nsIStyleContext* aContext); diff --git a/mozilla/layout/base/public/nsIFrameManager.h b/mozilla/layout/base/public/nsIFrameManager.h index 002401840c3..967fd5ad7f1 100644 --- a/mozilla/layout/base/public/nsIFrameManager.h +++ b/mozilla/layout/base/public/nsIFrameManager.h @@ -105,6 +105,7 @@ public: NS_IMETHOD ClearPlaceholderFrameMap() = 0; // Mapping undisplayed content + NS_IMETHOD GetUndisplayedContent(nsIContent* aContent, nsIStyleContext** aStyleContext)=0; NS_IMETHOD SetUndisplayedContent(nsIContent* aContent, nsIStyleContext* aStyleContext) = 0; NS_IMETHOD SetUndisplayedPseudoIn(nsIStyleContext* aPseudoContext, nsIContent* aParentContent) = 0; diff --git a/mozilla/layout/base/public/nsIStyleSet.h b/mozilla/layout/base/public/nsIStyleSet.h index 93da1eac755..8fa9df14574 100644 --- a/mozilla/layout/base/public/nsIStyleSet.h +++ b/mozilla/layout/base/public/nsIStyleSet.h @@ -37,6 +37,7 @@ class nsIFrame; class nsIDocument; class nsIFrameManager; class nsISupportsArray; +class nsIRuleNode; struct nsFindFrameHint; #include "nsVoidArray.h" @@ -79,6 +80,8 @@ public: virtual nsIStyleSheet* GetBackstopStyleSheetAt(PRInt32 aIndex) = 0; virtual void ReplaceBackstopStyleSheets(nsISupportsArray* aNewSheets) = 0; + virtual nsresult GetRuleTree(nsIRuleNode** aResult) = 0; + // enable / disable the Quirk style sheet: // returns NS_FAILURE if none is found, otherwise NS_OK NS_IMETHOD EnableQuirkStyleSheet(PRBool aEnable) = 0; diff --git a/mozilla/layout/html/base/src/nsFrameManager.cpp b/mozilla/layout/html/base/src/nsFrameManager.cpp index cd9f9af5e8c..eeda2a71697 100644 --- a/mozilla/layout/html/base/src/nsFrameManager.cpp +++ b/mozilla/layout/html/base/src/nsFrameManager.cpp @@ -161,6 +161,8 @@ public: nsresult RemoveNodeFor(nsIContent* aParentContent, UndisplayedNode* aNode); nsresult RemoveNodesFor(nsIContent* aParentContent); + nsresult GetNodeFor(nsIContent* aContent, nsIStyleContext** aResult); + // Removes all entries from the hash table void Clear(void); @@ -223,6 +225,7 @@ public: NS_IMETHOD ClearPlaceholderFrameMap(); // Undisplayed content functions + NS_IMETHOD GetUndisplayedContent(nsIContent* aContent, nsIStyleContext** aStyleContext); NS_IMETHOD SetUndisplayedContent(nsIContent* aContent, nsIStyleContext* aStyleContext); NS_IMETHOD SetUndisplayedPseudoIn(nsIStyleContext* aPseudoContext, nsIContent* aParentContent); @@ -675,6 +678,20 @@ FrameManager::ClearPlaceholderFrameMap() //---------------------------------------------------------------------- +NS_IMETHODIMP +FrameManager::GetUndisplayedContent(nsIContent* aContent, nsIStyleContext** aResult) +{ + if (!aContent || !aResult) { + return NS_ERROR_NULL_POINTER; + } + *aResult = nsnull; // initialize out param + + if (mUndisplayedMap) + mUndisplayedMap->GetNodeFor(aContent, aResult); + + return NS_OK; +} + NS_IMETHODIMP FrameManager::SetUndisplayedContent(nsIContent* aContent, nsIStyleContext* aStyleContext) @@ -2583,6 +2600,20 @@ UndisplayedMap::AddNodeFor(nsIContent* aParentContent, nsIStyleContext* aPseudoS return AppendNodeFor(node, aParentContent); } +nsresult +UndisplayedMap::GetNodeFor(nsIContent* aContent, nsIStyleContext** aResult) +{ + PLHashEntry** entry = GetEntryFor(aContent); + if (*entry) { + UndisplayedNode* node = (UndisplayedNode*)((*entry)->value); + *aResult = node->mStyle; + NS_IF_ADDREF(*aResult); + } + else + *aResult = nsnull; + return NS_OK; +} + nsresult UndisplayedMap::RemoveNodeFor(nsIContent* aParentContent, UndisplayedNode* aNode) { diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp index 3755193ba57..c1d991c39d7 100644 --- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -9800,6 +9800,66 @@ nsCSSFrameConstructor::AttributeChanged(nsIPresContext* aPresContext, } #endif // INCLUDE_XUL + // check for inline style. we need to clear the data at the style context's rule + // node whenever the inline style property changes. + if (aAttribute == nsHTMLAtoms::style) { + nsCOMPtr html(do_QueryInterface(aContent)); + if (html) { + nsHTMLValue val; + html->GetHTMLAttribute(nsHTMLAtoms::style, val); + if (eHTMLUnit_ISupports == val.GetUnit()) { + // This style rule exists and we need to blow away any computed data that this + // rule cached in the rule tree. + nsCOMPtr rule = getter_AddRefs((nsIStyleRule*)val.GetISupportsValue()); + nsCOMPtr context; + if (primaryFrame) + primaryFrame->GetStyleContext(getter_AddRefs(context)); + else { + // We might be in the undisplayed map. Retrieve the style context from there. + nsCOMPtr frameManager; + shell->GetFrameManager(getter_AddRefs(frameManager)); + frameManager->GetUndisplayedContent(aContent, getter_AddRefs(context)); + if (!context) { + // Well, we don't have a context to use as a guide. + // Attempt #3 will be to resolve style if we at least have a parent frame. + nsCOMPtr parent; + aContent->GetParent(*getter_AddRefs(parent)); + if (parent) { + nsIFrame* parentFrame; + shell->GetPrimaryFrameFor(parent, &parentFrame); + if (parentFrame) { + nsCOMPtr parentContext; + parentFrame->GetStyleContext(getter_AddRefs(parentContext)); + aPresContext->ResolveStyleContextFor(aContent, parentContext, PR_FALSE, + getter_AddRefs(context)); + } + } + } + } + + if (context) { + nsCOMPtr ruleNode; + context->GetRuleNode(getter_AddRefs(ruleNode)); + ruleNode->ClearCachedData(rule); // XXXdwh. If we're willing to *really* special case + // inline style, we could only invalidate the struct data + // that actually changed. For example, if someone changes + // style.left, we really only need to blow away cached + // data in the position struct. + } + else { + // Ok, our only option left is to just crawl the entire rule + // tree and blow away the data that way. + nsCOMPtr set; + shell->GetStyleSet(getter_AddRefs(set)); + nsCOMPtr rootNode; + set->GetRuleTree(getter_AddRefs(rootNode)); + if (rootNode) + rootNode->ClearCachedDataInSubtree(rule); + } + } + } + } + // apply changes if (primaryFrame && aHint == NS_STYLE_HINT_ATTRCHANGE) result = primaryFrame->AttributeChanged(aPresContext, aContent, aNameSpaceID, aAttribute, aHint); @@ -9814,30 +9874,6 @@ nsCSSFrameConstructor::AttributeChanged(nsIPresContext* aPresContext, // is there? if (primaryFrame) { - // check for inline style. we need to clear the data at the style context's rule - // node whenever the inline style property changes. - if (aAttribute == nsHTMLAtoms::style) { - nsCOMPtr html(do_QueryInterface(aContent)); - if (html) { - nsHTMLValue val; - html->GetHTMLAttribute(nsHTMLAtoms::style, val); - if (eHTMLUnit_ISupports == val.GetUnit()) { - // This style rule exists and we need to blow away any computed data that this - // rule cached in the rule tree. - nsCOMPtr rule = getter_AddRefs((nsIStyleRule*)val.GetISupportsValue()); - nsCOMPtr context; - primaryFrame->GetStyleContext(getter_AddRefs(context)); - nsCOMPtr ruleNode; - context->GetRuleNode(getter_AddRefs(ruleNode)); - ruleNode->ClearCachedData(rule); // XXXdwh. If we're willing to *really* special case - // inline style, we could only invalidate the struct data - // that actually changed. For example, if someone changes - // style.left, we really only need to blow away cached - // data in the position struct. - } - } - } - PRInt32 maxHint = aHint; nsStyleChangeList changeList; // put primary frame on list to deal with, re-resolve may update or add next in flows