Bug 461199 (Part 20) - Rewrite the private browsing visited link coloring test to make it work with the new async API
☠☠ backed out by 7ac2e2bad75e ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 17 Feb 2010 14:04:31 -0800
changeset 38184 d03d64716ccd0629077c3c4dbf1d1ec56fd3f3a9
parent 38183 113cf8eec589b772490e5cc51ca8507dbececa22
child 38185 2eaaa58d2915e76708e669e07f38057091a6dce8
child 38239 7ac2e2bad75e47b059092ba18a264e2011a8a0e2
push id11651
push usersdwilsh@shawnwilsher.com
push dateWed, 17 Feb 2010 22:38:03 +0000
treeherdermozilla-central@550a4379468f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs461199
milestone1.9.3a2pre
Bug 461199 (Part 20) - Rewrite the private browsing visited link coloring test to make it work with the new async API r=mconnor r=sdwilsh r=bz
layout/build/nsLayoutStatics.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsCSSRuleProcessor.h
toolkit/components/places/tests/mochitest/bug_461710/Makefile.in
toolkit/components/places/tests/mochitest/bug_461710/visited_page-2.html
toolkit/components/places/tests/mochitest/bug_461710/visited_page-3.html
toolkit/components/places/tests/mochitest/test_bug_461710.html
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -250,17 +250,21 @@ nsLayoutStatics::Initialize()
   }
 
   rv = nsCCUncollectableMarker::Init();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize nsCCUncollectableMarker");
     return rv;
   }
 
-  nsCSSRuleProcessor::Startup();
+  rv = nsCSSRuleProcessor::Startup();
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Could not initialize nsCSSRuleProcessor");
+    return rv;
+  }
 
 #ifdef MOZ_XUL
   rv = nsXULPopupManager::Init();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize nsXULPopupManager");
     return rv;
   }
 #endif
@@ -305,17 +309,17 @@ nsLayoutStatics::Shutdown()
 #endif
   nsDOMStorageManager::Shutdown();
   txMozillaXSLTProcessor::Shutdown();
   nsDOMAttribute::Shutdown();
   nsDOMEventRTTearoff::Shutdown();
   nsEventListenerManager::Shutdown();
   nsComputedDOMStyle::Shutdown();
   CSSLoaderImpl::Shutdown();
-  nsCSSRuleProcessor::FreeSystemMetrics();
+  nsCSSRuleProcessor::Shutdown();
   nsTextFrameTextRunCache::Shutdown();
   nsHTMLDNSPrefetch::Shutdown();
   nsCSSRendering::Shutdown();
 #ifdef DEBUG
   nsFrame::DisplayReflowShutdown();
 #endif
   nsCellMap::Shutdown();
 
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -82,16 +82,19 @@
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 #include "nsContentUtils.h"
 #include "nsIMediaList.h"
 #include "nsCSSRules.h"
 #include "nsIPrincipal.h"
 #include "nsStyleSet.h"
 #include "prlog.h"
+#include "nsIObserverService.h"
+#include "nsIPrivateBrowsingService.h"
+#include "nsNetCID.h"
 
 #define VISITED_PSEUDO_PREF "layout.css.visited_links_enabled"
 
 static PRBool gSupportVisitedPseudo = PR_TRUE;
 
 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 static nsTArray< nsCOMPtr<nsIAtom> >* sSystemMetrics = 0;
 
@@ -763,16 +766,72 @@ RuleCascadeData::AttributeListFor(nsIAto
       PL_DHashTableRawRemove(&mAttributeSelectors, entry);
       return nsnull;
     }
     entry->mAttribute = aAttribute;
   }
   return entry->mSelectors;
 }
 
