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"
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 "mojo/application/public/cpp/application_impl.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
{
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
,
35 for (size_t i
= 0; i
< frame_data
.size(); ++i
) {
36 if (frame_data
[i
]->frame_id
== frame_id
) {
47 HTMLFrameTreeManager::TreeMap
* HTMLFrameTreeManager::instances_
= nullptr;
50 HTMLFrame
* HTMLFrameTreeManager::CreateFrameAndAttachToTree(
51 GlobalState
* global_state
,
52 mojo::ApplicationImpl
* app
,
54 scoped_ptr
<DocumentResourceWaiter
> resource_waiter
,
55 HTMLFrameDelegate
* delegate
) {
57 instances_
= new TreeMap
;
59 mojo::InterfaceRequest
<mandoline::FrameTreeClient
> frame_tree_client_request
;
60 mandoline::FrameTreeServerPtr frame_tree_server
;
61 mojo::Array
<mandoline::FrameDataPtr
> frame_data
;
62 resource_waiter
->Release(&frame_tree_client_request
, &frame_tree_server
,
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
];
75 frame_tree
= new HTMLFrameTreeManager(global_state
);
76 frame_tree
->Init(delegate
, view
, frame_data
);
77 if (frame_data
[0]->frame_id
== view
->id())
78 (*instances_
)[frame_data
[0]->frame_id
] = frame_tree
;
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
];
90 CHECK(!existing_frame
->IsLocal());
91 existing_frame
->set_delegate(delegate
);
92 existing_frame
->SwapToLocal(view
, data
->name
.To
<blink::WebString
>());
94 HTMLFrame
* parent
= frame_tree
->root_
->FindFrame(data
->parent_id
);
96 HTMLFrame::CreateParams
params(frame_tree
, parent
, view
->id());
97 HTMLFrame
* frame
= new HTMLFrame(params
);
98 frame
->set_delegate(delegate
);
99 frame
->Init(view
, data
->name
.To
<blink::WebString
>(),
100 data
->origin
.To
<blink::WebString
>());
104 HTMLFrame
* frame
= frame_tree
->root_
->FindFrame(view
->id());
106 frame
->Bind(frame_tree_server
.Pass(), frame_tree_client_request
.Pass());
110 blink::WebView
* HTMLFrameTreeManager::GetWebView() {
111 return root_
->web_view();
114 void HTMLFrameTreeManager::OnFrameDestroyed(HTMLFrame
* frame
) {
118 if (frame
== local_root_
)
119 local_root_
= nullptr;
121 if (!local_root_
|| !local_root_
->HasLocalDescendant())
125 HTMLFrameTreeManager::HTMLFrameTreeManager(GlobalState
* global_state
)
126 : global_state_(global_state
), root_(nullptr), local_root_(nullptr) {}
128 HTMLFrameTreeManager::~HTMLFrameTreeManager() {
130 DCHECK(!local_root_
);
131 RemoveFromInstances();
134 void HTMLFrameTreeManager::Init(
135 HTMLFrameDelegate
* delegate
,
136 mojo::View
* local_view
,
137 const mojo::Array
<mandoline::FrameDataPtr
>& frame_data
) {
138 root_
= BuildFrameTree(delegate
, frame_data
, local_view
->id(), local_view
);
139 local_root_
= root_
->FindFrame(local_view
->id());
141 local_root_
->UpdateFocus();
144 HTMLFrame
* HTMLFrameTreeManager::BuildFrameTree(
145 HTMLFrameDelegate
* delegate
,
146 const mojo::Array
<mandoline::FrameDataPtr
>& frame_data
,
147 uint32_t local_frame_id
,
148 mojo::View
* local_view
) {
149 std::vector
<HTMLFrame
*> parents
;
150 HTMLFrame
* root
= nullptr;
151 HTMLFrame
* last_frame
= nullptr;
152 for (size_t i
= 0; i
< frame_data
.size(); ++i
) {
153 if (last_frame
&& frame_data
[i
]->parent_id
== last_frame
->id()) {
154 parents
.push_back(last_frame
);
155 } else if (!parents
.empty()) {
156 while (parents
.back()->id() != frame_data
[i
]->parent_id
)
159 HTMLFrame::CreateParams
params(this,
160 !parents
.empty() ? parents
.back() : nullptr,
161 frame_data
[i
]->frame_id
);
162 HTMLFrame
* frame
= new HTMLFrame(params
);
166 DCHECK(frame
->parent());
169 if (frame_data
[i
]->frame_id
== local_frame_id
)
170 frame
->set_delegate(delegate
);
172 frame
->Init(local_view
, frame_data
[i
]->name
.To
<blink::WebString
>(),
173 frame_data
[i
]->origin
.To
<blink::WebString
>());
178 void HTMLFrameTreeManager::RemoveFromInstances() {
179 for (auto pair
: *instances_
) {
180 if (pair
.second
== this) {
181 instances_
->erase(pair
.first
);
187 void HTMLFrameTreeManager::ProcessOnFrameAdded(
189 mandoline::FrameDataPtr frame_data
) {
190 if (source
!= local_root_
)
193 HTMLFrame
* parent
= root_
->FindFrame(frame_data
->parent_id
);
195 DVLOG(1) << "Received invalid parent in OnFrameAdded "
196 << frame_data
->parent_id
;
199 if (root_
->FindFrame(frame_data
->frame_id
)) {
200 DVLOG(1) << "Child with id already exists in OnFrameAdded "
201 << frame_data
->frame_id
;
205 HTMLFrame::CreateParams
params(this, parent
, frame_data
->frame_id
);
206 // |parent| takes ownership of |frame|.
207 HTMLFrame
* frame
= new HTMLFrame(params
);
208 frame
->Init(nullptr, frame_data
->name
.To
<blink::WebString
>(),
209 frame_data
->origin
.To
<blink::WebString
>());
212 void HTMLFrameTreeManager::ProcessOnFrameRemoved(HTMLFrame
* source
,
214 if (source
!= local_root_
)
217 HTMLFrame
* frame
= root_
->FindFrame(frame_id
);
219 DVLOG(1) << "OnFrameRemoved with unknown frame " << frame_id
;
223 // We shouldn't see requests to remove the root.
224 if (frame
== root_
) {
225 DVLOG(1) << "OnFrameRemoved supplied root; ignoring";
229 // Requests to remove local frames are followed by the View being destroyed.
230 // We handle destruction there.
231 if (frame
->IsLocal())
237 void HTMLFrameTreeManager::ProcessOnFrameNameChanged(HTMLFrame
* source
,
239 const mojo::String
& name
) {
243 HTMLFrame
* frame
= root_
->FindFrame(frame_id
);
245 frame
->SetRemoteFrameName(name
);