Don't start image loads for the if-visited style contexts. (Bug 557287) r=bzbarsky
authorL. David Baron <dbaron@dbaron.org>
Tue, 06 Apr 2010 12:42:41 -0700
changeset 40498 363849c0170b1493960b7ed527cef775401ec43b
parent 40497 8eba981e2c9f1291cc5cb5c933b548d1a5d9a7a4
child 40499 aa2b262d938a21f0787962899ed826c1c5229d3d
push idunknown
push userunknown
push dateunknown
reviewersbzbarsky
bugs557287
milestone1.9.3a4pre
Don't start image loads for the if-visited style contexts. (Bug 557287) r=bzbarsky
layout/style/nsCSSDataBlock.cpp
layout/style/nsRuleNode.cpp
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -40,16 +40,17 @@
  * declaration, and the code for expanding and compacting it
  */
 
 #include "nsCSSDataBlock.h"
 #include "nsCSSProps.h"
 #include "nsRuleData.h"
 #include "nsRuleNode.h"
 #include "nsStyleSet.h"
+#include "nsStyleContext.h"
 
 /*
  * nsCSSCompressedDataBlock holds property-value pairs corresponding to
  * CSS declaration blocks.  The value is stored in one of the five CSS
  * data types: nsCSSValue, nsCSSRect, nsCSSValueList, nsCSSValuePair,
  * and nsCSSValuePairList, which each correspond to a value of the
  * nsCSSType enumeration.
  *
@@ -198,16 +199,30 @@ TryToStartImageLoad(const nsCSSValue& aV
     if (aValue.GetUnit() == eCSSUnit_Array) {
       TryToStartImageLoadOnValue(aValue.GetArrayValue()->Item(0), aDocument);
     }
   } else {
     TryToStartImageLoadOnValue(aValue, aDocument);
   }
 }
 
+static inline PRBool
+ShouldStartImageLoads(nsRuleData *aRuleData, nsCSSProperty aProperty)
+{
+  // Don't initiate image loads for if-visited styles.  This is
+  // important because:
+  //  (1) it's a waste of CPU and bandwidth
+  //  (2) in some cases we'd start the image load on a style change
+  //      where we wouldn't have started the load initially, which makes
+  //      which links are visited detectable to Web pages (see bug
+  //      557287)
+  return !aRuleData->mStyleContext->IsStyleIfVisited() &&
+         nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_START_IMAGE_LOADS);
+}
+
 nsresult
 nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
 {
     // If we have no data for these structs, then return immediately.
     // This optimization should make us return most of the time, so we
     // have to worry much less (although still some) about the speed of
     // the rest of the function.
     if (!(aRuleData->mSIDs & mStyleBits))
@@ -226,18 +241,17 @@ nsCSSCompressedDataBlock::MapRuleInfoInt
             void *prop =
                 nsCSSExpandedDataBlock::RuleDataPropertyAt(aRuleData, iProp);
             switch (nsCSSProps::kTypeTable[iProp]) {
                 case eCSSType_Value: {
                     nsCSSValue* target = static_cast<nsCSSValue*>(prop);
                     if (target->GetUnit() == eCSSUnit_Null) {
                         const nsCSSValue *val = ValueAtCursor(cursor);
                         NS_ASSERTION(val->GetUnit() != eCSSUnit_Null, "oops");
-                        if (nsCSSProps::PropHasFlags(iProp,
-                                CSS_PROPERTY_START_IMAGE_LOADS)) {
+                        if (ShouldStartImageLoads(aRuleData, iProp)) {
                             TryToStartImageLoad(*val, doc, iProp);
                         }
                         *target = *val;
                         if (iProp == eCSSProperty_font_family) {
                             // XXX Are there other things like this?
                             aRuleData->mFontData->mFamilyFromHTML = PR_FALSE;
                         }
                         if (nsCSSProps::PropHasFlags(iProp,
@@ -296,18 +310,17 @@ nsCSSCompressedDataBlock::MapRuleInfoInt
                     }
                     cursor += CDBValuePairStorage_advance;
                 } break;
 
                 case eCSSType_ValueList:
                 case eCSSType_ValuePairList: {
                     void** target = static_cast<void**>(prop);
                     if (!*target) {
-                        if (nsCSSProps::PropHasFlags(iProp,
-                                CSS_PROPERTY_START_IMAGE_LOADS)) {
+                        if (ShouldStartImageLoads(aRuleData, iProp)) {
                             for (nsCSSValueList* l = ValueListAtCursor(cursor);
                                  l; l = l->mNext) {
                                 TryToStartImageLoad(l->mValue, doc, iProp);
                             }
                         }
 
                         void* val = PointerAtCursor(cursor);
                         NS_ASSERTION(val, "oops");
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -679,17 +679,22 @@ static void SetStyleImage(nsStyleContext
                     *gradient, aCanStoreInRuleTree);
         aResult.SetGradientData(gradient);
       }
       break;
     }
     case eCSSUnit_None:
       break;
     default:
-      NS_NOTREACHED("unexpected unit; maybe nsCSSValue::Image::Image() failed?");
+      // We might have eCSSUnit_URL values for if-visited style
+      // contexts, which we can safely treat like 'none'.  Otherwise
+      // this is an unexpected unit.
+      NS_ASSERTION(aStyleContext->IsStyleIfVisited() &&
+                   aValue.GetUnit() == eCSSUnit_URL,
+                   "unexpected unit; maybe nsCSSValue::Image::Image() failed?");
       break;
   }
 }
 
 // flags for SetDiscrete - align values with SETCOORD_* constants
 // where possible
 
 #define SETDSC_NORMAL                 0x01   // N