+class nsPrivateBrowsingObserver : nsIObserver,
+                                  nsSupportsWeakReference
+{
+public:
+  nsPrivateBrowsingObserver();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  void Init();
+  PRBool InPrivateBrowsing() const { return mInPrivateBrowsing; }
+
+private:
+  PRBool mInPrivateBrowsing;
+};
+
+NS_IMPL_ISUPPORTS2(nsPrivateBrowsingObserver, nsIObserver, nsISupportsWeakReference)
+
+nsPrivateBrowsingObserver::nsPrivateBrowsingObserver()
+  : mInPrivateBrowsing(PR_FALSE)
+{
+}
+
+void
+nsPrivateBrowsingObserver::Init()
+{
+  nsCOMPtr<nsIPrivateBrowsingService> pbService =
+    do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
+  if (pbService) {
+    pbService->GetPrivateBrowsingEnabled(&mInPrivateBrowsing);
+
+    nsCOMPtr<nsIObserverService> observerService =
+      do_GetService("@mozilla.org/observer-service;1");
+    if (observerService) {
+      observerService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, PR_TRUE);
+    }
+  }
+}
+
+nsresult
+nsPrivateBrowsingObserver::Observe(nsISupports *aSubject,
+                                   const char *aTopic,
+                                   const PRUnichar *aData)
+{
+  if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) {
+    if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).get())) {
+      mInPrivateBrowsing = PR_TRUE;
+    } else {
+      mInPrivateBrowsing = PR_FALSE;
+    }
+  }
+  return NS_OK;
+}
+
+static nsPrivateBrowsingObserver *gPrivateBrowsingObserver = nsnull;
+
 // -------------------------------
 // CSS Style rule processor implementation
 //
 
 nsCSSRuleProcessor::nsCSSRuleProcessor(const nsCOMArray<nsICSSStyleSheet>& aSheets,
                                        PRUint8 aSheetType)
   : mSheets(aSheets)
   , mRuleCascades(nsnull)
@@ -788,24 +847,31 @@ nsCSSRuleProcessor::~nsCSSRuleProcessor(
   for (PRInt32 i = mSheets.Count() - 1; i >= 0; --i)
     mSheets[i]->DropRuleProcessor(this);
   mSheets.Clear();
   ClearRuleCascades();
 }
 
 NS_IMPL_ISUPPORTS1(nsCSSRuleProcessor, nsIStyleRuleProcessor)
 
-/* static */ void
+/* static */ nsresult
 nsCSSRuleProcessor::Startup()
 {
   nsContentUtils::AddBoolPrefVarCache(VISITED_PSEUDO_PREF,
                                       &gSupportVisitedPseudo);
   // We want to default to true, not false as AddBoolPrefVarCache does.
   gSupportVisitedPseudo =
     nsContentUtils::GetBoolPref(VISITED_PSEUDO_PREF, PR_TRUE);
+
+  gPrivateBrowsingObserver = new nsPrivateBrowsingObserver();
+  NS_ENSURE_TRUE(gPrivateBrowsingObserver, NS_ERROR_OUT_OF_MEMORY);
+  NS_ADDREF(gPrivateBrowsingObserver);
+  gPrivateBrowsingObserver->Init();
+
+  return NS_OK;
 }
 
 static PRBool
 InitSystemMetrics()
 {
   NS_ASSERTION(!sSystemMetrics, "already initialized");
 
   sSystemMetrics = new nsTArray< nsCOMPtr<nsIAtom> >;
@@ -885,16 +951,23 @@ InitSystemMetrics()
 
 /* static */ void
 nsCSSRuleProcessor::FreeSystemMetrics()
 {
   delete sSystemMetrics;
   sSystemMetrics = nsnull;
 }
 
+/* static */ void
+nsCSSRuleProcessor::Shutdown()
+{
+  FreeSystemMetrics();
+  NS_RELEASE(gPrivateBrowsingObserver);
+}
+
 /* static */ PRBool
 nsCSSRuleProcessor::HasSystemMetric(nsIAtom* aMetric)
 {
   if (!sSystemMetrics && !InitSystemMetrics()) {
     return PR_FALSE;
   }
   return sSystemMetrics->IndexOf(aMetric) != sSystemMetrics->NoIndex;
 }
@@ -1032,17 +1105,19 @@ RuleProcessorData::ContentState()
       mPresContext->EventStateManager()->GetContentState(mContent,
                                                          mContentState);
     } else {
       mContentState = mContent->IntrinsicState();
     }
 
     // If we are not supposed to mark visited links as such, be sure to flip the
     // bits appropriately.
-    if (!gSupportVisitedPseudo && (mContentState & NS_EVENT_STATE_VISITED)) {
+    if ((!gSupportVisitedPseudo ||
+        gPrivateBrowsingObserver->InPrivateBrowsing()) &&
+        (mContentState & NS_EVENT_STATE_VISITED)) {
       mContentState = (mContentState & ~PRUint32(NS_EVENT_STATE_VISITED)) |
                       NS_EVENT_STATE_UNVISITED;
     }
   }
   return mContentState;
 }
 
 PRBool
