Index: ios/shared/chrome/browser/tabs/web_state_list.mm |
diff --git a/ios/shared/chrome/browser/tabs/web_state_list.mm b/ios/shared/chrome/browser/tabs/web_state_list.mm |
index cb85ed433ee72233257fc0c3181adf4e9dfaca74..09d4539a504cac82030c843e29af024f475a295c 100644 |
--- a/ios/shared/chrome/browser/tabs/web_state_list.mm |
+++ b/ios/shared/chrome/browser/tabs/web_state_list.mm |
@@ -7,6 +7,7 @@ |
#include "base/logging.h" |
#include "base/memory/ptr_util.h" |
#import "ios/shared/chrome/browser/tabs/web_state_list_observer.h" |
+#import "ios/web/public/navigation_manager.h" |
#import "ios/web/public/web_state/web_state.h" |
#if !defined(__has_feature) || !__has_feature(objc_arc) |
@@ -22,10 +23,26 @@ class WebStateList::WebStateWrapper { |
~WebStateWrapper(); |
web::WebState* web_state() const { return web_state_; } |
- void set_web_state(web::WebState* web_state) { web_state_ = web_state; } |
+ web::WebState* opener() const { return opener_; } |
+ |
+ // Resets the wrapped WebState (and clear associated state). |
+ void SetWebState(web::WebState* web_state); |
+ |
+ // Sets the opener for the wrapped WebState and record the opener navigation |
+ // index to allow detecting navigation changes during the same session. |
+ void SetOpener(web::WebState* opener); |
+ |
+ // Returns whether opener spawned the wrapped WebState. If |use_group| is |
marq (ping after 24h)
2017/02/16 15:19:17
|opener|
sdefresne
2017/02/16 15:42:01
Done.
|
+ // true, also use the opener navigation index to detect navigation changes |
+ // during the same session. |
+ bool WasOpenBy(const web::WebState* opener, |
marq (ping after 24h)
2017/02/16 15:19:17
WasOpenedBy(). yay, English!
sdefresne
2017/02/16 15:42:01
Done.
|
+ int opener_navigation_index, |
+ bool use_group) const; |
private: |
web::WebState* web_state_; |
+ web::WebState* opener_ = nullptr; |
+ int opener_last_committed_index_; |
const bool has_web_state_ownership_; |
DISALLOW_COPY_AND_ASSIGN(WebStateWrapper); |
@@ -33,13 +50,42 @@ class WebStateList::WebStateWrapper { |
WebStateList::WebStateWrapper::WebStateWrapper(web::WebState* web_state, |
bool assume_ownership) |
- : web_state_(web_state), has_web_state_ownership_(assume_ownership) {} |
+ : web_state_(web_state), has_web_state_ownership_(assume_ownership) { |
+ DCHECK(web_state_); |
+} |
WebStateList::WebStateWrapper::~WebStateWrapper() { |
if (has_web_state_ownership_) |
delete web_state_; |
} |
+void WebStateList::WebStateWrapper::SetWebState(web::WebState* web_state) { |
+ DCHECK(web_state); |
+ web_state_ = web_state; |
+ opener_ = nullptr; |
+} |
+ |
+void WebStateList::WebStateWrapper::SetOpener(web::WebState* opener) { |
+ opener_ = opener; |
+ if (opener_) { |
+ opener_last_committed_index_ = |
+ opener_->GetNavigationManager()->GetLastCommittedItemIndex(); |
+ } |
+} |
+ |
+bool WebStateList::WebStateWrapper::WasOpenBy(const web::WebState* opener, |
+ int opener_navigation_index, |
+ bool use_group) const { |
+ DCHECK(opener); |
+ if (opener_ != opener) |
+ return false; |
+ |
+ if (!use_group) |
+ return true; |
+ |
+ return opener_last_committed_index_ == opener_navigation_index; |
+} |
+ |
WebStateList::WebStateList(WebStateOwnership ownership) |
: web_state_ownership_(ownership) {} |
@@ -62,13 +108,35 @@ int WebStateList::GetIndexOfWebState(const web::WebState* web_state) const { |
return kInvalidIndex; |
} |
-void WebStateList::InsertWebState(int index, web::WebState* web_state) { |
+web::WebState* WebStateList::GetOpenerOfWebStateAt(int index) const { |
+ DCHECK(ContainsIndex(index)); |
+ return web_state_wrappers_[index]->opener(); |
+} |
+ |
+int WebStateList::GetIndexOfNextWebStateOpenedBy(const web::WebState* opener, |
+ int start_index, |
+ bool use_group) const { |
+ return GetIndexOfNthWebStateOpenedBy(opener, start_index, 1, use_group); |
+} |
+ |
+int WebStateList::GetIndexOfLastWebStateOpenedBy(const web::WebState* opener, |
+ int start_index, |
+ bool use_group) const { |
+ return GetIndexOfNthWebStateOpenedBy(opener, start_index, INT_MAX, use_group); |
+} |
+ |
+void WebStateList::InsertWebState(int index, |
+ web::WebState* web_state, |
+ web::WebState* opener) { |
DCHECK(ContainsIndex(index) || index == count()); |
web_state_wrappers_.insert( |
web_state_wrappers_.begin() + index, |
base::MakeUnique<WebStateWrapper>(web_state, |
web_state_ownership_ == WebStateOwned)); |
+ if (opener) |
+ SetOpenerOfWebStateAt(index, opener); |
+ |
for (auto& observer : observers_) |
observer.WebStateInsertedAt(this, web_state, index); |
} |
@@ -91,10 +159,17 @@ void WebStateList::MoveWebStateAt(int from_index, int to_index) { |
} |
web::WebState* WebStateList::ReplaceWebStateAt(int index, |
- web::WebState* web_state) { |
+ web::WebState* web_state, |
+ web::WebState* opener) { |
DCHECK(ContainsIndex(index)); |
- web::WebState* old_web_state = web_state_wrappers_[index]->web_state(); |
- web_state_wrappers_[index]->set_web_state(web_state); |
+ FixOpenersReferencing(index); |
+ |
+ auto& web_state_wrapper = web_state_wrappers_[index]; |
+ web::WebState* old_web_state = web_state_wrapper->web_state(); |
+ web_state_wrapper->SetWebState(web_state); |
+ |
+ if (opener && opener != old_web_state) |
+ SetOpenerOfWebStateAt(index, opener); |
for (auto& observer : observers_) |
observer.WebStateReplacedAt(this, old_web_state, web_state, index); |
@@ -104,6 +179,8 @@ web::WebState* WebStateList::ReplaceWebStateAt(int index, |
void WebStateList::DetachWebStateAt(int index) { |
DCHECK(ContainsIndex(index)); |
+ FixOpenersReferencing(index); |
+ |
web::WebState* web_state = web_state_wrappers_[index]->web_state(); |
web_state_wrappers_.erase(web_state_wrappers_.begin() + index); |
@@ -119,5 +196,44 @@ void WebStateList::RemoveObserver(WebStateListObserver* observer) { |
observers_.RemoveObserver(observer); |
} |
+void WebStateList::SetOpenerOfWebStateAt(int index, web::WebState* opener) { |
+ DCHECK(ContainsIndex(index)); |
+ DCHECK(ContainsIndex(GetIndexOfWebState(opener))); |
+ web_state_wrappers_[index]->SetOpener(opener); |
+} |
+ |
+void WebStateList::FixOpenersReferencing(int index) { |
+ web::WebState* old_web_state = web_state_wrappers_[index]->web_state(); |
+ for (auto& web_state_wrapper : web_state_wrappers_) { |
+ if (web_state_wrapper->opener() == old_web_state) |
+ web_state_wrapper->SetOpener(nullptr); |
+ } |
+} |
+ |
+int WebStateList::GetIndexOfNthWebStateOpenedBy(const web::WebState* opener, |
+ int start_index, |
+ int skip_up_to, |
+ bool use_group) const { |
+ DCHECK_GT(skip_up_to, 0); |
marq (ping after 24h)
2017/02/16 15:19:17
Document this precondition in the header comments.
sdefresne
2017/02/16 15:42:01
Done.
|
+ if (!opener || !ContainsIndex(start_index) || start_index == INT_MAX) |
+ return kInvalidIndex; |
+ |
+ const int opener_navigation_index = |
+ use_group ? opener->GetNavigationManager()->GetCurrentItemIndex() : -1; |
+ |
+ int found_index = kInvalidIndex; |
+ for (int index = start_index + 1; index < count() && skip_up_to; ++index) { |
+ if (web_state_wrappers_[index]->WasOpenBy(opener, opener_navigation_index, |
+ use_group)) { |
+ found_index = index; |
+ --skip_up_to; |
+ } else if (found_index != kInvalidIndex) { |
+ return found_index; |
+ } |
+ } |
+ |
+ return found_index; |
+} |
+ |
// static |
const int WebStateList::kInvalidIndex; |