dom/base/nsHistory.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=78: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsHistory.h"
     9 #include "jsapi.h"
    10 #include "mozilla/dom/HistoryBinding.h"
    11 #include "nsCOMPtr.h"
    12 #include "nsPIDOMWindow.h"
    13 #include "nsIDocument.h"
    14 #include "nsIPresShell.h"
    15 #include "nsPresContext.h"
    16 #include "nsIDocShell.h"
    17 #include "nsIWebNavigation.h"
    18 #include "nsIURI.h"
    19 #include "nsIInterfaceRequestorUtils.h"
    20 #include "nsReadableUtils.h"
    21 #include "nsContentUtils.h"
    22 #include "nsISHistory.h"
    23 #include "nsISHistoryInternal.h"
    24 #include "mozilla/Preferences.h"
    26 using namespace mozilla;
    27 using namespace mozilla::dom;
    29 static const char* sAllowPushStatePrefStr =
    30   "browser.history.allowPushState";
    31 static const char* sAllowReplaceStatePrefStr =
    32   "browser.history.allowReplaceState";
    34 //
    35 //  History class implementation
    36 //
    37 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsHistory)
    38 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHistory)
    39 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHistory)
    40 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHistory)
    41   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    42   NS_INTERFACE_MAP_ENTRY(nsISupports)
    43   NS_INTERFACE_MAP_ENTRY(nsIDOMHistory) // Empty, needed for extension compat
    44 NS_INTERFACE_MAP_END
    46 nsHistory::nsHistory(nsPIDOMWindow* aInnerWindow)
    47   : mInnerWindow(do_GetWeakReference(aInnerWindow))
    48 {
    49   SetIsDOMBinding();
    50 }
    52 nsHistory::~nsHistory()
    53 {
    54 }
    56 nsPIDOMWindow*
    57 nsHistory::GetParentObject() const
    58 {
    59   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
    60   return win;
    61 }
    63 JSObject*
    64 nsHistory::WrapObject(JSContext* aCx)
    65 {
    66   return HistoryBinding::Wrap(aCx, this);
    67 }
    69 uint32_t
    70 nsHistory::GetLength(ErrorResult& aRv) const
    71 {
    72   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
    73   if (!win || !win->HasActiveDocument()) {
    74     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    76     return 0;
    77   }
    79   // Get session History from docshell
    80   nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
    81   if (!sHistory) {
    82     aRv.Throw(NS_ERROR_FAILURE);
    84     return 0;
    85   }
    87   int32_t len;
    88   nsresult rv = sHistory->GetCount(&len);
    90   if (NS_FAILED(rv)) {
    91     aRv.Throw(rv);
    93     return 0;
    94   }
    96   return len >= 0 ? len : 0;
    97 }
    99 void
   100 nsHistory::GetState(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   101                     ErrorResult& aRv) const
   102 {
   103   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
   104   if (!win) {
   105     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   106     return;
   107   }
   109   if (!win->HasActiveDocument()) {
   110     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   111     return;
   112   }
   114   nsCOMPtr<nsIDocument> doc =
   115     do_QueryInterface(win->GetExtantDoc());
   116   if (!doc) {
   117     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   118     return;
   119   }
   121   nsCOMPtr<nsIVariant> variant;
   122   doc->GetStateObject(getter_AddRefs(variant));
   124   if (variant) {
   125     aRv = variant->GetAsJSVal(aResult);
   127     if (aRv.Failed()) {
   128       return;
   129     }
   131     if (!JS_WrapValue(aCx, aResult)) {
   132       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
   133     }
   135     return;
   136   }
   138   aResult.setNull();
   139 }
   141 void
   142 nsHistory::Go(int32_t aDelta, ErrorResult& aRv)
   143 {
   144   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
   145   if (!win || !win->HasActiveDocument()) {
   146     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   148     return;
   149   }
   151   if (!aDelta) {
   152     nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(GetDocShell()));
   154     if (window && window->IsHandlingResizeEvent()) {
   155       // history.go(0) (aka location.reload()) was called on a window
   156       // that is handling a resize event. Sites do this since Netscape
   157       // 4.x needed it, but we don't, and it's a horrible experience
   158       // for nothing.  In stead of reloading the page, just clear
   159       // style data and reflow the page since some sites may use this
   160       // trick to work around gecko reflow bugs, and this should have
   161       // the same effect.
   163       nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   165       nsIPresShell *shell;
   166       nsPresContext *pcx;
   167       if (doc && (shell = doc->GetShell()) && (pcx = shell->GetPresContext())) {
   168         pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
   169       }
   171       return;
   172     }
   173   }
   175   nsCOMPtr<nsISHistory> session_history = GetSessionHistory();
   176   nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(session_history));
   177   if (!webnav) {
   178     aRv.Throw(NS_ERROR_FAILURE);
   180     return;
   181   }
   183   int32_t curIndex = -1;
   184   int32_t len = 0;
   185   session_history->GetIndex(&curIndex);
   186   session_history->GetCount(&len);
   188   int32_t index = curIndex + aDelta;
   189   if (index > -1 && index < len)
   190     webnav->GotoIndex(index);
   192   // Ignore the return value from GotoIndex(), since returning errors
   193   // from GotoIndex() can lead to exceptions and a possible leak
   194   // of history length
   195 }
   197 void
   198 nsHistory::Back(ErrorResult& aRv)
   199 {
   200   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
   201   if (!win || !win->HasActiveDocument()) {
   202     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   204     return;
   205   }
   207   nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
   208   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
   209   if (!webNav) {
   210     aRv.Throw(NS_ERROR_FAILURE);
   212     return;
   213   }
   215   webNav->GoBack();
   216 }
   218 void
   219 nsHistory::Forward(ErrorResult& aRv)
   220 {
   221   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
   222   if (!win || !win->HasActiveDocument()) {
   223     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   225     return;
   226   }
   228   nsCOMPtr<nsISHistory> sHistory = GetSessionHistory();
   229   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
   230   if (!webNav) {
   231     aRv.Throw(NS_ERROR_FAILURE);
   233     return;
   234   }
   236   webNav->GoForward();
   237 }
   239 void
   240 nsHistory::PushState(JSContext* aCx, JS::Handle<JS::Value> aData,
   241                      const nsAString& aTitle, const nsAString& aUrl,
   242                      ErrorResult& aRv)
   243 {
   244   PushOrReplaceState(aCx, aData, aTitle, aUrl, aRv, false);
   245 }
   247 void
   248 nsHistory::ReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
   249                         const nsAString& aTitle, const nsAString& aUrl,
   250                         ErrorResult& aRv)
   251 {
   252   PushOrReplaceState(aCx, aData, aTitle, aUrl, aRv, true);
   253 }
   255 void
   256 nsHistory::PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
   257                               const nsAString& aTitle, const nsAString& aUrl,
   258                               ErrorResult& aRv, bool aReplace)
   259 {
   260   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
   261   if (!win) {
   262     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   264     return;
   265   }
   267   if (!win->HasActiveDocument()) {
   268     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   270     return;
   271   }
   273   // Check that PushState hasn't been pref'ed off.
   274   if (!Preferences::GetBool(aReplace ? sAllowReplaceStatePrefStr :
   275                             sAllowPushStatePrefStr, false)) {
   276     return;
   277   }
   279   // AddState might run scripts, so we need to hold a strong reference to the
   280   // docShell here to keep it from going away.
   281   nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
   283   if (!docShell) {
   284     aRv.Throw(NS_ERROR_FAILURE);
   286     return;
   287   }
   289   // The "replace" argument tells the docshell to whether to add a new
   290   // history entry or modify the current one.
   292   aRv = docShell->AddState(aData, aTitle, aUrl, aReplace, aCx);
   293 }
   295 nsIDocShell*
   296 nsHistory::GetDocShell() const
   297 {
   298   nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mInnerWindow);
   299   if (!win) {
   300     return nullptr;
   301   }
   302   return win->GetDocShell();
   303 }
   305 already_AddRefed<nsISHistory>
   306 nsHistory::GetSessionHistory() const
   307 {
   308   nsIDocShell *docShell = GetDocShell();
   309   NS_ENSURE_TRUE(docShell, nullptr);
   311   // Get the root DocShell from it
   312   nsCOMPtr<nsIDocShellTreeItem> root;
   313   docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
   314   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(root));
   315   NS_ENSURE_TRUE(webNav, nullptr);
   317   nsCOMPtr<nsISHistory> shistory;
   319   // Get SH from nsIWebNavigation
   320   webNav->GetSessionHistory(getter_AddRefs(shistory));
   322   return shistory.forget();
   323 }

mercurial