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

Side by Side Diff: components/html_viewer/html_frame_tree_manager.cc

Issue 1677293002: Bye bye Mandoline (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: moar Created 4 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
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/html_viewer/html_frame_tree_manager.h"
6
7 #include <stddef.h>
8 #include <algorithm>
9 #include <utility>
10
11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "base/macros.h"
14 #include "components/html_viewer/blink_basic_type_converters.h"
15 #include "components/html_viewer/blink_url_request_type_converters.h"
16 #include "components/html_viewer/document_resource_waiter.h"
17 #include "components/html_viewer/global_state.h"
18 #include "components/html_viewer/html_factory.h"
19 #include "components/html_viewer/html_frame.h"
20 #include "components/html_viewer/html_frame_delegate.h"
21 #include "components/html_viewer/html_frame_tree_manager_observer.h"
22 #include "components/mus/public/cpp/window_tree_connection.h"
23 #include "components/web_view/web_view_switches.h"
24 #include "third_party/WebKit/public/web/WebLocalFrame.h"
25 #include "third_party/WebKit/public/web/WebRemoteFrame.h"
26 #include "third_party/WebKit/public/web/WebTreeScopeType.h"
27 #include "third_party/WebKit/public/web/WebView.h"
28 #include "ui/gfx/geometry/dip_util.h"
29 #include "ui/gfx/geometry/size.h"
30
31 namespace html_viewer {
32 namespace {
33
34 // Returns the index of the FrameData with the id of |frame_id| in |index|. On
35 // success returns true, otherwise false.
36 bool FindFrameDataIndex(
37 const mojo::Array<web_view::mojom::FrameDataPtr>& frame_data,
38 uint32_t frame_id,
39 size_t* index) {
40 for (size_t i = 0; i < frame_data.size(); ++i) {
41 if (frame_data[i]->frame_id == frame_id) {
42 *index = i;
43 return true;
44 }
45 }
46 return false;
47 }
48
49 } // namespace
50
51 // Object that calls OnHTMLFrameTreeManagerChangeIdAdvanced() from the
52 // destructor.
53 class HTMLFrameTreeManager::ChangeIdAdvancedNotifier {
54 public:
55 explicit ChangeIdAdvancedNotifier(
56 base::ObserverList<HTMLFrameTreeManagerObserver>* observers)
57 : observers_(observers) {}
58 ~ChangeIdAdvancedNotifier() {
59 FOR_EACH_OBSERVER(HTMLFrameTreeManagerObserver, *observers_,
60 OnHTMLFrameTreeManagerChangeIdAdvanced());
61 }
62
63 private:
64 base::ObserverList<HTMLFrameTreeManagerObserver>* observers_;
65
66 DISALLOW_COPY_AND_ASSIGN(ChangeIdAdvancedNotifier);
67 };
68
69 // static
70 HTMLFrameTreeManager::TreeMap* HTMLFrameTreeManager::instances_ = nullptr;
71
72 // static
73 HTMLFrame* HTMLFrameTreeManager::CreateFrameAndAttachToTree(
74 GlobalState* global_state,
75 mus::Window* window,
76 scoped_ptr<DocumentResourceWaiter> resource_waiter,
77 HTMLFrameDelegate* delegate) {
78 if (!instances_)
79 instances_ = new TreeMap;
80
81 mojo::InterfaceRequest<web_view::mojom::FrameClient> frame_client_request;
82 web_view::mojom::FramePtr server_frame;
83 mojo::Array<web_view::mojom::FrameDataPtr> frame_data;
84 uint32_t change_id;
85 uint32_t window_id;
86 web_view::mojom::WindowConnectType window_connect_type;
87 web_view::mojom::FrameClient::OnConnectCallback on_connect_callback;
88 resource_waiter->Release(&frame_client_request, &server_frame, &frame_data,
89 &change_id, &window_id, &window_connect_type,
90 &on_connect_callback);
91 resource_waiter.reset();
92
93 on_connect_callback.Run();
94
95 HTMLFrameTreeManager* frame_tree =
96 FindFrameTreeWithRoot(frame_data[0]->frame_id);
97
98 DCHECK(!frame_tree || change_id <= frame_tree->change_id_);
99
100 DVLOG(2) << "HTMLFrameTreeManager::CreateFrameAndAttachToTree "
101 << " frame_tree=" << frame_tree << " use_existing="
102 << (window_connect_type ==
103 web_view::mojom::WindowConnectType::USE_EXISTING)
104 << " frame_id=" << window_id;
105 if (window_connect_type == web_view::mojom::WindowConnectType::USE_EXISTING &&
106 !frame_tree) {
107 DVLOG(1) << "was told to use existing window but do not have frame tree";
108 return nullptr;
109 }
110
111 if (!frame_tree) {
112 frame_tree = new HTMLFrameTreeManager(global_state);
113 frame_tree->Init(delegate, window, frame_data, change_id);
114 (*instances_)[frame_data[0]->frame_id] = frame_tree;
115 } else if (window_connect_type ==
116 web_view::mojom::WindowConnectType::USE_EXISTING) {
117 HTMLFrame* existing_frame = frame_tree->root_->FindFrame(window_id);
118 if (!existing_frame) {
119 DVLOG(1) << "was told to use existing window but could not find window";
120 return nullptr;
121 }
122 if (!existing_frame->IsLocal()) {
123 DVLOG(1) << "was told to use existing window, but frame is remote";
124 return nullptr;
125 }
126 existing_frame->SwapDelegate(delegate);
127 } else {
128 // We're going to share a frame tree. We should know about the frame.
129 CHECK(window->id() != frame_data[0]->frame_id);
130 HTMLFrame* existing_frame = frame_tree->root_->FindFrame(window->id());
131 if (existing_frame) {
132 CHECK(!existing_frame->IsLocal());
133 size_t frame_data_index = 0u;
134 CHECK(FindFrameDataIndex(frame_data, window->id(), &frame_data_index));
135 const web_view::mojom::FrameDataPtr& data = frame_data[frame_data_index];
136 existing_frame->SwapToLocal(delegate, window, data->client_properties);
137 } else {
138 // If we can't find the frame and the change_id of the incoming
139 // tree is before the change id we've processed, then we removed the
140 // frame and need do nothing.
141 if (change_id < frame_tree->change_id_)
142 return nullptr;
143
144 // We removed the frame but it hasn't been acked yet.
145 if (frame_tree->pending_remove_ids_.count(window->id()))
146 return nullptr;
147
148 // We don't know about the frame, but should. Something is wrong.
149 DVLOG(1) << "unable to locate frame to attach to";
150 return nullptr;
151 }
152 }
153
154 HTMLFrame* frame = frame_tree->root_->FindFrame(window_id);
155 DCHECK(frame);
156 frame->Bind(std::move(server_frame), std::move(frame_client_request));
157 return frame;
158 }
159
160 // static
161 HTMLFrameTreeManager* HTMLFrameTreeManager::FindFrameTreeWithRoot(
162 uint32_t root_frame_id) {
163 return (!base::CommandLine::ForCurrentProcess()->HasSwitch(
164 web_view::switches::kOOPIFAlwaysCreateNewFrameTree) &&
165 instances_ && instances_->count(root_frame_id))
166 ? (*instances_)[root_frame_id]
167 : nullptr;
168 }
169
170 blink::WebView* HTMLFrameTreeManager::GetWebView() {
171 return root_->web_view();
172 }
173
174 void HTMLFrameTreeManager::AddObserver(HTMLFrameTreeManagerObserver* observer) {
175 observers_.AddObserver(observer);
176 }
177
178 void HTMLFrameTreeManager::RemoveObserver(
179 HTMLFrameTreeManagerObserver* observer) {
180 observers_.RemoveObserver(observer);
181 }
182
183 void HTMLFrameTreeManager::OnFrameDestroyed(HTMLFrame* frame) {
184 if (!in_process_on_frame_removed_)
185 pending_remove_ids_.insert(frame->id());
186
187 if (frame == root_) {
188 // If |root_| is removed before |local_frame_|, we don't have a way to
189 // select a new local frame when |local_frame_| is removed. On the other
190 // hand, it is impossible to remove |root_| after all local frames are gone,
191 // because by that time this object has already been deleted.
192 CHECK_EQ(root_, local_frame_);
193 root_ = nullptr;
194 }
195
196 if (frame != local_frame_)
197 return;
198
199 // |local_frame_| is being removed. We need to find out whether we have local
200 // frames that are not descendants of |local_frame_|, and if yes select a new
201 // |local_frame_|.
202 local_frame_ = FindNewLocalFrame();
203 if (!local_frame_)
204 delete this;
205 }
206
207 HTMLFrameTreeManager::HTMLFrameTreeManager(GlobalState* global_state)
208 : global_state_(global_state),
209 root_(nullptr),
210 local_frame_(nullptr),
211 change_id_(0u),
212 in_process_on_frame_removed_(false),
213 weak_factory_(this) {}
214
215 HTMLFrameTreeManager::~HTMLFrameTreeManager() {
216 DCHECK(!local_frame_);
217 RemoveFromInstances();
218
219 FOR_EACH_OBSERVER(HTMLFrameTreeManagerObserver, observers_,
220 OnHTMLFrameTreeManagerDestroyed());
221 }
222
223 void HTMLFrameTreeManager::Init(
224 HTMLFrameDelegate* delegate,
225 mus::Window* local_window,
226 const mojo::Array<web_view::mojom::FrameDataPtr>& frame_data,
227 uint32_t change_id) {
228 change_id_ = change_id;
229 root_ =
230 BuildFrameTree(delegate, frame_data, local_window->id(), local_window);
231 local_frame_ = root_->FindFrame(local_window->id());
232 CHECK(local_frame_);
233 local_frame_->UpdateFocus();
234 }
235
236 HTMLFrame* HTMLFrameTreeManager::BuildFrameTree(
237 HTMLFrameDelegate* delegate,
238 const mojo::Array<web_view::mojom::FrameDataPtr>& frame_data,
239 uint32_t local_frame_id,
240 mus::Window* local_window) {
241 std::vector<HTMLFrame*> parents;
242 HTMLFrame* root = nullptr;
243 HTMLFrame* last_frame = nullptr;
244 for (size_t i = 0; i < frame_data.size(); ++i) {
245 if (last_frame && frame_data[i]->parent_id == last_frame->id()) {
246 parents.push_back(last_frame);
247 } else if (!parents.empty()) {
248 while (parents.back()->id() != frame_data[i]->parent_id)
249 parents.pop_back();
250 }
251 HTMLFrame::CreateParams params(this,
252 !parents.empty() ? parents.back() : nullptr,
253 frame_data[i]->frame_id, local_window,
254 frame_data[i]->client_properties, nullptr);
255 if (frame_data[i]->frame_id == local_frame_id)
256 params.delegate = delegate;
257
258 HTMLFrame* frame = delegate->GetHTMLFactory()->CreateHTMLFrame(&params);
259 if (!last_frame)
260 root = frame;
261 else
262 DCHECK(frame->parent());
263 last_frame = frame;
264 }
265 return root;
266 }
267
268 void HTMLFrameTreeManager::RemoveFromInstances() {
269 for (auto pair : *instances_) {
270 if (pair.second == this) {
271 instances_->erase(pair.first);
272 return;
273 }
274 }
275 }
276
277 bool HTMLFrameTreeManager::PrepareForStructureChange(HTMLFrame* source,
278 uint32_t change_id) {
279 // The change ids may differ if multiple HTMLDocuments are attached to the
280 // same tree (which means we have multiple FrameClient for the same tree).
281 if (change_id != (change_id_ + 1))
282 return false;
283
284 // We only process changes for the topmost local root.
285 if (source != local_frame_)
286 return false;
287
288 // Update the id as the change is going to be applied (or we can assume it
289 // will be applied if we get here).
290 change_id_ = change_id;
291 return true;
292 }
293
294 void HTMLFrameTreeManager::ProcessOnFrameAdded(
295 HTMLFrame* source,
296 uint32_t change_id,
297 web_view::mojom::FrameDataPtr frame_data) {
298 if (!PrepareForStructureChange(source, change_id))
299 return;
300
301 ChangeIdAdvancedNotifier notifier(&observers_);
302
303 HTMLFrame* parent = root_->FindFrame(frame_data->parent_id);
304 if (!parent) {
305 DVLOG(1) << "Received invalid parent in OnFrameAdded "
306 << frame_data->parent_id;
307 return;
308 }
309 if (root_->FindFrame(frame_data->frame_id)) {
310 DVLOG(1) << "Child with id already exists in OnFrameAdded "
311 << frame_data->frame_id;
312 return;
313 }
314
315 // Because notification is async it's entirely possible for us to create a
316 // new frame, and remove it before we get the add from the server. This check
317 // ensures we don't add back a frame we explicitly removed.
318 if (pending_remove_ids_.count(frame_data->frame_id))
319 return;
320
321 DVLOG(2) << "OnFrameAdded this=" << this
322 << " frame_id=" << frame_data->frame_id;
323
324 HTMLFrame::CreateParams params(this, parent, frame_data->frame_id, nullptr,
325 frame_data->client_properties, nullptr);
326 // |parent| takes ownership of created HTMLFrame.
327 source->GetFirstAncestorWithDelegate()
328 ->delegate_->GetHTMLFactory()
329 ->CreateHTMLFrame(&params);
330 }
331
332 void HTMLFrameTreeManager::ProcessOnFrameRemoved(HTMLFrame* source,
333 uint32_t change_id,
334 uint32_t frame_id) {
335 if (!PrepareForStructureChange(source, change_id))
336 return;
337
338 ChangeIdAdvancedNotifier notifier(&observers_);
339
340 pending_remove_ids_.erase(frame_id);
341
342 HTMLFrame* frame = root_->FindFrame(frame_id);
343 if (!frame) {
344 DVLOG(1) << "OnFrameRemoved with unknown frame " << frame_id;
345 return;
346 }
347
348 // We shouldn't see requests to remove the root.
349 if (frame == root_) {
350 DVLOG(1) << "OnFrameRemoved supplied root; ignoring";
351 return;
352 }
353
354 // Requests to remove local frames are followed by the Window being destroyed.
355 // We handle destruction there.
356 if (frame->IsLocal())
357 return;
358
359 DVLOG(2) << "OnFrameRemoved this=" << this << " frame_id=" << frame_id;
360
361 DCHECK(!in_process_on_frame_removed_);
362 in_process_on_frame_removed_ = true;
363 base::WeakPtr<HTMLFrameTreeManager> ref(weak_factory_.GetWeakPtr());
364 frame->Close();
365 if (!ref)
366 return; // We were deleted.
367
368 in_process_on_frame_removed_ = false;
369 }
370
371 void HTMLFrameTreeManager::ProcessOnFrameClientPropertyChanged(
372 HTMLFrame* source,
373 uint32_t frame_id,
374 const mojo::String& name,
375 mojo::Array<uint8_t> new_data) {
376 if (source != local_frame_)
377 return;
378
379 HTMLFrame* frame = root_->FindFrame(frame_id);
380 if (frame)
381 frame->SetValueFromClientProperty(name, std::move(new_data));
382 }
383
384 HTMLFrame* HTMLFrameTreeManager::FindNewLocalFrame() {
385 HTMLFrame* new_local_frame = nullptr;
386
387 if (root_) {
388 std::queue<HTMLFrame*> nodes;
389 nodes.push(root_);
390
391 while (!nodes.empty()) {
392 HTMLFrame* node = nodes.front();
393 nodes.pop();
394
395 if (node == local_frame_)
396 continue;
397
398 if (node->IsLocal()) {
399 new_local_frame = node;
400 break;
401 }
402
403 for (const auto& child : node->children())
404 nodes.push(child);
405 }
406 }
407
408 return new_local_frame;
409 }
410
411 } // namespace mojo
OLDNEW
« no previous file with comments | « components/html_viewer/html_frame_tree_manager.h ('k') | components/html_viewer/html_frame_tree_manager_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698