Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: ios/shared/chrome/browser/tabs/web_state_list.mm

Issue 2697193004: Add opener-opened relationship between WebState in WebStateList. (Closed)
Patch Set: Fix opener relationship when restoring a session. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "ios/shared/chrome/browser/tabs/web_state_list.h" 5 #import "ios/shared/chrome/browser/tabs/web_state_list.h"
6 6
7 #include <utility>
8
7 #include "base/logging.h" 9 #include "base/logging.h"
8 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
9 #import "ios/shared/chrome/browser/tabs/web_state_list_observer.h" 11 #import "ios/shared/chrome/browser/tabs/web_state_list_observer.h"
12 #import "ios/web/public/navigation_manager.h"
10 #import "ios/web/public/web_state/web_state.h" 13 #import "ios/web/public/web_state/web_state.h"
11 14
12 #if !defined(__has_feature) || !__has_feature(objc_arc) 15 #if !defined(__has_feature) || !__has_feature(objc_arc)
13 #error "This file requires ARC support." 16 #error "This file requires ARC support."
14 #endif 17 #endif
15 18
16 // Wrapper around a WebState stored in a WebStateList. May own the WebState 19 // Wrapper around a WebState stored in a WebStateList. May own the WebState
17 // dependending on the WebStateList ownership setting (should always be true 20 // dependending on the WebStateList ownership setting (should always be true
18 // once ownership of Tab is sane, see http://crbug.com/546222 for progress). 21 // once ownership of Tab is sane, see http://crbug.com/546222 for progress).
19 class WebStateList::WebStateWrapper { 22 class WebStateList::WebStateWrapper {
20 public: 23 public:
21 WebStateWrapper(web::WebState* web_state, bool assume_ownership); 24 WebStateWrapper(web::WebState* web_state, bool assume_ownership);
22 ~WebStateWrapper(); 25 ~WebStateWrapper();
23 26
24 web::WebState* web_state() const { return web_state_; } 27 web::WebState* web_state() const { return web_state_; }
25 void set_web_state(web::WebState* web_state) { web_state_ = web_state; } 28 web::WebState* opener() const { return opener_; }
29
30 // Replaces the wrapped WebState (and clear associated state) and returns the
31 // old WebState after forfeiting ownership.
32 web::WebState* ReplaceWebState(web::WebState* web_state);
33
34 // Sets the opener for the wrapped WebState and record the opener navigation
35 // index to allow detecting navigation changes during the same session.
36 void SetOpener(web::WebState* opener);
37
38 // Returns whether |opener| spawned the wrapped WebState. If |use_group| is
39 // true, also use the opener navigation index to detect navigation changes
40 // during the same session.
41 bool WasOpenedBy(const web::WebState* opener,
42 int opener_navigation_index,
43 bool use_group) const;
26 44
27 private: 45 private:
28 web::WebState* web_state_; 46 web::WebState* web_state_;
47 web::WebState* opener_ = nullptr;
48 int opener_last_committed_index_;
29 const bool has_web_state_ownership_; 49 const bool has_web_state_ownership_;
30 50
31 DISALLOW_COPY_AND_ASSIGN(WebStateWrapper); 51 DISALLOW_COPY_AND_ASSIGN(WebStateWrapper);
32 }; 52 };
33 53
34 WebStateList::WebStateWrapper::WebStateWrapper(web::WebState* web_state, 54 WebStateList::WebStateWrapper::WebStateWrapper(web::WebState* web_state,
35 bool assume_ownership) 55 bool assume_ownership)
36 : web_state_(web_state), has_web_state_ownership_(assume_ownership) {} 56 : web_state_(web_state), has_web_state_ownership_(assume_ownership) {
57 DCHECK(web_state_);
58 }
37 59
38 WebStateList::WebStateWrapper::~WebStateWrapper() { 60 WebStateList::WebStateWrapper::~WebStateWrapper() {
39 if (has_web_state_ownership_) 61 if (has_web_state_ownership_)
40 delete web_state_; 62 delete web_state_;
41 } 63 }
42 64
65 web::WebState* WebStateList::WebStateWrapper::ReplaceWebState(
66 web::WebState* web_state) {
67 DCHECK(web_state);
68 DCHECK_NE(web_state, web_state_);
69
70 using std::swap;
rohitrao (ping after 24h) 2017/02/22 14:57:53 Why using? Could you just call std::swap(web_stat
sdefresne 2017/02/22 18:23:47 This is an habit that I grew that allows to force
71 swap(web_state, web_state_);
72 opener_ = nullptr;
73 return web_state;
74 }
75
76 void WebStateList::WebStateWrapper::SetOpener(web::WebState* opener) {
77 opener_ = opener;
78 if (opener_) {
79 opener_last_committed_index_ =
80 opener_->GetNavigationManager()->GetLastCommittedItemIndex();
81 }
82 }
83
84 bool WebStateList::WebStateWrapper::WasOpenedBy(const web::WebState* opener,
85 int opener_navigation_index,
86 bool use_group) const {
87 DCHECK(opener);
88 if (opener_ != opener)
89 return false;
90
91 if (!use_group)
92 return true;
93
94 return opener_last_committed_index_ == opener_navigation_index;
95 }
96
43 WebStateList::WebStateList(WebStateOwnership ownership) 97 WebStateList::WebStateList(WebStateOwnership ownership)
44 : web_state_ownership_(ownership) {} 98 : web_state_ownership_(ownership) {}
45 99
46 WebStateList::~WebStateList() = default; 100 WebStateList::~WebStateList() = default;
47 101
48 bool WebStateList::ContainsIndex(int index) const { 102 bool WebStateList::ContainsIndex(int index) const {
49 return 0 <= index && index < count(); 103 return 0 <= index && index < count();
50 } 104 }
51 105
52 web::WebState* WebStateList::GetWebStateAt(int index) const { 106 web::WebState* WebStateList::GetWebStateAt(int index) const {
53 DCHECK(ContainsIndex(index)); 107 DCHECK(ContainsIndex(index));
54 return web_state_wrappers_[index]->web_state(); 108 return web_state_wrappers_[index]->web_state();
55 } 109 }
56 110
57 int WebStateList::GetIndexOfWebState(const web::WebState* web_state) const { 111 int WebStateList::GetIndexOfWebState(const web::WebState* web_state) const {
58 for (int index = 0; index < count(); ++index) { 112 for (int index = 0; index < count(); ++index) {
59 if (web_state_wrappers_[index]->web_state() == web_state) 113 if (web_state_wrappers_[index]->web_state() == web_state)
60 return index; 114 return index;
61 } 115 }
62 return kInvalidIndex; 116 return kInvalidIndex;
63 } 117 }
64 118
65 void WebStateList::InsertWebState(int index, web::WebState* web_state) { 119 web::WebState* WebStateList::GetOpenerOfWebStateAt(int index) const {
120 DCHECK(ContainsIndex(index));
121 return web_state_wrappers_[index]->opener();
122 }
123
124 void WebStateList::SetOpenerOfWebStateAt(int index, web::WebState* opener) {
125 DCHECK(ContainsIndex(index));
126 DCHECK(ContainsIndex(GetIndexOfWebState(opener)));
127 web_state_wrappers_[index]->SetOpener(opener);
128 }
129
130 int WebStateList::GetIndexOfNextWebStateOpenedBy(const web::WebState* opener,
131 int start_index,
132 bool use_group) const {
133 return GetIndexOfNthWebStateOpenedBy(opener, start_index, use_group, 1);
134 }
135
136 int WebStateList::GetIndexOfLastWebStateOpenedBy(const web::WebState* opener,
137 int start_index,
138 bool use_group) const {
139 return GetIndexOfNthWebStateOpenedBy(opener, start_index, use_group, INT_MAX);
140 }
141
142 void WebStateList::InsertWebState(int index,
143 web::WebState* web_state,
144 web::WebState* opener) {
66 DCHECK(ContainsIndex(index) || index == count()); 145 DCHECK(ContainsIndex(index) || index == count());
67 web_state_wrappers_.insert( 146 web_state_wrappers_.insert(
68 web_state_wrappers_.begin() + index, 147 web_state_wrappers_.begin() + index,
69 base::MakeUnique<WebStateWrapper>(web_state, 148 base::MakeUnique<WebStateWrapper>(web_state,
70 web_state_ownership_ == WebStateOwned)); 149 web_state_ownership_ == WebStateOwned));
71 150
151 if (opener)
152 SetOpenerOfWebStateAt(index, opener);
153
72 for (auto& observer : observers_) 154 for (auto& observer : observers_)
73 observer.WebStateInsertedAt(this, web_state, index); 155 observer.WebStateInsertedAt(this, web_state, index);
74 } 156 }
75 157
76 void WebStateList::MoveWebStateAt(int from_index, int to_index) { 158 void WebStateList::MoveWebStateAt(int from_index, int to_index) {
77 DCHECK(ContainsIndex(from_index)); 159 DCHECK(ContainsIndex(from_index));
78 DCHECK(ContainsIndex(to_index)); 160 DCHECK(ContainsIndex(to_index));
79 if (from_index == to_index) 161 if (from_index == to_index)
80 return; 162 return;
81 163
82 std::unique_ptr<WebStateWrapper> web_state_wrapper = 164 std::unique_ptr<WebStateWrapper> web_state_wrapper =
83 std::move(web_state_wrappers_[from_index]); 165 std::move(web_state_wrappers_[from_index]);
84 web::WebState* web_state = web_state_wrapper->web_state(); 166 web::WebState* web_state = web_state_wrapper->web_state();
85 web_state_wrappers_.erase(web_state_wrappers_.begin() + from_index); 167 web_state_wrappers_.erase(web_state_wrappers_.begin() + from_index);
86 web_state_wrappers_.insert(web_state_wrappers_.begin() + to_index, 168 web_state_wrappers_.insert(web_state_wrappers_.begin() + to_index,
87 std::move(web_state_wrapper)); 169 std::move(web_state_wrapper));
88 170
89 for (auto& observer : observers_) 171 for (auto& observer : observers_)
90 observer.WebStateMoved(this, web_state, from_index, to_index); 172 observer.WebStateMoved(this, web_state, from_index, to_index);
91 } 173 }
92 174
93 web::WebState* WebStateList::ReplaceWebStateAt(int index, 175 web::WebState* WebStateList::ReplaceWebStateAt(int index,
94 web::WebState* web_state) { 176 web::WebState* web_state,
177 web::WebState* opener) {
95 DCHECK(ContainsIndex(index)); 178 DCHECK(ContainsIndex(index));
96 web::WebState* old_web_state = web_state_wrappers_[index]->web_state(); 179 FixOpenersReferencing(index);
97 web_state_wrappers_[index]->set_web_state(web_state); 180
181 auto& web_state_wrapper = web_state_wrappers_[index];
182 web::WebState* old_web_state = web_state_wrapper->ReplaceWebState(web_state);
183
184 if (opener && opener != old_web_state)
185 SetOpenerOfWebStateAt(index, opener);
98 186
99 for (auto& observer : observers_) 187 for (auto& observer : observers_)
100 observer.WebStateReplacedAt(this, old_web_state, web_state, index); 188 observer.WebStateReplacedAt(this, old_web_state, web_state, index);
101 189
102 return old_web_state; 190 return old_web_state;
103 } 191 }
104 192
105 void WebStateList::DetachWebStateAt(int index) { 193 void WebStateList::DetachWebStateAt(int index) {
106 DCHECK(ContainsIndex(index)); 194 DCHECK(ContainsIndex(index));
195 FixOpenersReferencing(index);
196
107 web::WebState* web_state = web_state_wrappers_[index]->web_state(); 197 web::WebState* web_state = web_state_wrappers_[index]->web_state();
108 web_state_wrappers_.erase(web_state_wrappers_.begin() + index); 198 web_state_wrappers_.erase(web_state_wrappers_.begin() + index);
109 199
110 for (auto& observer : observers_) 200 for (auto& observer : observers_)
111 observer.WebStateDetachedAt(this, web_state, index); 201 observer.WebStateDetachedAt(this, web_state, index);
112 } 202 }
113 203
114 void WebStateList::AddObserver(WebStateListObserver* observer) { 204 void WebStateList::AddObserver(WebStateListObserver* observer) {
115 observers_.AddObserver(observer); 205 observers_.AddObserver(observer);
116 } 206 }
117 207
118 void WebStateList::RemoveObserver(WebStateListObserver* observer) { 208 void WebStateList::RemoveObserver(WebStateListObserver* observer) {
119 observers_.RemoveObserver(observer); 209 observers_.RemoveObserver(observer);
120 } 210 }
121 211
212 void WebStateList::FixOpenersReferencing(int index) {
rohitrao (ping after 24h) 2017/02/22 14:57:52 Is this really ClearOpenersReferencing()?
sdefresne 2017/02/22 18:23:47 Yes. I've named it this following TabStripModel (b
213 web::WebState* old_web_state = web_state_wrappers_[index]->web_state();
214 for (auto& web_state_wrapper : web_state_wrappers_) {
215 if (web_state_wrapper->opener() == old_web_state)
216 web_state_wrapper->SetOpener(nullptr);
217 }
218 }
219
220 int WebStateList::GetIndexOfNthWebStateOpenedBy(const web::WebState* opener,
221 int start_index,
222 bool use_group,
223 int n) const {
224 DCHECK_GT(n, 0);
225 if (!opener || !ContainsIndex(start_index) || start_index == INT_MAX)
226 return kInvalidIndex;
227
228 const int opener_navigation_index =
229 use_group ? opener->GetNavigationManager()->GetCurrentItemIndex() : -1;
230
231 int found_index = kInvalidIndex;
232 for (int index = start_index + 1; index < count() && n; ++index) {
233 if (web_state_wrappers_[index]->WasOpenedBy(opener, opener_navigation_index,
234 use_group)) {
235 found_index = index;
236 --n;
237 } else if (found_index != kInvalidIndex) {
238 return found_index;
239 }
240 }
241
242 return found_index;
243 }
244
122 // static 245 // static
123 const int WebStateList::kInvalidIndex; 246 const int WebStateList::kInvalidIndex;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698