Allow multiple post-resolve callbacks. (Maybe not the long term approach for CSS transitions, but easiest right now.) (Bug 435441) r=bzbarsky
authorL. David Baron <dbaron@dbaron.org>
Fri, 11 Sep 2009 06:46:36 -0400
changeset 32403 9ef12a27ab1411702b7dea8f3055da13800e6b06
parent 32402 2c12630e5db6e9819a80e76035cafcf8aa7d7c99
child 32404 c87e6a6a41bb59c0d77db8c0e5126db1b386cee4
push idunknown
push userunknown
push dateunknown
reviewersbzbarsky
bugs435441
milestone1.9.3a1pre
Allow multiple post-resolve callbacks. (Maybe not the long term approach for CSS transitions, but easiest right now.) (Bug 435441) r=bzbarsky
layout/style/nsHTMLStyleSheet.cpp
layout/style/nsRuleData.h
layout/style/nsRuleNode.cpp
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -200,17 +200,17 @@ static void TbodyPostResolveCallback(voi
                                NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_ROWS);
 }
 
 NS_IMETHODIMP
 nsHTMLStyleSheet::TableTbodyRule::MapRuleInfoInto(nsRuleData* aRuleData)
 {
   if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) {
     aRuleData->mCanStoreInRuleTree = PR_FALSE;
-    aRuleData->mPostResolveCallback = &TbodyPostResolveCallback;
+    aRuleData->mPostResolveCallbacks.AppendElement(&TbodyPostResolveCallback);
   }
   return NS_OK;
 }
 // -----------------------------------------------------------
 
 static void RowPostResolveCallback(void* aStyleStruct, nsRuleData* aRuleData)
 {
   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_TOP, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
@@ -219,17 +219,17 @@ static void RowPostResolveCallback(void*
                                NS_STYLE_TABLE_RULES_ROWS, NS_STYLE_TABLE_RULES_ROWS);
 }
 
 NS_IMETHODIMP
 nsHTMLStyleSheet::TableRowRule::MapRuleInfoInto(nsRuleData* aRuleData)
 {
   if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) {
     aRuleData->mCanStoreInRuleTree = PR_FALSE;
-    aRuleData->mPostResolveCallback = &RowPostResolveCallback;
+    aRuleData->mPostResolveCallbacks.AppendElement(&RowPostResolveCallback);
   }
   return NS_OK;
 }
 
 static void ColgroupPostResolveCallback(void* aStyleStruct, nsRuleData* aRuleData)
 {
   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_LEFT, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
                                NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_COLS);
@@ -237,17 +237,17 @@ static void ColgroupPostResolveCallback(
                                NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_COLS);
 }
 
 NS_IMETHODIMP
 nsHTMLStyleSheet::TableColgroupRule::MapRuleInfoInto(nsRuleData* aRuleData)
 {
   if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) {
     aRuleData->mCanStoreInRuleTree = PR_FALSE;
-    aRuleData->mPostResolveCallback = &ColgroupPostResolveCallback;
+    aRuleData->mPostResolveCallbacks.AppendElement(&ColgroupPostResolveCallback);
   }
   return NS_OK;
 }
 
 static void ColPostResolveCallback(void* aStyleStruct, nsRuleData* aRuleData)
 {
   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_LEFT, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
                                NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
@@ -266,27 +266,27 @@ static void UngroupedColPostResolveCallb
                                NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
 }
 
 NS_IMETHODIMP
 nsHTMLStyleSheet::TableColRule::MapRuleInfoInto(nsRuleData* aRuleData)
 {
   if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) {
     aRuleData->mCanStoreInRuleTree = PR_FALSE;
-    aRuleData->mPostResolveCallback = &ColPostResolveCallback;
+    aRuleData->mPostResolveCallbacks.AppendElement(&ColPostResolveCallback);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLStyleSheet::TableUngroupedColRule::MapRuleInfoInto(nsRuleData* aRuleData)
 {
   if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) {
     aRuleData->mCanStoreInRuleTree = PR_FALSE;
-    aRuleData->mPostResolveCallback = &UngroupedColPostResolveCallback;
+    aRuleData->mPostResolveCallbacks.AppendElement(&UngroupedColPostResolveCallback);
   }
   return NS_OK;
 }
 // -----------------------------------------------------------
 
 struct MappedAttrTableEntry : public PLDHashEntryHdr {
   nsMappedAttributes *mAttributes;
 };
--- a/layout/style/nsRuleData.h
+++ b/layout/style/nsRuleData.h
@@ -41,31 +41,34 @@
  * hold data from matched rules during style data computation 
  */
 
 #ifndef nsRuleData_h_
 #define nsRuleData_h_
 
 #include "nsCSSStruct.h"
 #include "nsStyleStructFwd.h"
