Use common code to set HttpNetworkSession::Param pointers.
[chromium-blink-merge.git] / components / html_viewer / html_frame_tree_manager.cc
blob9de240fb6972b271c2eff8419e64b3ae876161ca
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.
5 #include "components/html_viewer/html_frame_tree_manager.h"
7 #include <algorithm>
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "components/html_viewer/blink_basic_type_converters.h"
12 #include "components/html_viewer/blink_url_request_type_converters.h"
13 #include "components/html_viewer/document_resource_waiter.h"
14 #include "components/html_viewer/global_state.h"
15 #include "components/html_viewer/html_frame.h"
16 #include "components/html_viewer/html_frame_delegate.h"
17 #include "components/html_viewer/html_viewer_switches.h"
18 #include "components/view_manager/public/cpp/view_manager.h"
19 #include "third_party/WebKit/public/web/WebLocalFrame.h"
20 #include "third_party/WebKit/public/web/WebRemoteFrame.h"
21 #include "third_party/WebKit/public/web/WebTreeScopeType.h"
22 #include "third_party/WebKit/public/web/WebView.h"
23 #include "ui/gfx/geometry/dip_util.h"
24 #include "ui/gfx/geometry/size.h"
26 namespace html_viewer {
27 namespace {
29 // Returns the index of the FrameData with the id of |frame_id| in |index|. On
30 // success returns true, otherwise false.
31 bool FindFrameDataIndex(const mojo::Array<mandoline::FrameDataPtr>& frame_data,
32 uint32_t frame_id,
33 size_t* index) {
34 for (size_t i = 0; i < frame_data.size(); ++i) {
35 if (frame_data[i]->frame_id == frame_id) {
36 *index = i;
37 return true;
40 return false;
43 } // namespace
45 // static
46 HTMLFrameTreeManager::TreeMap* HTMLFrameTreeManager::instances_ = nullptr;
48 // static
49 HTMLFrame* HTMLFrameTreeManager::CreateFrameAndAttachToTree(
50 GlobalState* global_state,
51 mojo::View* view,
52 scoped_ptr<DocumentResourceWaiter> resource_waiter,
53 HTMLFrameDelegate* delegate) {
54 if (!instances_)
55 instances_ = new TreeMap;
57 mojo::InterfaceRequest<mandoline::FrameTreeClient> frame_tree_client_request;
58 mandoline::FrameTreeServerPtr frame_tree_server;
59 mojo::Array<mandoline::FrameDataPtr> frame_data;
60 uint32_t change_id;
61 resource_waiter->Release(&frame_tree_client_request, &frame_tree_server,
62 &frame_data, &change_id);
63 resource_waiter.reset();
65 HTMLFrameTreeManager* frame_tree = nullptr;
67 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
68 switches::kOOPIFAlwaysCreateNewFrameTree)) {
69 if (instances_->count(frame_data[0]->frame_id))
70 frame_tree = (*instances_)[frame_data[0]->frame_id];
73 if (!frame_tree) {
74 frame_tree = new HTMLFrameTreeManager(global_state);
75 frame_tree->Init(delegate, view, frame_data, change_id);
76 if (frame_data[0]->frame_id == view->id())
77 (*instances_)[frame_data[0]->frame_id] = frame_tree;
78 } else {
79 // We're going to share a frame tree. There are two possibilities:
80 // . We already know about the frame, in which case we swap it to local.
81 // . We don't know about the frame (most likely because of timing issues),
82 // but we better know about the parent. Create a new frame for it.
83 CHECK(view->id() != frame_data[0]->frame_id);
84 HTMLFrame* existing_frame = frame_tree->root_->FindFrame(view->id());
85 size_t frame_data_index = 0u;
86 CHECK(FindFrameDataIndex(frame_data, view->id(), &frame_data_index));
87 const mandoline::FrameDataPtr& data = frame_data[frame_data_index];
88 if (existing_frame) {
89 CHECK(!existing_frame->IsLocal());
90 existing_frame->SwapToLocal(delegate, view, data->client_properties);
91 } else {
92 HTMLFrame* parent = frame_tree->root_->FindFrame(data->parent_id);
93 CHECK(parent);
94 HTMLFrame::CreateParams params(frame_tree, parent, view->id(), view,
95 data->client_properties, delegate);
96 delegate->CreateHTMLFrame(&params);
100 HTMLFrame* frame = frame_tree->root_->FindFrame(view->id());
101 DCHECK(frame);
102 frame->Bind(frame_tree_server.Pass(), frame_tree_client_request.Pass());
103 return frame;
106 blink::WebView* HTMLFrameTreeManager::GetWebView() {
107 return root_->web_view();
110 void HTMLFrameTreeManager::OnFrameDestroyed(HTMLFrame* frame) {
111 if (frame == root_)
112 root_ = nullptr;
114 if (frame == local_root_)
115 local_root_ = nullptr;
117 if (!in_process_on_frame_removed_)
118 pending_remove_ids_.insert(frame->id());
120 if (!local_root_ || !local_root_->HasLocalDescendant())
121 delete this;
124 HTMLFrameTreeManager::HTMLFrameTreeManager(GlobalState* global_state)
125 : global_state_(global_state),
126 root_(nullptr),
127 local_root_(nullptr),
128 change_id_(0u),
129 in_process_on_frame_removed_(false),
130 weak_factory_(this) {}
132 HTMLFrameTreeManager::~HTMLFrameTreeManager() {
133 DCHECK(!root_ || !local_root_);
134 RemoveFromInstances();
137 void HTMLFrameTreeManager::Init(
138 HTMLFrameDelegate* delegate,
139 mojo::View* local_view,
140 const mojo::Array<mandoline::FrameDataPtr>& frame_data,
141 uint32_t change_id) {
142 change_id_ = change_id;
143 root_ = BuildFrameTree(delegate, frame_data, local_view->id(), local_view);
144 local_root_ = root_->FindFrame(local_view->id());
145 CHECK(local_root_);
146 local_root_->UpdateFocus();
149 HTMLFrame* HTMLFrameTreeManager::BuildFrameTree(
150 HTMLFrameDelegate* delegate,
151 const mojo::Array<mandoline::FrameDataPtr>& frame_data,
152 uint32_t local_frame_id,
153 mojo::View* local_view) {
154 std::vector<HTMLFrame*> parents;
155 HTMLFrame* root = nullptr;
156 HTMLFrame* last_frame = nullptr;
157 for (size_t i = 0; i < frame_data.size(); ++i) {
158 if (last_frame && frame_data[i]->parent_id == last_frame->id()) {
159 parents.push_back(last_frame);
160 } else if (!parents.empty()) {
161 while (parents.back()->id() != frame_data[i]->parent_id)
162 parents.pop_back();
164 HTMLFrame::CreateParams params(this,
165 !parents.empty() ? parents.back() : nullptr,
166 frame_data[i]->frame_id, local_view,
167 frame_data[i]->client_properties, nullptr);
168 if (frame_data[i]->frame_id == local_frame_id)
169 params.delegate = delegate;
171 HTMLFrame* frame = delegate->CreateHTMLFrame(&params);
172 if (!last_frame)
173 root = frame;
174 else
175 DCHECK(frame->parent());
176 last_frame = frame;
178 return root;
181 void HTMLFrameTreeManager::RemoveFromInstances() {
182 for (auto pair : *instances_) {
183 if (pair.second == this) {
184 instances_->erase(pair.first);
185 return;
190 bool HTMLFrameTreeManager::PrepareForStructureChange(HTMLFrame* source,
191 uint32_t change_id) {
192 // The change ids may differ if multiple HTMLDocuments are attached to the
193 // same tree (which means we have multiple FrameTreeClients for the same
194 // tree).
195 if (change_id != (change_id_ + 1))
196 return false;
198 // We only process changes for the topmost local root.
199 if (source != local_root_)
200 return false;
202 // Update the id as the change is going to be applied (or we can assume it
203 // will be applied if we get here).
204 change_id_ = change_id;
205 return true;
208 void HTMLFrameTreeManager::ProcessOnFrameAdded(
209 HTMLFrame* source,
210 uint32_t change_id,
211 mandoline::FrameDataPtr frame_data) {
212 if (!PrepareForStructureChange(source, change_id))
213 return;
215 HTMLFrame* parent = root_->FindFrame(frame_data->parent_id);
216 if (!parent) {
217 DVLOG(1) << "Received invalid parent in OnFrameAdded "
218 << frame_data->parent_id;
219 return;
221 if (root_->FindFrame(frame_data->frame_id)) {
222 DVLOG(1) << "Child with id already exists in OnFrameAdded "
223 << frame_data->frame_id;
224 return;
227 // Because notification is async it's entirely possible for us to create a
228 // new frame, and remove it before we get the add from the server. This check
229 // ensures we don't add back a frame we explicitly removed.
230 if (pending_remove_ids_.count(frame_data->frame_id))
231 return;
233 HTMLFrame::CreateParams params(this, parent, frame_data->frame_id, nullptr,
234 frame_data->client_properties, nullptr);
235 // |parent| takes ownership of created HTMLFrame.
236 source->GetLocalRoot()->delegate_->CreateHTMLFrame(&params);
239 void HTMLFrameTreeManager::ProcessOnFrameRemoved(HTMLFrame* source,
240 uint32_t change_id,
241 uint32_t frame_id) {
242 if (!PrepareForStructureChange(source, change_id))
243 return;
245 pending_remove_ids_.erase(frame_id);
247 HTMLFrame* frame = root_->FindFrame(frame_id);
248 if (!frame) {
249 DVLOG(1) << "OnFrameRemoved with unknown frame " << frame_id;
250 return;
253 // We shouldn't see requests to remove the root.
254 if (frame == root_) {
255 DVLOG(1) << "OnFrameRemoved supplied root; ignoring";
256 return;
259 // Requests to remove local frames are followed by the View being destroyed.
260 // We handle destruction there.
261 if (frame->IsLocal())
262 return;
264 DCHECK(!in_process_on_frame_removed_);
265 in_process_on_frame_removed_ = true;
266 base::WeakPtr<HTMLFrameTreeManager> ref(weak_factory_.GetWeakPtr());
267 frame->Close();
268 if (!ref)
269 return; // We were deleted.
271 in_process_on_frame_removed_ = false;
274 void HTMLFrameTreeManager::ProcessOnFrameClientPropertyChanged(
275 HTMLFrame* source,
276 uint32_t frame_id,
277 const mojo::String& name,
278 mojo::Array<uint8_t> new_data) {
279 if (source != local_root_)
280 return;
282 HTMLFrame* frame = root_->FindFrame(frame_id);
283 if (frame)
284 frame->SetValueFromClientProperty(name, new_data.Pass());
287 } // namespace mojo