Bug 737841 - Part 3: remove no more useful redirectsMode query option.
authorMarco Bonardo <mbonardo@mozilla.com>
Sat, 07 Apr 2012 01:17:53 +0200
changeset 94519 b94616a8d514973c005d75a9692f00f024102725
parent 94518 52a1ab08417af171997678dcb4f29f31cf2c6999
child 94520 3be23dcd43e45a3e108aded097c0065a6b244698
push idunknown
push userunknown
push dateunknown
bugs737841
milestone14.0a1
Bug 737841 - Part 3: remove no more useful redirectsMode query option. r=dietrich rs=gavin
browser/base/content/browser-places.js
browser/components/nsBrowserGlue.js
browser/components/places/tests/unit/head_bookmarks.js
browser/modules/NewTabUtils.jsm
browser/modules/WindowsJumpLists.jsm
netwerk/test/unit/test_URIs.js
services/sync/tests/unit/test_bookmark_smart_bookmarks.js
toolkit/components/places/PlacesDBUtils.jsm
toolkit/components/places/nsINavHistoryService.idl
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/nsNavHistoryQuery.cpp
toolkit/components/places/nsNavHistoryQuery.h
toolkit/components/places/tests/head_common.js
toolkit/components/places/tests/queries/head_queries.js
toolkit/components/places/tests/queries/test_querySerialization.js
toolkit/components/places/tests/queries/test_redirects.js
toolkit/components/places/tests/queries/test_redirectsMode.js
toolkit/components/places/tests/queries/xpcshell.ini
toolkit/components/places/tests/unit/test_preventive_maintenance.js
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -502,17 +502,17 @@ function HistoryMenu(aPopupShowingEvent)
   // views definitions, and we don't need them there.
   // Defining the prototype inheritance in the prototype itself would cause
   // browser.js to halt on "PlacesMenu is not defined" error.
   this.__proto__.__proto__ = PlacesMenu.prototype;
   XPCOMUtils.defineLazyServiceGetter(this, "_ss",
                                      "@mozilla.org/browser/sessionstore;1",
                                      "nsISessionStore");
   PlacesMenu.call(this, aPopupShowingEvent,
-                  "place:redirectsMode=2&sort=4&maxResults=15");
+                  "place:sort=4&maxResults=15");
 }
 
 HistoryMenu.prototype = {
   toggleRecentlyClosedTabs: function HM_toggleRecentlyClosedTabs() {
     // enable/disable the Recently Closed Tabs sub menu
     var undoMenu = this._rootElt.getElementsByClassName("recentlyClosedTabsMenu")[0];
 
     // no restorable tabs, so disable menu
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1347,17 +1347,17 @@ BrowserGlue.prototype = {
   ensurePlacesDefaultQueriesInitialized:
   function BG_ensurePlacesDefaultQueriesInitialized() {
     // This is actual version of the smart bookmarks, must be increased every
     // time smart bookmarks change.
     // When adding a new smart bookmark below, its newInVersion property must
     // be set to the version it has been added in, we will compare its value
     // to users' smartBookmarksVersion and add new smart bookmarks without
     // recreating old deleted ones.
-    const SMART_BOOKMARKS_VERSION = 3;
+    const SMART_BOOKMARKS_VERSION = 4;
     const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";
     const SMART_BOOKMARKS_PREF = "browser.places.smartBookmarksVersion";
 
     // TODO bug 399268: should this be a pref?
     const MAX_RESULTS = 10;
 
     // Get current smart bookmarks version.  If not set, create them.
     let smartBookmarksCurrentVersion = 0;
@@ -1375,19 +1375,17 @@ BrowserGlue.prototype = {
       runBatched: function BG_EPDQI_runBatched() {
         let menuIndex = 0;
         let toolbarIndex = 0;
         let bundle = Services.strings.createBundle("chrome://browser/locale/places/places.properties");
 
         let smartBookmarks = {
           MostVisited: {
             title: bundle.GetStringFromName("mostVisitedTitle"),
-            uri: NetUtil.newURI("place:redirectsMode=" +
-                                Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET +
-                                "&sort=" +
+            uri: NetUtil.newURI("place:sort=" +
                                 Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING +
                                 "&maxResults=" + MAX_RESULTS),
             parent: PlacesUtils.toolbarFolderId,
             position: toolbarIndex++,
             newInVersion: 1
           },
           RecentlyBookmarked: {
             title: bundle.GetStringFromName("recentlyBookmarkedTitle"),
--- a/browser/components/places/tests/unit/head_bookmarks.js
+++ b/browser/components/places/tests/unit/head_bookmarks.js
@@ -97,15 +97,15 @@ let (XULAppInfo = {
 
 
 const FILENAME_BOOKMARKS_HTML = "bookmarks.html";
 let (backup_date = new Date().toLocaleFormat("%Y-%m-%d")) {
   const FILENAME_BOOKMARKS_JSON = "bookmarks-" + backup_date + ".json";
 }
 
 // Smart bookmarks constants.
-const SMART_BOOKMARKS_VERSION = 3;
+const SMART_BOOKMARKS_VERSION = 4;
 const SMART_BOOKMARKS_ON_TOOLBAR = 1;
 const SMART_BOOKMARKS_ON_MENU = 3; // Takes in count the additional separator.
 
 // Default bookmarks constants.
 const DEFAULT_BOOKMARKS_ON_TOOLBAR = 1;
 const DEFAULT_BOOKMARKS_ON_MENU = 1;
--- a/browser/modules/NewTabUtils.jsm
+++ b/browser/modules/NewTabUtils.jsm
@@ -427,19 +427,16 @@ let PlacesProvider = {
    */
   getLinks: function PlacesProvider_getLinks(aCallback) {
     let options = PlacesUtils.history.getNewQueryOptions();
     options.maxResults = HISTORY_RESULTS_LIMIT;
 
     // Sort by frecency, descending.
     options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_FRECENCY_DESCENDING
 
-    // We don't want source redirects for this query.
-    options.redirectsMode = Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET;
-
     let links = [];
 
     let callback = {
       handleResult: function (aResultSet) {
         let row;
 
         while (row = aResultSet.getNextRow()) {
           let url = row.getResultByIndex(1);
--- a/browser/modules/WindowsJumpLists.jsm
+++ b/browser/modules/WindowsJumpLists.jsm
@@ -472,18 +472,16 @@ var WinTaskbarJumpList =
    * Nav history helpers
    */
 
   _getHistoryResults:
   function WTBLJL__getHistoryResults(aSortingMode, aLimit, aCallback, aScope) {
     var options = PlacesUtils.history.getNewQueryOptions();
     options.maxResults = aLimit;
     options.sortingMode = aSortingMode;
-    // We don't want source redirects for these queries.
-    options.redirectsMode = Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET;
     var query = PlacesUtils.history.getNewQuery();
 
     // Return the pending statement to the caller, to allow cancelation.
     return PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
                               .asyncExecuteLegacyQueries([query], 1, options, {
       handleResult: function (aResultSet) {
         for (let row; (row = aResultSet.getNextRow());) {
           try {
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -224,20 +224,20 @@ var gTests = [
     ref:     "",
     nsIURL:  false, nsINestedURI: false },
   { spec:    "blob:123456",
     scheme:  "blob",
     prePath: "blob:",
     path:    "123456",
     ref:     "",
     nsIURL:  false, nsINestedURI: false, immutable: true },
-  { spec:    "place:redirectsMode=2&sort=8&maxResults=10",
+  { spec:    "place:sort=8&maxResults=10",
     scheme:  "place",
     prePath: "place:",
-    path:    "redirectsMode=2&sort=8&maxResults=10",
+    path:    "sort=8&maxResults=10",
     ref:     "",
     nsIURL:  false, nsINestedURI: false },
   { spec:    "resource://gre/",
     scheme:  "resource",
     prePath: "resource://gre",
     path:    "/",
     ref:     "",
     nsIURL:  true, nsINestedURI: false },
--- a/services/sync/tests/unit/test_bookmark_smart_bookmarks.js
+++ b/services/sync/tests/unit/test_bookmark_smart_bookmarks.js
@@ -68,19 +68,17 @@ add_test(function test_annotation_upload
     // This can happen in XULRunner.
     clearBookmarks();
     _("Start count is now " + startCount);
   }
 
   _("Create a smart bookmark in the toolbar.");
   let parent = PlacesUtils.toolbarFolderId;
   let uri =
-    Utils.makeURI("place:redirectsMode=" +
-                  Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET +
-                  "&sort=" +
+    Utils.makeURI("place:sort=" +
                   Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING +
                   "&maxResults=10");
   let title = "Most Visited";
 
   let mostVisitedID = newSmartBookmark(parent, uri, -1, title, "MostVisited");
 
   _("New item ID: " + mostVisitedID);
   do_check_true(!!mostVisitedID);
@@ -175,19 +173,17 @@ add_test(function test_annotation_upload
   }
 });
 
 add_test(function test_smart_bookmarks_duped() {
   new SyncTestingInfrastructure();
 
   let parent = PlacesUtils.toolbarFolderId;
   let uri =
-    Utils.makeURI("place:redirectsMode=" +
-                  Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET +
-                  "&sort=" +
+    Utils.makeURI("place:sort=" +
                   Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING +
                   "&maxResults=10");
   let title = "Most Visited";
   let mostVisitedID = newSmartBookmark(parent, uri, -1, title, "MostVisited");
   let mostVisitedGUID = store.GUIDForId(mostVisitedID);
   
   let record = store.createRecord(mostVisitedGUID);
   
--- a/toolkit/components/places/PlacesDBUtils.jsm
+++ b/toolkit/components/places/PlacesDBUtils.jsm
@@ -706,16 +706,29 @@ let PlacesDBUtils = {
         "SELECT h.id FROM moz_places h " +
         "WHERE visit_count <> (SELECT count(*) FROM moz_historyvisits v " +
                               "WHERE v.place_id = h.id AND visit_type NOT IN (0,4,7,8)) " +
            "OR last_visit_date <> (SELECT MAX(visit_date) FROM moz_historyvisits v " +
                                   "WHERE v.place_id = h.id) " +
       ")");
     cleanupStatements.push(fixVisitStats);
 
+    // L.3 recalculate hidden for redirects.
+    let fixRedirectsHidden = DBConn.createAsyncStatement(
+      "UPDATE moz_places " +
+      "SET hidden = 1 " +
+      "WHERE id IN ( " +
+        "SELECT h.id FROM moz_places h " +
+        "JOIN moz_historyvisits src ON src.place_id = h.id " +
+        "JOIN moz_historyvisits dst ON dst.from_visit = src.id AND dst.visit_type IN (5,6) " +
+        "LEFT JOIN moz_bookmarks on fk = h.id AND fk ISNULL " +
+        "GROUP BY src.place_id HAVING count(*) = visit_count " +
+      ")");
+    cleanupStatements.push(fixRedirectsHidden);
+
     // MAINTENANCE STATEMENTS SHOULD GO ABOVE THIS POINT!
 
     return cleanupStatements;
   },
 
   /**
    * Tries to vacuum the database.
    *
--- a/toolkit/components/places/nsINavHistoryService.idl
+++ b/toolkit/components/places/nsINavHistoryService.idl
@@ -1035,17 +1035,17 @@ interface nsINavHistoryQuery : nsISuppor
    * Creates a new query item with the same parameters of this one.
    */
   nsINavHistoryQuery clone();
 };
 
 /**
  * This object represents the global options for executing a query.
  */
-[scriptable, uuid(d46a1ae7-aef8-47a2-9a5c-e6347253f9b2)]
+[scriptable, uuid(8198dfa7-8061-4766-95cb-fa86b3c00a47)]
 interface nsINavHistoryQueryOptions : nsISupports
 {
   /**
    * You can ask for the results to be pre-sorted. Since the DB has indices
    * of many items, it can produce sorted results almost for free. These should
    * be self-explanatory.
    *
    * Note: re-sorting is slower, as is sorting by title or when you have a
@@ -1196,48 +1196,24 @@ interface nsINavHistoryQueryOptions : ns
    *
    * Note that this has no effect on folder links, which are place: URIs
    * returned by nsINavBookmarkService.GetFolderURI. These are always expanded
    * and will appear as bookmark folders.
    */
   attribute boolean expandQueries;
 
   /**
-   * Most items in history are marked "hidden." Only toplevel pages that the
-   * user sees in the URL bar are not hidden. Hidden things include the content
-   * of iframes and all images on web pages. Normally, you don't want these
-   * things. If you do, set this flag and you'll get all items, even hidden
-   * ones. Does nothing for bookmark queries. Defaults to false.
+   * Some pages in history are marked "hidden" and thus don't appear by default
+   * in queries.  These include automatic framed visits and redirects.  Setting
+   * this attribute will return all pages, even hidden ones.  Does nothing for
+   * bookmark queries. Defaults to false.
    */
   attribute boolean includeHidden;
 
   /**
-   * Include both redirected-from and redirected-to pages into results.
-   */
-  const unsigned short REDIRECTS_MODE_ALL = 0;
-  /**
-   * Query results will not include redirected-to pages, but will include
-   * redirected-from pages.
-   */
-  const unsigned short REDIRECTS_MODE_SOURCE = 1;
-  /**
-   * Query results will not include redirected-from pages but will include
-   * redirected-to pages.
-   */
-  const unsigned short REDIRECTS_MODE_TARGET = 2;
-
-  /**
-   * Defines how redirects should be handled, see REDIRECTS_MODE_* constants
-   * above.
-   * Defaults to REDIRECTS_MODE_ALL.
-   * Note: this option is effective only on QUERY_TYPE_HISTORY.
-   */
-  attribute unsigned short redirectsMode;
-
-  /**
    * This is the maximum number of results that you want. The query is exeucted,
    * the results are sorted, and then the top 'maxResults' results are taken
    * and returned. Set to 0 (the default) to get all results.
    *
    * THIS DOES NOT WORK IN CONJUNCTION WITH SORTING BY TITLE. This is because
    * sorting by title requires us to sort after using locale-sensetive sorting
    * (as opposed to letting the database do it for us).
    *
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -1627,20 +1627,20 @@ nsNavHistory::ExecuteQueries(nsINavHisto
 
   NS_ADDREF(*_retval = result);
   return NS_OK;
 }
 
 // determine from our nsNavHistoryQuery array and nsNavHistoryQueryOptions
 // if this is the place query from the history menu.
 // from browser-menubar.inc, our history menu query is:
-// place:redirectsMode=2&sort=4&maxResults=10
+// place:sort=4&maxResults=10
 // note, any maxResult > 0 will still be considered a history menu query
-// or if this is the place query from the "Most Visited" item in the "Smart Bookmarks" folder:
-// place:redirectsMode=2&sort=8&maxResults=10
+// or if this is the place query from the "Most Visited" item in the
+// "Smart Bookmarks" folder: place:sort=8&maxResults=10
 // note, any maxResult > 0 will still be considered a Most Visited menu query
 static
 bool IsOptimizableHistoryQuery(const nsCOMArray<nsNavHistoryQuery>& aQueries,
                                  nsNavHistoryQueryOptions *aOptions,
                                  PRUint16 aSortMode)
 {
   if (aQueries.Count() != 1)
     return false;
@@ -1744,17 +1744,16 @@ private:
 
   const nsCString& mConditions;
   bool mUseLimit;
   bool mHasSearchTerms;
 
   PRUint16 mResultType;
   PRUint16 mQueryType;
   bool mIncludeHidden;
-  PRUint16 mRedirectsMode;
   PRUint16 mSortingMode;
   PRUint32 mMaxResults;
 
   nsCString mQueryString;
   nsCString mGroupBy;
   bool mHasDateColumns;
   bool mSkipOrderBy;
   nsNavHistory::StringHash& mAddParams;
@@ -1767,17 +1766,16 @@ PlacesSQLQueryBuilder::PlacesSQLQueryBui
     nsNavHistory::StringHash& aAddParams,
     bool aHasSearchTerms)
 : mConditions(aConditions)
 , mUseLimit(aUseLimit)
 , mHasSearchTerms(aHasSearchTerms)
 , mResultType(aOptions->ResultType())
 , mQueryType(aOptions->QueryType())
 , mIncludeHidden(aOptions->IncludeHidden())
-, mRedirectsMode(aOptions->RedirectsMode())
 , mSortingMode(aOptions->SortingMode())
 , mMaxResults(aOptions->MaxResults())
 , mSkipOrderBy(false)
 , mAddParams(aAddParams)
 {
   mHasDateColumns = (mQueryType == nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS);
 }
 
@@ -2244,37 +2242,16 @@ PlacesSQLQueryBuilder::SelectAsTag()
 nsresult
 PlacesSQLQueryBuilder::Where()
 {
 
   // Set query options
   nsCAutoString additionalVisitsConditions;
   nsCAutoString additionalPlacesConditions;
 
-  if (mRedirectsMode == nsINavHistoryQueryOptions::REDIRECTS_MODE_SOURCE) {
-    // At least one visit that is not a redirect target should exist.
-    additionalVisitsConditions += NS_LITERAL_CSTRING(
-      "AND visit_type NOT IN ") +
-      nsPrintfCString("(%d,%d) ", nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
-                                  nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY);
-  }
-  else if (mRedirectsMode == nsINavHistoryQueryOptions::REDIRECTS_MODE_TARGET) {
-    // At least one visit that is not a redirect source should exist.
-    additionalPlacesConditions += nsPrintfCString(1024,
-      "AND EXISTS ( "
-        "SELECT id "
-        "FROM moz_historyvisits v "
-        "WHERE place_id = h.id "
-          "AND NOT EXISTS(SELECT id FROM moz_historyvisits "
-                         "WHERE from_visit = v.id AND visit_type IN (%d,%d)) "
-      ") ",
-      nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
-      nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY);
-  }
-
   if (!mIncludeHidden) {
     additionalPlacesConditions += NS_LITERAL_CSTRING("AND hidden = 0 ");
   }
 
   if (mQueryType == nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY) {
     // last_visit_date is updated for any kind of visit, so it's a good
     // indicator whether the page has visits.
     additionalPlacesConditions += NS_LITERAL_CSTRING(
@@ -2503,43 +2480,17 @@ nsNavHistory::ConstructQueryString(
       queryString.Append(NS_LITERAL_CSTRING("last_visit_date DESC "));
     else
       queryString.Append(NS_LITERAL_CSTRING("visit_count DESC "));
 
     queryString.Append(NS_LITERAL_CSTRING("LIMIT "));
     queryString.AppendInt(aOptions->MaxResults());
 
     nsCAutoString additionalQueryOptions;
-    if (aOptions->RedirectsMode() ==
-          nsINavHistoryQueryOptions::REDIRECTS_MODE_SOURCE) {
-      // At least one visit that is not a redirect target should exist.
-      additionalQueryOptions +=  nsPrintfCString(256,
-        "AND EXISTS ( "
-          "SELECT id "
-          "FROM moz_historyvisits "
-          "WHERE place_id = h.id "
-            "AND visit_type NOT IN (%d,%d)"
-        ") ",
-        TRANSITION_REDIRECT_PERMANENT,
-        TRANSITION_REDIRECT_TEMPORARY);
-    }
-    else if (aOptions->RedirectsMode() ==
-              nsINavHistoryQueryOptions::REDIRECTS_MODE_TARGET) {
-      // At least one visit that is not a redirect source should exist.
-      additionalQueryOptions += nsPrintfCString(1024,
-        "AND EXISTS ( "
-          "SELECT id "
-          "FROM moz_historyvisits v "
-          "WHERE place_id = h.id "
-            "AND NOT EXISTS(SELECT id FROM moz_historyvisits "
-                           "WHERE from_visit = v.id AND visit_type IN (%d,%d)) "
-        ") ",
-        TRANSITION_REDIRECT_PERMANENT,
-        TRANSITION_REDIRECT_TEMPORARY);
-    }
+
     queryString.ReplaceSubstring("{QUERY_OPTIONS}",
                                   additionalQueryOptions.get());
     return NS_OK;
   }
 
   nsCAutoString conditions;
   for (PRInt32 i = 0; i < aQueries.Count(); i++) {
     nsCString queryClause;
--- a/toolkit/components/places/nsNavHistoryQuery.cpp
+++ b/toolkit/components/places/nsNavHistoryQuery.cpp
@@ -166,17 +166,16 @@ static void SetOptionsKeyUint32(const ns
 #define QUERYKEY_SORTING_ANNOTATION "sortingAnnotation"
 #define QUERYKEY_RESULT_TYPE "type"
 #define QUERYKEY_EXCLUDE_ITEMS "excludeItems"
 #define QUERYKEY_EXCLUDE_QUERIES "excludeQueries"
 #define QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "excludeReadOnlyFolders"
 #define QUERYKEY_EXPAND_QUERIES "expandQueries"
 #define QUERYKEY_FORCE_ORIGINAL_TITLE "originalTitle"
 #define QUERYKEY_INCLUDE_HIDDEN "includeHidden"
-#define QUERYKEY_REDIRECTS_MODE "redirectsMode"
 #define QUERYKEY_MAX_RESULTS "maxResults"
 #define QUERYKEY_QUERY_TYPE "queryType"
 #define QUERYKEY_TAG "tag"
 #define QUERYKEY_NOTTAGS "!tags"
 #define QUERYKEY_ASYNC_ENABLED "asyncEnabled"
 #define QUERYKEY_TRANSITION "transition"
 
 inline void AppendAmpersandIfNonempty(nsACString& aString)
@@ -589,23 +588,16 @@ nsNavHistory::QueriesToQueryString(nsINa
   }
 
   // include hidden
   if (options->IncludeHidden()) {
     AppendAmpersandIfNonempty(queryString);
     queryString += NS_LITERAL_CSTRING(QUERYKEY_INCLUDE_HIDDEN "=1");
   }
 
-  // redirects mode
-  if (options->RedirectsMode() !=  nsINavHistoryQueryOptions::REDIRECTS_MODE_ALL) {
-    AppendAmpersandIfNonempty(queryString);
-    queryString += NS_LITERAL_CSTRING(QUERYKEY_REDIRECTS_MODE "=");
-    AppendInt16(queryString, options->RedirectsMode());
-  }
-
   // max results
   if (options->MaxResults()) {
     AppendAmpersandIfNonempty(queryString);
     queryString += NS_LITERAL_CSTRING(QUERYKEY_MAX_RESULTS "=");
     AppendInt32(queryString, options->MaxResults());
   }
 
   // queryType
@@ -871,20 +863,16 @@ nsNavHistory::TokensToQueries(const nsTA
     // expand queries
     } else if (kvp.key.EqualsLiteral(QUERYKEY_EXPAND_QUERIES)) {
       SetOptionsKeyBool(kvp.value, aOptions,
                         &nsINavHistoryQueryOptions::SetExpandQueries);
     // include hidden
     } else if (kvp.key.EqualsLiteral(QUERYKEY_INCLUDE_HIDDEN)) {
       SetOptionsKeyBool(kvp.value, aOptions,
                         &nsINavHistoryQueryOptions::SetIncludeHidden);
-    // query type
-    } else if (kvp.key.EqualsLiteral(QUERYKEY_REDIRECTS_MODE)) {
-      SetOptionsKeyUint16(kvp.value, aOptions,
-                          &nsINavHistoryQueryOptions::SetRedirectsMode);
     // max results
     } else if (kvp.key.EqualsLiteral(QUERYKEY_MAX_RESULTS)) {
       SetOptionsKeyUint32(kvp.value, aOptions,
                           &nsINavHistoryQueryOptions::SetMaxResults);
     // query type
     } else if (kvp.key.EqualsLiteral(QUERYKEY_QUERY_TYPE)) {
       SetOptionsKeyUint16(kvp.value, aOptions,
                           &nsINavHistoryQueryOptions::SetQueryType);
@@ -1516,30 +1504,16 @@ nsNavHistoryQueryOptions::GetIncludeHidd
 }
 NS_IMETHODIMP
 nsNavHistoryQueryOptions::SetIncludeHidden(bool aIncludeHidden)
 {
   mIncludeHidden = aIncludeHidden;
   return NS_OK;
 }
 
-// redirectsMode
-NS_IMETHODIMP
-nsNavHistoryQueryOptions::GetRedirectsMode(PRUint16* _retval)
-{
-  *_retval = mRedirectsMode;
-  return NS_OK;
-}
-NS_IMETHODIMP
-nsNavHistoryQueryOptions::SetRedirectsMode(PRUint16 aRedirectsMode)
-{
-  mRedirectsMode = aRedirectsMode;
-  return NS_OK;
-}
-
 // maxResults
 NS_IMETHODIMP
 nsNavHistoryQueryOptions::GetMaxResults(PRUint32* aMaxResults)
 {
   *aMaxResults = mMaxResults;
   return NS_OK;
 }
 NS_IMETHODIMP
--- a/toolkit/components/places/nsNavHistoryQuery.h
+++ b/toolkit/components/places/nsNavHistoryQuery.h
@@ -136,17 +136,16 @@ public:
   nsNavHistoryQueryOptions()
   : mSort(0)
   , mResultType(0)
   , mExcludeItems(false)
   , mExcludeQueries(false)
   , mExcludeReadOnlyFolders(false)
   , mExpandQueries(true)
   , mIncludeHidden(false)
-  , mRedirectsMode(nsINavHistoryQueryOptions::REDIRECTS_MODE_ALL)
   , mMaxResults(0)
   , mQueryType(nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY)
   , mAsyncEnabled(false)
   { }
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYQUERYOPTIONS_IID)
 
   NS_DECL_ISUPPORTS
@@ -154,17 +153,16 @@ public:
 
   PRUint16 SortingMode() const { return mSort; }
   PRUint16 ResultType() const { return mResultType; }
   bool ExcludeItems() const { return mExcludeItems; }
   bool ExcludeQueries() const { return mExcludeQueries; }
   bool ExcludeReadOnlyFolders() const { return mExcludeReadOnlyFolders; }
   bool ExpandQueries() const { return mExpandQueries; }
   bool IncludeHidden() const { return mIncludeHidden; }
-  PRUint16 RedirectsMode() const { return mRedirectsMode; }
   PRUint32 MaxResults() const { return mMaxResults; }
   PRUint16 QueryType() const { return mQueryType; }
   bool AsyncEnabled() const { return mAsyncEnabled; }
 
   nsresult Clone(nsNavHistoryQueryOptions **aResult);
 
 private:
   nsNavHistoryQueryOptions(const nsNavHistoryQueryOptions& other) {} // no copy
@@ -179,17 +177,16 @@ private:
   nsCString mSortingAnnotation;
   nsCString mParentAnnotationToExclude;
   PRUint16 mResultType;
   bool mExcludeItems;
   bool mExcludeQueries;
   bool mExcludeReadOnlyFolders;
   bool mExpandQueries;
   bool mIncludeHidden;
-  PRUint16 mRedirectsMode;
   PRUint32 mMaxResults;
   PRUint16 mQueryType;
   bool mAsyncEnabled;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryQueryOptions, NS_NAVHISTORYQUERYOPTIONS_IID)
 
 #endif // nsNavHistoryQuery_h_
--- a/toolkit/components/places/tests/head_common.js
+++ b/toolkit/components/places/tests/head_common.js
@@ -877,16 +877,17 @@ NavHistoryResultObserver.prototype = {
  * @param aPlaceInfo
  *        Can be an nsIURI, in such a case a single LINK visit will be added.
  *        Otherwise can be an object describing the visit to add, or an array
  *        of these objects:
  *          { uri: nsIURI of the page,
  *            transition: one of the TRANSITION_* from nsINavHistoryService,
  *            [optional] title: title of the page,
  *            [optional] visitDate: visit date in microseconds from the epoch
+ *            [optional] referrer: nsIURI of the referrer for this visit
  *          }
  * @param [optional] aCallback
  *        Function to be invoked on completion.
  * @param [optional] aStack
  *        The stack frame used to report errors.
  */
 function addVisits(aPlaceInfo, aCallback, aStack)
 {
@@ -905,17 +906,18 @@ function addVisits(aPlaceInfo, aCallback
   let now = Date.now();
   for (let i = 0; i < places.length; i++) {
     if (!places[i].title) {
       places[i].title = "test visit for " + places[i].uri.spec;
     }
     places[i].visits = [{
       transitionType: places[i].transition === undefined ? TRANSITION_LINK
                                                          : places[i].transition,
-      visitDate: places[i].visitDate || (now++) * 1000
+      visitDate: places[i].visitDate || (now++) * 1000,
+      referrerURI: places[i].referrer
     }];
   }
 
   PlacesUtils.asyncHistory.updatePlaces(
     places,
     {
       handleError: function AAV_handleError() {
         do_throw("Unexpected error in adding visit.", stack);
--- a/toolkit/components/places/tests/queries/head_queries.js
+++ b/toolkit/components/places/tests/queries/head_queries.js
@@ -102,16 +102,35 @@ function populateDB(aArray) {
                 print("Error while setting visit_count.");
               }
               finally {
                 stmt.finalize();
               }
             }
           }
 
+          if (qdata.isRedirect) {
+            // Redirect sources added through the docshell are properly marked
+            // as redirects and get hidden state, the API doesn't have that
+            // power (And actually doesn't make much sense to add redirects
+            // through the API).
+            let stmt = DBConn().createStatement(
+              "UPDATE moz_places SET hidden = 1 WHERE url = :url");
+            stmt.params.url = qdata.uri;
+            try {
+              stmt.execute();
+            }
+            catch (ex) {
+              print("Error while setting visit_count.");
+            }
+            finally {
+              stmt.finalize();
+            }
+          }
+
           if (qdata.isDetails) {
             // Then we add extraneous page details for testing
             PlacesUtils.history.addPageWithDetails(uri(qdata.uri),
                                                    qdata.title, qdata.lastVisit);
           }
 
           if (qdata.markPageAsTyped){
             PlacesUtils.bhistory.markPageAsTyped(uri(qdata.uri));
--- a/toolkit/components/places/tests/queries/test_querySerialization.js
+++ b/toolkit/components/places/tests/queries/test_querySerialization.js
@@ -500,33 +500,16 @@ const queryOptionSwitches = [
       function (aQuery, aQueryOptions) {
         aQueryOptions.queryType = aQueryOptions.QUERY_TYPE_HISTORY;
       },
       function (aQuery, aQueryOptions) {
         aQueryOptions.queryType = aQueryOptions.QUERY_TYPE_UNIFIED;
       }
     ]
   },
-  // redirectsMode
-  {
-    property: "redirectsMode",
-    desc:     "nsINavHistoryQueryOptions.redirectsMode",
-    matches:  simplePropertyMatches,
-    runs:     [
-      function (aQuery, aQueryOptions) {
-        aQueryOptions.redirectsMode = aQueryOptions.REDIRECTS_MODE_ALL;
-      },
-      function (aQuery, aQueryOptions) {
-        aQueryOptions.redirectsMode = aQueryOptions.REDIRECTS_MODE_TARGET;
-      },
-      function (aQuery, aQueryOptions) {
-        aQueryOptions.redirectsMode = aQueryOptions.REDIRECTS_MODE_SOURCE;
-      }
-    ]
-  },
 ];
 
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
  * Enumerates all the sequences of the cartesian product of the arrays contained
  * in aSequences.  Examples:
  *
rename from toolkit/components/places/tests/queries/test_redirectsMode.js
rename to toolkit/components/places/tests/queries/test_redirects.js
--- a/toolkit/components/places/tests/queries/test_redirectsMode.js
+++ b/toolkit/components/places/tests/queries/test_redirects.js
@@ -1,100 +1,54 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Places Test Code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Marco Bonardo <mak77@bonardo.net> (Original Author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Array of visits we will add to the database, will be populated later
 // in the test.
 let visits = [];
 
 /**
  * Takes a sequence of query options, and compare query results obtained through
  * them with a custom filtered array of visits, based on the values we are
  * expecting from the query.
  *
  * @param  aSequence
  *         an array that contains query options in the form:
- *         [includeHidden, redirectsMode, maxResults, sortingMode]
+ *         [includeHidden, maxResults, sortingMode]
  */
 function check_results_callback(aSequence) {
   // Sanity check: we should receive 3 parameters.
-  do_check_eq(aSequence.length, 4);
+  do_check_eq(aSequence.length, 3);
   let includeHidden = aSequence[0];
-  let redirectsMode = aSequence[1];
-  let maxResults = aSequence[2];
-  let sortingMode = aSequence[3];
+  let maxResults = aSequence[1];
+  let sortingMode = aSequence[2];
   print("\nTESTING: includeHidden(" + includeHidden + ")," +
-                  " redirectsMode(" + redirectsMode + ")," +
                   " maxResults("    + maxResults    + ")," +
                   " sortingMode("   + sortingMode   + ").");
 
+  function isHidden(aVisit) {
+    return aVisit.transType == Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK ||
+           aVisit.isRedirect;
+  }
+
   // Build expectedData array.
   let expectedData = visits.filter(function (aVisit, aIndex, aArray) {
     // Embed visits never appear in results.
     if (aVisit.transType == Ci.nsINavHistoryService.TRANSITION_EMBED)
       return false;
 
-    if (aVisit.transType == Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK &&
-      !includeHidden) {
+    if (!includeHidden && isHidden(aVisit)) {
       // If the page has any non-hidden visit, then it's visible.
       if (visits.filter(function (refVisit) {
-            return refVisit.uri == aVisit.uri &&
-                   refVisit.transType != Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK;
+        return refVisit.uri == aVisit.uri && !isHidden(refVisit);
           }).length == 0)
         return false;
     }
 
-    if (redirectsMode == Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_SOURCE) {
-      // Filter out any redirect target.
-      return aVisit.transType != Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT &&
-             aVisit.transType != Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY;
-    }
-
-    if (redirectsMode == Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET) {
-      // Filter out any entry that is a redirect source.
-      return visits.filter(function (refVisit) {
-        return !refVisit.isRedirect && refVisit.uri == aVisit.uri;
-      }).length > 0;
-    }
-
     return true;
   });
 
   // Remove duplicates, since queries are RESULTS_AS_URI (unique pages).
   let seen = [];
   expectedData = expectedData.filter(function (aData) {
     if (seen.indexOf(aData.uri) != -1)
       return false;
@@ -124,17 +78,16 @@ function check_results_callback(aSequenc
   if (maxResults) {
     expectedData = expectedData.slice(0, maxResults);
   }
 
   // Create a new query with required options.
   let query = PlacesUtils.history.getNewQuery();
   let options = PlacesUtils.history.getNewQueryOptions();
   options.includeHidden = includeHidden;
-  options.redirectsMode = redirectsMode;
   options.sortingMode = sortingMode;
   if (maxResults)
     options.maxResults = maxResults;
 
   // Compare resultset with expectedData.
   let result = PlacesUtils.history.executeQuery(query, options);
   let root = result.root;
   root.containerOpen = true;
@@ -251,16 +204,17 @@ function add_visits_to_database() {
   ];
 
   // we add a visit for each of the above transition types.
   t.forEach(function (transition) visits.push(
     { isVisit: true,
       transType: transition,
       uri: "http://" + transition + ".example.com/",
       title: transition + "-example",
+      isRedirect: true,
       lastVisit: timeInMicroseconds--,
       visitCount: (transition == Ci.nsINavHistoryService.TRANSITION_EMBED ||
                    transition == Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK) ? 0 : visitCount++,
       isInQuery: true }));
 
   // Add a REDIRECT_TEMPORARY layer of visits for each of the above visits.
   t.forEach(function (transition) visits.push(
     { isVisit: true,
@@ -298,16 +252,17 @@ function add_visits_to_database() {
     return null;
   }
   t.forEach(function (transition) visits.push(
     { isVisit: true,
       transType: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT,
       uri: "http://" + transition + ".example.com/",
       title: getLastValue("http://" + transition + ".example.com/", "title"),
       lastVisit: getLastValue("http://" + transition + ".example.com/", "lastVisit"),
+      isRedirect: true,
       referrer: "http://" + transition + ".redirect.perm.example.com/",
       visitCount: getLastValue("http://" + transition + ".example.com/", "visitCount"),
       isInQuery: true }));
 
   // Add an unvisited bookmark in the database, it should never appear.
   visits.push({ isBookmark: true,
     uri: "http://unvisited.bookmark.com/",
     parentFolder: PlacesUtils.bookmarksMenuFolderId,
@@ -329,24 +284,21 @@ function run_test() {
   // Frecency and hidden are updated asynchronously, wait for them.
   waitForAsyncUpdates(continue_test);
  }
 
  function continue_test() {
   // This array will be used by cartProd to generate a matrix of all possible
   // combinations.
   let includeHidden_options = [true, false];
-  let redirectsMode_options =  [Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_ALL,
-                                Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_SOURCE,
-                                Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET];
   let maxResults_options = [5, 10, 20, null];
   // These sortingMode are choosen to toggle using special queries for history
   // menu and most visited smart bookmark.
   let sorting_options = [Ci.nsINavHistoryQueryOptions.SORT_BY_NONE,
                          Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING,
                          Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING];
   // Will execute check_results_callback() for each generated combination.
-  cartProd([includeHidden_options, redirectsMode_options, maxResults_options, sorting_options],
+  cartProd([includeHidden_options, maxResults_options, sorting_options],
            check_results_callback);
 
   remove_all_bookmarks();
   waitForClearHistory(do_test_finished);
 }
--- a/toolkit/components/places/tests/queries/xpcshell.ini
+++ b/toolkit/components/places/tests/queries/xpcshell.ini
@@ -7,17 +7,17 @@ tail =
 [test_abstime-annotation-uri.js]
 [test_async.js]
 [test_containersQueries_sorting.js]
 [test_excludeReadOnlyFolders.js]
 [test_history_queries_tags_liveUpdate.js]
 [test_history_queries_titles_liveUpdate.js]
 [test_onlyBookmarked.js]
 [test_querySerialization.js]
-[test_redirectsMode.js]
+[test_redirects.js]
 # Bug 676989: test hangs consistently on Android
 skip-if = os == "android"
 [test_results-as-tag-contents-query.js]
 [test_results-as-visit.js]
 [test_searchterms-domain.js]
 [test_searchterms-uri.js]
 [test_searchterms-bookmarklets.js]
 [test_sort-date-site-grouping.js]
--- a/toolkit/components/places/tests/unit/test_preventive_maintenance.js
+++ b/toolkit/components/places/tests/unit/test_preventive_maintenance.js
@@ -1141,16 +1141,64 @@ tests.push({
     do_check_false(stmt.executeStep());
     stmt.finalize();
   }
 });
 
 //------------------------------------------------------------------------------
 
 tests.push({
+  name: "L.3",
+  desc: "recalculate hidden for redirects.",
+
+  setup: function() {
+    addVisits([
+      { uri: NetUtil.newURI("http://l3.moz.org/"),
+        transition: TRANSITION_TYPED },
+      { uri: NetUtil.newURI("http://l3.moz.org/redirecting/"),
+        transition: TRANSITION_TYPED },
+      { uri: NetUtil.newURI("http://l3.moz.org/redirecting2/"),
+        transition: TRANSITION_REDIRECT_TEMPORARY,
+        referrer: NetUtil.newURI("http://l3.moz.org/redirecting/") },
+      { uri: NetUtil.newURI("http://l3.moz.org/target/"),
+        transition: TRANSITION_REDIRECT_PERMANENT,
+        referrer: NetUtil.newURI("http://l3.moz.org/redirecting2/") },
+    ]);
+  },
+
+  asyncCheck: function(aCallback) {
+    let stmt = mDBConn.createAsyncStatement(
+      "SELECT h.url FROM moz_places h WHERE h.hidden = 1"
+    );
+    stmt.executeAsync({
+      _count: 0,
+      handleResult: function(aResultSet) {
+        for (let row; (row = aResultSet.getNextRow());) {
+          let url = row.getResultByIndex(0);
+          do_check_true(/redirecting/.test(url));
+          this._count++;
+        }
+      },
+      handleError: function(aError) {
+      },
+      handleCompletion: function(aReason) {
+        dump_table("moz_places");
+        dump_table("moz_historyvisits");
+        do_check_eq(aReason, Ci.mozIStorageStatementCallback.REASON_FINISHED);
+        do_check_eq(this._count, 2);
+        aCallback();
+      }
+    });
+    stmt.finalize();
+  }
+});
+
+//------------------------------------------------------------------------------
+
+tests.push({
   name: "Z",
   desc: "Sanity: Preventive maintenance does not touch valid items",
 
   _uri1: uri("http://www1.mozilla.org"),
   _uri2: uri("http://www2.mozilla.org"),
   _folderId: null,
   _bookmarkId: null,
   _separatorId: null,