/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ #include "PartialSHistory.h" #include "nsIWebNavigation.h" namespace mozilla { namespace dom { NS_IMPL_CYCLE_COLLECTION(PartialSHistory, mOwnerFrameLoader) NS_IMPL_CYCLE_COLLECTING_ADDREF(PartialSHistory) NS_IMPL_CYCLE_COLLECTING_RELEASE(PartialSHistory) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PartialSHistory) NS_INTERFACE_MAP_ENTRY(nsIPartialSHistory) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPartialSHistory) NS_INTERFACE_MAP_ENTRY(nsISHistoryListener) NS_INTERFACE_MAP_ENTRY(nsIPartialSHistoryListener) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END PartialSHistory::PartialSHistory(nsIFrameLoader* aOwnerFrameLoader) : mCount(0), mGlobalIndexOffset(0), mOwnerFrameLoader(aOwnerFrameLoader) { MOZ_ASSERT(aOwnerFrameLoader); } already_AddRefed PartialSHistory::GetSessionHistory() { if (!mOwnerFrameLoader) { // Cycle collected? return nullptr; } nsCOMPtr docShell; mOwnerFrameLoader->GetDocShell(getter_AddRefs(docShell)); if (!docShell) { return nullptr; } nsCOMPtr webNav(do_QueryInterface(docShell)); nsCOMPtr shistory; webNav->GetSessionHistory(getter_AddRefs(shistory)); return shistory.forget(); } already_AddRefed PartialSHistory::GetTabParent() { if (!mOwnerFrameLoader) { // Cycle collected? return nullptr; } nsCOMPtr tabParent; mOwnerFrameLoader->GetTabParent(getter_AddRefs(tabParent)); return RefPtr(static_cast(tabParent.get())).forget(); } NS_IMETHODIMP PartialSHistory::GetCount(uint32_t* aResult) { if (!aResult) { return NS_ERROR_INVALID_POINTER; } // If we have direct reference to nsISHistory, simply pass through. nsCOMPtr shistory(GetSessionHistory()); if (shistory) { int32_t count; nsresult rv = shistory->GetCount(&count); if (NS_FAILED(rv) || count < 0) { *aResult = 0; return NS_ERROR_FAILURE; } *aResult = count; return NS_OK; } // Otherwise use the cached value. *aResult = mCount; return NS_OK; } NS_IMETHODIMP PartialSHistory::GetGlobalIndex(int32_t* aResult) { if (!aResult) { return NS_ERROR_INVALID_POINTER; } nsCOMPtr shistory = GetSessionHistory(); if (shistory) { int32_t idx; nsresult rv = shistory->GetIndex(&idx); NS_ENSURE_SUCCESS(rv, rv); *aResult = idx + GetGlobalIndexOffset(); return NS_OK; } *aResult = mIndex + GetGlobalIndexOffset(); return NS_OK; } NS_IMETHODIMP PartialSHistory::GetGlobalIndexOffset(uint32_t* aResult) { if (!aResult) { return NS_ERROR_INVALID_POINTER; } // If we have direct reference to nsISHistory, simply pass through. nsCOMPtr shistory(GetSessionHistory()); if (shistory) { int32_t offset; nsresult rv = shistory->GetGlobalIndexOffset(&offset); if (NS_FAILED(rv) || offset < 0) { *aResult = 0; return NS_ERROR_FAILURE; } *aResult = offset; return NS_OK; } // Otherwise use the cached value. *aResult = mGlobalIndexOffset; return NS_OK; } NS_IMETHODIMP PartialSHistory::GetOwnerFrameLoader(nsIFrameLoader** aResult) { nsCOMPtr loader(mOwnerFrameLoader); loader.forget(aResult); return NS_OK; } NS_IMETHODIMP PartialSHistory::OnAttachGroupedSessionHistory(uint32_t aOffset) { mGlobalIndexOffset = aOffset; // If we have direct reference to nsISHistory, simply pass through. nsCOMPtr shistory(GetSessionHistory()); if (shistory) { // nsISHistory uses int32_t if (aOffset > INT32_MAX) { return NS_ERROR_FAILURE; } return shistory->OnAttachGroupedSessionHistory(aOffset); } // Otherwise notify through TabParent. RefPtr tabParent(GetTabParent()); if (!tabParent) { // We have neither shistory nor tabParent? NS_WARNING("Unable to get shitory nor tabParent!"); return NS_ERROR_UNEXPECTED; } Unused << tabParent->SendNotifyAttachGroupedSessionHistory(aOffset); return NS_OK; } NS_IMETHODIMP PartialSHistory::HandleSHistoryUpdate(uint32_t aCount, uint32_t aIndex, bool aTruncate) { // Update our local cache of mCount and mIndex mCount = aCount; mIndex = aIndex; return SHistoryDidUpdate(aTruncate); } nsresult PartialSHistory::SHistoryDidUpdate(bool aTruncate /* = false */) { if (!mOwnerFrameLoader) { // Cycle collected? return NS_ERROR_UNEXPECTED; } nsCOMPtr groupedHistory; mOwnerFrameLoader->GetGroupedSessionHistory(getter_AddRefs(groupedHistory)); if (NS_WARN_IF(!groupedHistory)) { // Maybe we're not the active partial history, but in this case we shouldn't // receive any update from session history object either. return NS_ERROR_FAILURE; } groupedHistory->HandleSHistoryUpdate(this, aTruncate); return NS_OK; } NS_IMETHODIMP PartialSHistory::OnActive(uint32_t aGlobalLength, uint32_t aTargetLocalIndex) { // In-process case. nsCOMPtr shistory(GetSessionHistory()); if (shistory) { // nsISHistory uses int32_t if (aGlobalLength > INT32_MAX || aTargetLocalIndex > INT32_MAX) { return NS_ERROR_FAILURE; } return shistory->OnPartialSessionHistoryActive(aGlobalLength, aTargetLocalIndex); } // Cross-process case. RefPtr tabParent(GetTabParent()); if (!tabParent) { // We have neither shistory nor tabParent? NS_WARNING("Unable to get shitory nor tabParent!"); return NS_ERROR_UNEXPECTED; } Unused << tabParent->SendNotifyPartialSessionHistoryActive(aGlobalLength, aTargetLocalIndex); return NS_OK; } NS_IMETHODIMP PartialSHistory::OnDeactive() { // In-process case. nsCOMPtr shistory(GetSessionHistory()); if (shistory) { if (NS_FAILED(shistory->OnPartialSessionHistoryDeactive())) { return NS_ERROR_FAILURE; } return NS_OK; } // Cross-process case. RefPtr tabParent(GetTabParent()); if (!tabParent) { // We have neither shistory nor tabParent? NS_WARNING("Unable to get shitory nor tabParent!"); return NS_ERROR_UNEXPECTED; } Unused << tabParent->SendNotifyPartialSessionHistoryDeactive(); return NS_OK; } /******************************************************************************* * nsIPartialSHistoryListener ******************************************************************************/ NS_IMETHODIMP PartialSHistory::OnRequestCrossBrowserNavigation(uint32_t aIndex) { if (!mOwnerFrameLoader) { // Cycle collected? return NS_ERROR_UNEXPECTED; } nsCOMPtr promise; return mOwnerFrameLoader->RequestGroupedHistoryNavigation(aIndex, getter_AddRefs(promise)); } /******************************************************************************* * nsISHistoryListener ******************************************************************************/ NS_IMETHODIMP PartialSHistory::OnLengthChanged(int32_t aCount) { return SHistoryDidUpdate(/* aTruncate = */ true); } NS_IMETHODIMP PartialSHistory::OnIndexChanged(int32_t aIndex) { return SHistoryDidUpdate(/* aTruncate = */ false); } NS_IMETHODIMP PartialSHistory::OnHistoryNewEntry(nsIURI *aNewURI, int32_t aOldIndex) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP PartialSHistory::OnHistoryGoBack(nsIURI *aBackURI, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP PartialSHistory::OnHistoryGoForward(nsIURI *aForwardURI, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP PartialSHistory::OnHistoryReload(nsIURI *aReloadURI, uint32_t aReloadFlags, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP PartialSHistory::OnHistoryGotoIndex(int32_t aIndex, nsIURI *aGotoURI, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP PartialSHistory::OnHistoryPurge(int32_t aNumEntries, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP PartialSHistory::OnHistoryReplaceEntry(int32_t aIndex) { return NS_ERROR_NOT_IMPLEMENTED; } } // namespace dom } // namespace mozilla