Delete unused downloads page asset.
[chromium-blink-merge.git] / mandoline / tab / frame.cc
blobdcff344c6792a98b9c6bff3304e945862805cb30
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 "mandoline/tab/frame.h"
7 #include <algorithm>
9 #include "base/auto_reset.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/stl_util.h"
13 #include "components/view_manager/public/cpp/view.h"
14 #include "components/view_manager/public/cpp/view_property.h"
15 #include "mandoline/tab/frame_tree.h"
16 #include "mandoline/tab/frame_tree_delegate.h"
17 #include "mandoline/tab/frame_user_data.h"
19 using mojo::View;
21 DECLARE_VIEW_PROPERTY_TYPE(mandoline::Frame*);
23 namespace mandoline {
25 // Used to find the Frame associated with a View.
26 DEFINE_LOCAL_VIEW_PROPERTY_KEY(Frame*, kFrame, nullptr);
28 namespace {
30 const uint32_t kNoParentId = 0u;
32 FrameDataPtr FrameToFrameData(const Frame* frame) {
33 FrameDataPtr frame_data(FrameData::New());
34 frame_data->frame_id = frame->id();
35 frame_data->parent_id = frame->parent() ? frame->parent()->id() : kNoParentId;
36 frame_data->client_properties =
37 mojo::Map<mojo::String, mojo::Array<uint8_t>>::From(
38 frame->client_properties());
39 return frame_data.Pass();
42 } // namespace
44 Frame::Frame(FrameTree* tree,
45 View* view,
46 uint32_t id,
47 ViewOwnership view_ownership,
48 FrameTreeClient* frame_tree_client,
49 scoped_ptr<FrameUserData> user_data,
50 const ClientPropertyMap& client_properties)
51 : tree_(tree),
52 view_(nullptr),
53 id_(id),
54 parent_(nullptr),
55 view_ownership_(view_ownership),
56 user_data_(user_data.Pass()),
57 frame_tree_client_(frame_tree_client),
58 loading_(false),
59 progress_(0.f),
60 client_properties_(client_properties),
61 frame_tree_server_binding_(this),
62 weak_factory_(this) {
63 if (view)
64 SetView(view);
67 Frame::~Frame() {
68 if (view_)
69 view_->RemoveObserver(this);
70 while (!children_.empty())
71 delete children_[0];
72 if (parent_)
73 parent_->Remove(this);
74 if (view_) {
75 view_->ClearLocalProperty(kFrame);
76 if (view_ownership_ == ViewOwnership::OWNS_VIEW)
77 view_->Destroy();
81 void Frame::Init(Frame* parent) {
83 // Set the FrameTreeClient to null so that we don't notify the client of the
84 // add before OnConnect().
85 base::AutoReset<FrameTreeClient*> frame_tree_client_resetter(
86 &frame_tree_client_, nullptr);
87 if (parent)
88 parent->Add(this);
91 InitClient();
94 // static
95 Frame* Frame::FindFirstFrameAncestor(View* view) {
96 while (view && !view->GetLocalProperty(kFrame))
97 view = view->parent();
98 return view ? view->GetLocalProperty(kFrame) : nullptr;
101 const Frame* Frame::FindFrame(uint32_t id) const {
102 if (id == id_)
103 return this;
105 for (const Frame* child : children_) {
106 const Frame* match = child->FindFrame(id);
107 if (match)
108 return match;
110 return nullptr;
113 bool Frame::HasAncestor(const Frame* frame) const {
114 const Frame* current = this;
115 while (current && current != frame)
116 current = current->parent_;
117 return current == frame;
120 bool Frame::IsLoading() const {
121 if (loading_)
122 return true;
123 for (const Frame* child : children_) {
124 if (child->IsLoading())
125 return true;
127 return false;
130 double Frame::GatherProgress(int* frame_count) const {
131 ++(*frame_count);
132 double progress = progress_;
133 for (const Frame* child : children_)
134 progress += child->GatherProgress(frame_count);
135 return progress_;
138 void Frame::InitClient() {
139 std::vector<const Frame*> frames;
140 tree_->root()->BuildFrameTree(&frames);
142 mojo::Array<FrameDataPtr> array(frames.size());
143 for (size_t i = 0; i < frames.size(); ++i)
144 array[i] = FrameToFrameData(frames[i]).Pass();
146 // TODO(sky): error handling.
147 FrameTreeServerPtr frame_tree_server_ptr;
148 frame_tree_server_binding_.Bind(GetProxy(&frame_tree_server_ptr).Pass());
149 if (frame_tree_client_) {
150 frame_tree_client_->OnConnect(frame_tree_server_ptr.Pass(),
151 tree_->change_id(), array.Pass());
152 tree_->delegate_->DidStartNavigation(this);
156 void Frame::OnWillNavigateAck(FrameTreeClient* frame_tree_client,
157 scoped_ptr<FrameUserData> user_data,
158 mojo::ViewTreeClientPtr view_tree_client) {
159 while (!children_.empty())
160 delete children_[0];
162 user_data_ = user_data.Pass();
163 frame_tree_client_ = frame_tree_client;
164 frame_tree_server_binding_.Close();
165 loading_ = false;
166 progress_ = 0.f;
168 view_->Embed(view_tree_client.Pass());
169 InitClient();
172 void Frame::SetView(mojo::View* view) {
173 DCHECK(!view_);
174 DCHECK_EQ(id_, view->id());
175 view_ = view;
176 view_->SetLocalProperty(kFrame, this);
177 view_->AddObserver(this);
178 if (pending_navigate_.get())
179 StartNavigate(pending_navigate_.Pass());
182 Frame* Frame::GetAncestorWithFrameTreeClient() {
183 Frame* frame = this;
184 while (frame && !frame->frame_tree_client_)
185 frame = frame->parent_;
186 return frame;
189 void Frame::BuildFrameTree(std::vector<const Frame*>* frames) const {
190 frames->push_back(this);
191 for (const Frame* frame : children_)
192 frame->BuildFrameTree(frames);
195 void Frame::Add(Frame* node) {
196 DCHECK(!node->parent_);
198 node->parent_ = this;
199 children_.push_back(node);
201 tree_->root()->NotifyAdded(this, node, tree_->AdvanceChangeID());
204 void Frame::Remove(Frame* node) {
205 DCHECK_EQ(node->parent_, this);
206 auto iter = std::find(children_.begin(), children_.end(), node);
207 DCHECK(iter != children_.end());
208 node->parent_ = nullptr;
209 children_.erase(iter);
211 tree_->root()->NotifyRemoved(this, node, tree_->AdvanceChangeID());
214 void Frame::StartNavigate(mojo::URLRequestPtr request) {
215 pending_navigate_.reset();
217 // We need a View to navigate. When we get the View we'll complete the
218 // navigation.
219 // TODO(sky): consider state and what is not legal while waiting.
220 if (!view_) {
221 pending_navigate_ = request.Pass();
222 return;
225 FrameTreeClient* frame_tree_client = nullptr;
226 scoped_ptr<FrameUserData> user_data;
227 mojo::ViewTreeClientPtr view_tree_client;
228 if (!tree_->delegate_->CanNavigateFrame(this, request.Pass(),
229 &frame_tree_client, &user_data,
230 &view_tree_client)) {
231 return;
234 // TODO(sky): consider what state this should correspond to. Should we
235 // disallow certain operations until we get the ack?
236 Frame* ancestor_with_frame_tree_client = GetAncestorWithFrameTreeClient();
237 DCHECK(ancestor_with_frame_tree_client);
238 ancestor_with_frame_tree_client->frame_tree_client_->OnWillNavigate(
239 id_, base::Bind(&Frame::OnWillNavigateAck, weak_factory_.GetWeakPtr(),
240 frame_tree_client, base::Passed(&user_data),
241 base::Passed(&view_tree_client)));
244 void Frame::LoadingStartedImpl() {
245 DCHECK(!loading_);
246 loading_ = true;
247 progress_ = 0.f;
248 tree_->LoadingStateChanged();
251 void Frame::LoadingStoppedImpl() {
252 DCHECK(loading_);
253 loading_ = false;
254 tree_->LoadingStateChanged();
257 void Frame::ProgressChangedImpl(double progress) {
258 DCHECK(loading_);
259 progress_ = progress;
260 tree_->ProgressChanged();
263 void Frame::SetClientPropertyImpl(const mojo::String& name,
264 mojo::Array<uint8_t> value) {
265 auto iter = client_properties_.find(name);
266 const bool already_in_map = (iter != client_properties_.end());
267 if (value.is_null()) {
268 if (!already_in_map)
269 return;
270 client_properties_.erase(iter);
271 } else {
272 std::vector<uint8_t> as_vector(value.To<std::vector<uint8_t>>());
273 if (already_in_map && iter->second == as_vector)
274 return;
275 client_properties_[name] = as_vector;
277 tree_->ClientPropertyChanged(this, name, value);
280 Frame* Frame::FindTargetFrame(uint32_t frame_id) {
281 if (frame_id == id_)
282 return this; // Common case.
284 // TODO(sky): I need a way to sanity check frame_id here, but the connection
285 // id isn't known to us.
287 Frame* frame = FindFrame(frame_id);
288 if (frame->frame_tree_client_) {
289 // The frame has it's own client/server pair. It should make requests using
290 // the server it has rather than an ancestor.
291 DVLOG(1) << "ignore request for a frame that has its own client.";
292 return nullptr;
295 return frame;
298 void Frame::NotifyAdded(const Frame* source,
299 const Frame* added_node,
300 uint32_t change_id) {
301 if (frame_tree_client_)
302 frame_tree_client_->OnFrameAdded(change_id, FrameToFrameData(added_node));
304 for (Frame* child : children_)
305 child->NotifyAdded(source, added_node, change_id);
308 void Frame::NotifyRemoved(const Frame* source,
309 const Frame* removed_node,
310 uint32_t change_id) {
311 if (frame_tree_client_)
312 frame_tree_client_->OnFrameRemoved(change_id, removed_node->id());
314 for (Frame* child : children_)
315 child->NotifyRemoved(source, removed_node, change_id);
318 void Frame::NotifyClientPropertyChanged(const Frame* source,
319 const mojo::String& name,
320 const mojo::Array<uint8_t>& value) {
321 if (this != source && frame_tree_client_)
322 frame_tree_client_->OnFrameClientPropertyChanged(source->id(), name,
323 value.Clone());
325 for (Frame* child : children_)
326 child->NotifyClientPropertyChanged(source, name, value);
329 void Frame::OnTreeChanged(const TreeChangeParams& params) {
330 if (params.new_parent && this == tree_->root()) {
331 Frame* child_frame = FindFrame(params.target->id());
332 if (child_frame && !child_frame->view_)
333 child_frame->SetView(params.target);
337 void Frame::OnViewDestroying(mojo::View* view) {
338 if (parent_)
339 parent_->Remove(this);
341 // Reset |view_ownership_| so we don't attempt to delete |view_| in the
342 // destructor.
343 view_ownership_ = ViewOwnership::DOESNT_OWN_VIEW;
345 // TODO(sky): Change browser to create a child for each FrameTree.
346 if (tree_->root() == this) {
347 view_->RemoveObserver(this);
348 view_ = nullptr;
349 return;
352 delete this;
355 void Frame::PostMessageEventToFrame(uint32_t source_frame_id,
356 uint32_t target_frame_id,
357 HTMLMessageEventPtr event) {
358 Frame* source = tree_->root()->FindFrame(source_frame_id);
359 Frame* target = tree_->root()->FindFrame(target_frame_id);
360 if (!target || !source || source == target || !tree_->delegate_ ||
361 !tree_->delegate_->CanPostMessageEventToFrame(source, target,
362 event.get()))
363 return;
365 DCHECK(target->GetAncestorWithFrameTreeClient());
366 target->GetAncestorWithFrameTreeClient()
367 ->frame_tree_client_->OnPostMessageEvent(source_frame_id, target_frame_id,
368 event.Pass());
371 void Frame::LoadingStarted(uint32_t frame_id) {
372 Frame* target_frame = FindTargetFrame(frame_id);
373 if (target_frame)
374 target_frame->LoadingStartedImpl();
377 void Frame::LoadingStopped(uint32_t frame_id) {
378 Frame* target_frame = FindTargetFrame(frame_id);
379 if (target_frame)
380 target_frame->LoadingStoppedImpl();
383 void Frame::ProgressChanged(uint32_t frame_id, double progress) {
384 Frame* target_frame = FindTargetFrame(frame_id);
385 if (target_frame)
386 target_frame->ProgressChangedImpl(progress);
389 void Frame::SetClientProperty(uint32_t frame_id,
390 const mojo::String& name,
391 mojo::Array<uint8_t> value) {
392 Frame* target_frame = FindTargetFrame(frame_id);
393 if (target_frame)
394 target_frame->SetClientPropertyImpl(name, value.Pass());
397 void Frame::OnCreatedFrame(
398 uint32_t parent_id,
399 uint32_t frame_id,
400 mojo::Map<mojo::String, mojo::Array<uint8_t>> client_properties) {
401 // TODO(sky): I need a way to verify the id. Unfortunately the code here
402 // doesn't know the connection id of the embedder, so it's not possible to
403 // do it.
405 if (FindFrame(frame_id)) {
406 // TODO(sky): kill connection here?
407 DVLOG(1) << "OnCreatedLocalFrame supplied id of existing frame.";
408 return;
411 Frame* parent_frame = FindFrame(parent_id);
412 if (!parent_frame) {
413 DVLOG(1) << "OnCreatedLocalFrame supplied invalid parent_id.";
414 return;
417 if (parent_frame != this && parent_frame->frame_tree_client_) {
418 DVLOG(1) << "OnCreatedLocalFrame supplied parent from another connection.";
419 return;
422 tree_->CreateSharedFrame(parent_frame, frame_id,
423 client_properties.To<ClientPropertyMap>());
426 void Frame::RequestNavigate(mandoline::NavigationTargetType target_type,
427 uint32_t target_frame_id,
428 mojo::URLRequestPtr request) {
429 if (target_type == NAVIGATION_TARGET_TYPE_EXISTING_FRAME) {
430 Frame* target_frame = tree_->root()->FindFrame(target_frame_id);
431 if (!target_frame) {
432 DVLOG(1) << "RequestNavigate EXIT_FRAME with no matching frame";
433 return;
435 if (target_frame != tree_->root()) {
436 target_frame->StartNavigate(request.Pass());
437 return;
439 // Else case if |target_frame| == root. Treat at top level request.
441 tree_->delegate_->NavigateTopLevel(this, request.Pass());
444 void Frame::DidNavigateLocally(uint32_t frame_id, const mojo::String& url) {
445 NOTIMPLEMENTED();
448 } // namespace mandoline