--- a/layout/style/nsCSSRuleProcessor.h
+++ b/layout/style/nsCSSRuleProcessor.h
@@ -71,17 +71,18 @@ public:
                      PRUint8 aSheetType);
   virtual ~nsCSSRuleProcessor();
 
   NS_DECL_ISUPPORTS
 
 public:
   nsresult ClearRuleCascades();
 
-  static void Startup();
+  static nsresult Startup();
+  static void Shutdown();
   static void FreeSystemMetrics();
   static PRBool HasSystemMetric(nsIAtom* aMetric);
 
   /*
    * Returns true if the given RuleProcessorData matches one of the
    * selectors in aSelectorList.  Note that this method will assume
    * the matching is not for styling purposes.  aSelectorList must not
    * include any pseudo-element selectors.  aSelectorList is allowed
--- a/toolkit/components/places/tests/mochitest/bug_461710/Makefile.in
+++ b/toolkit/components/places/tests/mochitest/bug_461710/Makefile.in
@@ -42,17 +42,15 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir = toolkit/components/places/tests/bug_461710
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _HTTP_FILES	= \
 		visited_page.html \
-		visited_page-2.html \
-		visited_page-3.html \
 		link_page.html \
 		link_page-2.html \
 		link_page-3.html \
 		$(NULL)
 
 libs:: $(_HTTP_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
deleted file mode 100644
--- a/toolkit/components/places/tests/mochitest/bug_461710/visited_page-2.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-  <head>
-    <title>Visited page 2</title>
-  </head>
-  <body>
-    <p>This second page is marked as visited</p>
-  </body>
-</html>
\ No newline at end of file
deleted file mode 100644
--- a/toolkit/components/places/tests/mochitest/bug_461710/visited_page-3.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-  <head>
-    <title>Visited page 3</title>
-  </head>
-  <body>
-    <p>This third page is marked as visited</p>
-  </body>
-</html>
\ No newline at end of file
--- a/toolkit/components/places/tests/mochitest/test_bug_461710.html
+++ b/toolkit/components/places/tests/mochitest/test_bug_461710.html
@@ -17,103 +17,130 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 461710 **/
 
 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+
