Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / components / html_viewer / html_frame_tree_manager.cc
blob93bbfcb3a15148263980112058994d8f1f39529d
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_factory.h"
16 #include "components/html_viewer/html_frame.h"
17 #include "components/html_viewer/html_frame_delegate.h"
18 #include "components/html_viewer/html_viewer_switches.h"
19 #include "components/view_manager/public/cpp/view_tree_connection.h"
20 #include "third_party/WebKit/public/web/WebLocalFrame.h"
21 #include "third_party/WebKit/public/web/WebRemoteFrame.h"
22 #include "third_party/WebKit/public/web/WebTreeScopeType.h"
23 #include "third_party/WebKit/public/web/WebView.h"
24 #include "ui/gfx/geometry/dip_util.h"
25 #include "ui/gfx/geometry/size.h"
27 namespace html_viewer {
28 namespace {
30 // Returns the index of the FrameData with the id of |frame_id| in |index|. On
31 // success returns true, otherwise false.
32 bool FindFrameDataIndex(const mojo::Array<mandoline::FrameDataPtr>& frame_data,
33 uint32_t frame_id,
34 size_t* index) {
35 for (size_t i = 0; i < frame_data.size(); ++i) {
36 if (frame_data[i]->frame_id == frame_id) {
37 *index = i;
38 return true;
41 return false;
44 } // namespace
46 // static
47 HTMLFrameTreeManager::TreeMap* HTMLFrameTreeManager::instances_ = nullptr;
49 // static
50 HTMLFrame* HTMLFrameTreeManager::CreateFrameAndAttachToTree(
51 GlobalState* global_state,
52 mojo::View* view,
53 scoped_ptr<DocumentResourceWaiter> resource_waiter,
54 HTMLFrameDelegate* delegate) {
55 if (!instances_)
56 instances_ = new TreeMap;
58 mojo::InterfaceRequest<mandoline::FrameTreeClient> frame_tree_client_request;
59 mandoline::FrameTreeServerPtr frame_tree_server;
60 mojo::Array<mandoline::FrameDataPtr> frame_data;
61 uint32_t change_id;
62 resource_waiter->Release(&frame_tree_client_request, &frame_tree_server,
63 &frame_data, &change_id);
64 resource_waiter.reset();
66 HTMLFrameTreeManager* frame_tree = nullptr;
68 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
69 switches::kOOPIFAlwaysCreateNewFrameTree)) {
70 if (instances_->count(frame_data[0]->frame_id))
71 frame_tree = (*instances_)[frame_data[0]->frame_id];
74 if (!frame_tree) {
75 frame_tree = new HTMLFrameTreeManager(global_state);
76 frame_tree->Init(delegate, view, frame_data, change_id);
77 if (frame_data[0]->frame_id == view->id())
78 (*instances_)[frame_data[0]->frame_id] = frame_tree;
79 } else {
80 // We're going to share a frame tree. There are two possibilities:
81 // . We already know about the frame, in which case we swap it to local.
82 // . We don't know about the frame (most likely because of timing issues),
83 // but we better know about the parent. Create a new frame for it.
84 CHECK(view->id() != frame_data[0]->frame_id);
85 HTMLFrame* existing_frame = frame_tree->root_->FindFrame(view->id());
86 size_t frame_data_index = 0u;
87 CHECK(FindFrameDataIndex(frame_data, view->id(), &frame_data_index));
88 const mandoline::FrameDataPtr& data = frame_data[frame_data_index];
89 if (existing_frame) {
90 CHECK(!existing_frame->IsLocal());
91 existing_frame->SwapToLocal(delegate, view, data->client_properties);
92 } else {
93 // If we can't find the frame and the change_id of the incoming
94 // tree is before the change id we've processed, then we removed the
95 // frame and need do nothing.
96 if (change_id < frame_tree->change_id_)
97 return nullptr;
99 // We removed the frame but it hasn't been acked yet.
100 if (frame_tree->pending_remove_ids_.count(view->id()))
101 return nullptr;
103 // TODO(sky): if change_id > frame_tree->change_id_ then this needs
104 // to wait and bind once the change has been processed.
106 HTMLFrame* parent = frame_tree->root_->FindFrame(data->parent_id);
107 CHECK(parent);
108 HTMLFrame::CreateParams params(frame_tree, parent, view->id(), view,
109 data->client_properties, delegate);
110 delegate->GetHTMLFactory()->CreateHTMLFrame(&params);
114 HTMLFrame* frame = frame_tree->root_->FindFrame(view->id());
115 DCHECK(frame);
116 frame->Bind(frame_tree_server.Pass(), frame_tree_client_request.Pass());
117 return frame;
120 blink::WebView* HTMLFrameTreeManager::GetWebView() {
121 return root_->web_view();
124 void HTMLFrameTreeManager::OnFrameDestroyed(HTMLFrame* frame) {
125 if (frame == root_)
126 root_ = nullptr;
128 if (frame == local_root_)
129 local_root_ = nullptr;
131 if (!in_process_on_frame_removed_)
132 pending_remove_ids_.insert(frame->id());
134 if (!local_root_ || !local_root_->HasLocalDescendant())
135 delete this;
138 HTMLFrameTreeManager::HTMLFrameTreeManager(GlobalState* global_state)
139 : global_state_(global_state),
140 root_(nullptr),
141 local_root_(nullptr),
142 change_id_(0u),
143 in_process_on_frame_removed_(false),
144 weak_factory_(this) {}
146 HTMLFrameTreeManager::~HTMLFrameTreeManager() {
147 DCHECK(!root_ || !local_root_);
148 RemoveFromInstances();
151 void HTMLFrameTreeManager::Init(
152 HTMLFrameDelegate* delegate,
153 mojo::View* local_view,
154 const mojo::Array<mandoline::FrameDataPtr>& frame_data,
155 uint32_t change_id) {
156 change_id_ = change_id;
157 root_ = BuildFrameTree(delegate, frame_data, local_view->id(), local_view);
158 local_root_ = root_->FindFrame(local_view->id());
159 CHECK(local_root_);
160 local_root_->UpdateFocus();
163 HTMLFrame* HTMLFrameTreeManager::BuildFrameTree(
164 HTMLFrameDelegate* delegate,
165 const mojo::Array<mandoline::FrameDataPtr>& frame_data,
166 uint32_t local_frame_id,
167 mojo::View* local_view) {
168 std::vector<HTMLFrame*> parents;
169 HTMLFrame* root = nullptr;
170 HTMLFrame* last_frame = nullptr;
171 for (size_t i = 0; i < frame_data.size(); ++i) {
172 if (last_frame && frame_data[i]->parent_id == last_frame->id()) {
173 parents.push_back(last_frame);
174 } else if (!parents.empty()) {
175 while (parents.back()->id() != frame_data[i]->parent_id)
176 parents.pop_back();
178 HTMLFrame::CreateParams params(this,
179 !parents.empty() ? parents.back() : nullptr,
180 frame_data[i]->frame_id, local_view,
181 frame_data[i]->client_properties, nullptr);
182 if (frame_data[i]->frame_id == local_frame_id)
183 params.delegate = delegate;
185 HTMLFrame* frame = delegate->GetHTMLFactory()->CreateHTMLFrame(&params);
186 if (!last_frame)
187 root = frame;
188 else
189 DCHECK(frame->parent());
190 last_frame = frame;
192 return root;
195 void HTMLFrameTreeManager::RemoveFromInstances() {
196 for (auto pair : *instances_) {
197 if (pair.second == this) {
198 instances_->erase(pair.first);
199 return;
204 bool HTMLFrameTreeManager::PrepareForStructureChange(HTMLFrame* source,
205 uint32_t change_id) {
206 // The change ids may differ if multiple HTMLDocuments are attached to the
207 // same tree (which means we have multiple FrameTreeClients for the same
208 // tree).
209 if (change_id != (change_id_ + 1))
210 return false;
212 // We only process changes for the topmost local root.
213 if (source != local_root_)
214 return false;
216 // Update the id as the change is going to be applied (or we can assume it
217 // will be applied if we get here).
218 change_id_ = change_id;
219 return true;
222 void HTMLFrameTreeManager::ProcessOnFrameAdded(
223 HTMLFrame* source,
224 uint32_t change_id,
225 mandoline::FrameDataPtr frame_data) {
226 if (!PrepareForStructureChange(source, change_id))
227 return;
229 HTMLFrame* parent = root_->FindFrame(frame_data->parent_id);
230 if (!parent) {
231 DVLOG(1) << "Received invalid parent in OnFrameAdded "
232 << frame_data->parent_id;
233 return;
235 if (root_->FindFrame(frame_data->frame_id)) {
236 DVLOG(1) << "Child with id already exists in OnFrameAdded "
237 << frame_data->frame_id;
238 return;
241 // Because notification is async it's entirely possible for us to create a
242 // new frame, and remove it before we get the add from the server. This check
243 // ensures we don't add back a frame we explicitly removed.
244 if (pending_remove_ids_.count(frame_data->frame_id))
245 return;
247 HTMLFrame::CreateParams params(this, parent, frame_data->frame_id, nullptr,
248 frame_data->client_properties, nullptr);
249 // |parent| takes ownership of created HTMLFrame.
250 source->GetLocalRoot()->delegate_->GetHTMLFactory()->CreateHTMLFrame(&params);
253 void HTMLFrameTreeManager::ProcessOnFrameRemoved(HTMLFrame* source,
254 uint32_t change_id,
255 uint32_t frame_id) {
256 if (!PrepareForStructureChange(source, change_id))
257 return;
259 pending_remove_ids_.erase(frame_id);
261 HTMLFrame* frame = root_->FindFrame(frame_id);
262 if (!frame) {
263 DVLOG(1) << "OnFrameRemoved with unknown frame " << frame_id;
264 return;
267 // We shouldn't see requests to remove the root.
268 if (frame == root_) {
269 DVLOG(1) << "OnFrameRemoved supplied root; ignoring";
270 return;
273 // Requests to remove local frames are followed by the View being destroyed.
274 // We handle destruction there.
275 if (frame->IsLocal())
276 return;
278 DCHECK(!in_process_on_frame_removed_);
279 in_process_on_frame_removed_ = true;
280 base::WeakPtr<HTMLFrameTreeManager> ref(weak_factory_.GetWeakPtr());
281 frame->Close();
282 if (!ref)
283 return; // We were deleted.
285 in_process_on_frame_removed_ = false;
288 void HTMLFrameTreeManager::ProcessOnFrameClientPropertyChanged(
289 HTMLFrame* source,
290 uint32_t frame_id,
291 const mojo::String& name,
292 mojo::Array<uint8_t> new_data) {
293 if (source != local_root_)
294 return;
296 HTMLFrame* frame = root_->FindFrame(frame_id);
297 if (frame)
298 frame->SetValueFromClientProperty(name, new_data.Pass());
301 } // namespace mojo