+#include "nsTArray.h"
 class nsPresContext;
 class nsStyleContext;
 
 struct nsRuleData;
 typedef void (*nsPostResolveFunc)(void* aStyleStruct, nsRuleData* aData);
 
 struct nsRuleData
 {
   PRUint32 mSIDs;
   PRPackedBool mCanStoreInRuleTree;
   PRPackedBool mIsImportantRule;
   PRUint8 mLevel; // an nsStyleSet::sheetType
   nsPresContext* mPresContext;
   nsStyleContext* mStyleContext;
-  nsPostResolveFunc mPostResolveCallback;
+  // MapRuleInfoInto should append to this array, so it is ordered from
+  // most specific to least.
+  nsTArray<nsPostResolveFunc> mPostResolveCallbacks;
   nsRuleDataFont* mFontData; // Should always be stack-allocated! We don't own these structures!
   nsRuleDataDisplay* mDisplayData;
   nsRuleDataMargin* mMarginData;
   nsRuleDataList* mListData;
   nsRuleDataPosition* mPositionData;
   nsRuleDataTable* mTableData;
   nsRuleDataColor* mColorData;
   nsRuleDataContent* mContentData;
@@ -75,17 +78,17 @@ struct nsRuleData
 
 #ifdef MOZ_SVG
   nsRuleDataSVG* mSVGData;
 #endif
 
   nsRuleDataColumn* mColumnData;
 
   nsRuleData(PRUint32 aSIDs, nsPresContext* aContext, nsStyleContext* aStyleContext) 
-    :mSIDs(aSIDs), mPresContext(aContext), mStyleContext(aStyleContext), mPostResolveCallback(nsnull),
+    :mSIDs(aSIDs), mPresContext(aContext), mStyleContext(aStyleContext),
      mFontData(nsnull), mDisplayData(nsnull), mMarginData(nsnull), mListData(nsnull), 
      mPositionData(nsnull), mTableData(nsnull), mColorData(nsnull), mContentData(nsnull), mTextData(nsnull),
      mUserInterfaceData(nsnull), mColumnData(nsnull)
   {
     mCanStoreInRuleTree = PR_TRUE;
     mXULData = nsnull;
 #ifdef MOZ_SVG
     mSVGData = nsnull;
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1939,26 +1939,27 @@ nsRuleNode::WalkRuleTree(const nsStyleSt
   PRBool isReset = nsCachedStyleData::IsReset(aSID);
   if (!highestNode)
     highestNode = rootNode;
 
   if (!aRuleData->mCanStoreInRuleTree)
     detail = eRulePartialMixed; // Treat as though some data is specified to avoid
                                 // the optimizations and force data computation.
 
-  if (detail == eRuleNone && startStruct && !aRuleData->mPostResolveCallback) {
+  if (detail == eRuleNone && startStruct &&
+      aRuleData->mPostResolveCallbacks.IsEmpty()) {
     // We specified absolutely no rule information, but a parent rule in the tree
     // specified all the rule information.  We set a bit along the branch from our
     // node in the tree to the node that specified the data that tells nodes on that
     // branch that they never need to examine their rules for this particular struct type
     // ever again.
     PropagateDependentBit(bit, ruleNode);
     return startStruct;
   }
-  // FIXME Do we need to check for mPostResolveCallback?
+  // FIXME Do we need to check for mPostResolveCallbacks?
   if ((!startStruct && !isReset &&
        (detail == eRuleNone || detail == eRulePartialInherited)) ||
       detail == eRuleFullInherited) {
     // We specified no non-inherited information and neither did any of
     // our parent rules.
 
     // We set a bit along the branch from the highest node (ruleNode)
     // down to our node (this) indicating that no non-inherited data was
@@ -2003,19 +2004,23 @@ nsRuleNode::WalkRuleTree(const nsStyleSt
 #define STYLE_STRUCT_TEST aSID
 #define STYLE_STRUCT(name, checkdata_cb, ctor_args)                           \
   res = Compute##name##Data(startStruct, *aSpecificData, aContext,            \
                       highestNode, detail, aRuleData->mCanStoreInRuleTree);
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 #undef STYLE_STRUCT_TEST
 
-  // If we have a post-resolve callback, handle that now.
-  if (aRuleData->mPostResolveCallback && (NS_LIKELY(res != nsnull)))
-    (*aRuleData->mPostResolveCallback)(const_cast<void*>(res), aRuleData);
+  // If we have post-resolve callbacks, handle that now.
+  if (NS_LIKELY(res != nsnull)) {
+    // Enumerate from least to most specific rule.
+    for (PRUint32 i = aRuleData->mPostResolveCallbacks.Length(); i-- != 0; ) {
+      (*aRuleData->mPostResolveCallbacks[i])(const_cast<void*>(res), aRuleData);
+    }
+  }
 
   // Now return the result.
   return res;
 }
 
 const void*
 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
 {
@@ -2998,19 +3003,21 @@ nsRuleNode::SetGenericFont(nsPresContext
     if (i != 0)
       fontData.mFamily.Reset();
 
     nsRuleNode::SetFont(aPresContext, context, aMinFontSize,
                         aGenericFontID, fontData, &parentFont, aFont,
                         PR_FALSE, dummy);
 
     // XXX Not sure if we need to do this here
-    // If we have a post-resolve callback, handle that now.
-    if (ruleData.mPostResolveCallback)
-      (ruleData.mPostResolveCallback)(aFont, &ruleData);
+    // If we have post-resolve callbacks, handle that now.
+    // Enumerate from least to most specific rule.
+    for (PRUint32 j = ruleData.mPostResolveCallbacks.Length(); j-- != 0; ) {
+      (*ruleData.mPostResolveCallbacks[j])(aFont, &ruleData);
+    }
 
     parentFont = *aFont;
   }
 }
 
 static PRBool ExtractGeneric(const nsString& aFamily, PRBool aGeneric,
                              void *aData)
 {