+const LAZY_ADD_TIMER = 3000;
+
+/**
+ * Helper function which waits until another function returns true, and
+ * then notifies a callback.
+ *
+ * Original function stolen from docshell/test/chrome/docshell_helpers.js.
+ *
+ * Parameters:
+ *
+ *    fn: a function which is evaluated repeatedly, and when it turns true,
+ *        the onWaitComplete callback is notified.
+ *
+ *    onWaitComplete:  a callback which will be notified when fn() returns
+ *        true.
+ */
+function waitForTrue(fn, onWaitComplete) {
+  var start = new Date().valueOf();
+
+  // Loop until the test function returns true, or until a timeout occurs,
+  // if a timeout is defined.
+  var intervalid =
+    setInterval(
+      function() {
+        if (fn.call()) {
+          // Stop calling the test function and notify the callback.
+          clearInterval(intervalid);
+          onWaitComplete.call();
+        }
+      }, 20);
+}
 
 const kRed = "rgb(255, 0, 0)";
 const kBlue = "rgb(0, 0, 255)";
 
 var testpath = document.location.pathname + "/../bug_461710/";
 var prefix = "http://localhost:8888" + testpath;
 var subtests = [
                    "visited_page.html",   // 1
-                   "visited_page-2.html", // 2
-                   "visited_page-3.html", // 3
-                   "link_page.html",      // 4
-                   "link_page-2.html",    // 5
-                   "link_page-3.html"     // 6
+                   "link_page.html",      // 2
+                   "link_page-2.html",    // 3
+                   "link_page-3.html"     // 4
                ];
 
 
 var testNum = 0;
 function loadNextTest() {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   // run the initialization code for each test
   switch (++ testNum) {
     case 1:
       // nothing to do here
       break;
 
     case 2:
-      // nothing to do here
+      ok(!pb.privateBrowsingEnabled, "Test #" + testNum + " should be run outside of private mode");
       break;
 
     case 3:
-      // nothing to do here
-      break;
-
-    case 4:
-      ok(!pb.privateBrowsingEnabled, "Test #" + testNum + " should be run outside of private mode");
-      break;
-
-    case 5:
       pb.privateBrowsingEnabled = true;
       ok(pb.privateBrowsingEnabled, "Test #" + testNum + " should be run inside of private mode");
       break;
 
-    case 6:
+    case 4:
       pb.privateBrowsingEnabled = false;
       ok(!pb.privateBrowsingEnabled, "Test #" + testNum + " should be run outside of private mode");
       break;
 
     default:
       ok(false, "Unexpected call to loadNextTest for test #" + testNum);
   }
 
+  if (testNum == 1) {
+    // Because of LAZY_ADD, the page won't be marked as visited until three seconds,
+    // so wait for four seconds to be safe
+    setTimeout(handleLoad, LAZY_ADD_TIMER * 2);
+  } else {
+    observer.expectURL(prefix + subtests[0]);
+    waitForTrue(function() observer.resolved, function() {
+      // And the nodes get notified after the "link-visited" topic, so
+      // we need to execute soon...
+      SimpleTest.executeSoon(handleLoad);
+    });
+  }
   iframe.src = prefix + subtests[testNum-1];
 }
 
 
 function checkTest() {
   switch (testNum) {
     case 1:
       // nothing to do here, we just want to mark the page as visited
       break;
 
     case 2:
-      // nothing to do here, we just want to mark the page as visited
-      break;
-
-    case 3:
-      // nothing to do here, we just want to mark the page as visited
-      break;
-
-    case 4:
       // run outside of private mode, link should appear as visited
       var doc = iframe.contentDocument;
       var win = doc.defaultView;
       var style = win.getComputedStyle(doc.getElementById("link"), "");
       is(style.getPropertyValue("color"), kRed, "Visited link coloring should work outside of private mode");
       break;
 
-    case 5:
+    case 3:
       // run inside of private mode, link should appear as not visited
       var doc = iframe.contentDocument;
       var win = doc.defaultView;
       var style = win.getComputedStyle(doc.getElementById("link"), "");
       is(style.getPropertyValue("color"), kBlue, "Visited link coloring should not work inside of private mode");
       break;
 
-    case 6:
+    case 4:
       // run outside of private mode, link should appear as visited
       var doc = iframe.contentDocument;
       var win = doc.defaultView;
       var style = win.getComputedStyle(doc.getElementById("link"), "");
       is(style.getPropertyValue("color"), kRed, "Visited link coloring should work outside of private mode");
       break;
 
     default:
@@ -132,44 +159,70 @@ function get_PBSvc() {
     _PBSvc = Cc["@mozilla.org/privatebrowsing;1"].
              getService(Ci.nsIPrivateBrowsingService);
     return _PBSvc;
   } catch (e) {}
   return null;
 }
 
 
-var ignoreLoad = false;
-function handleLoad(aEvent) {
+function handleLoad() {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   checkTest();
 
   if (testNum < subtests.length) {
     loadNextTest();
   } else {
     prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
     SimpleTest.finish();
   }
 }
 
+const URI_VISITED_RESOLUTION_TOPIC = "visited-status-resolution";
+var os, observer = {
+  uri: null,
+  resolved: true,
+  observe: function (aSubject, aTopic, aData) {
+    SimpleTest.is(aTopic, URI_VISITED_RESOLUTION_TOPIC, "Unexpected topic");
+
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+    if (this.uri.equals(aSubject.QueryInterface(Ci.nsIURI))) {
+      this.resolved = true;
+
+      os.removeObserver(this, URI_VISITED_RESOLUTION_TOPIC);
+    }
+  },
+  expectURL: function (url) {
+    ok(this.resolved, "Can't set the expected URL when another is yet to be resolved");
+    this.resolved = false;
+
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+    this.uri = NetUtil.newURI(url);
+    os.addObserver(this, URI_VISITED_RESOLUTION_TOPIC, false);
+  }
+};
 
 var pb = get_PBSvc();
 if (!pb) { // Private Browsing might not be available
   ok(true, "Private Browsing is not available");
   SimpleTest.finish();
 } else {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   var prefBranch = Cc["@mozilla.org/preferences-service;1"].
                    getService(Ci.nsIPrefBranch);
   prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
 
+  os = Cc["@mozilla.org/observer-service;1"].
+           getService(Ci.nsIObserverService);
+
   var iframe = document.getElementById("iframe");
-  iframe.onload = handleLoad;
 
   SimpleTest.waitForExplicitFinish();
 
   loadNextTest();
 }
 
 </script>
 </pre>