Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / html_viewer / html_frame.cc
blob2a307bc718923c32181cd23ceae28352a1dabf6d
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.h"
7 #include <algorithm>
8 #include <limits>
10 #include "base/bind.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "components/html_viewer/ax_provider_impl.h"
16 #include "components/html_viewer/blink_basic_type_converters.h"
17 #include "components/html_viewer/blink_input_events_type_converters.h"
18 #include "components/html_viewer/blink_text_input_type_converters.h"
19 #include "components/html_viewer/blink_url_request_type_converters.h"
20 #include "components/html_viewer/devtools_agent_impl.h"
21 #include "components/html_viewer/geolocation_client_impl.h"
22 #include "components/html_viewer/global_state.h"
23 #include "components/html_viewer/html_factory.h"
24 #include "components/html_viewer/html_frame_delegate.h"
25 #include "components/html_viewer/html_frame_properties.h"
26 #include "components/html_viewer/html_frame_tree_manager.h"
27 #include "components/html_viewer/html_widget.h"
28 #include "components/html_viewer/media_factory.h"
29 #include "components/html_viewer/stats_collection_controller.h"
30 #include "components/html_viewer/touch_handler.h"
31 #include "components/html_viewer/web_layer_impl.h"
32 #include "components/html_viewer/web_layer_tree_view_impl.h"
33 #include "components/html_viewer/web_storage_namespace_impl.h"
34 #include "components/html_viewer/web_url_loader_impl.h"
35 #include "components/mus/ids.h"
36 #include "components/mus/public/cpp/scoped_view_ptr.h"
37 #include "components/mus/public/cpp/view.h"
38 #include "components/mus/public/cpp/view_tree_connection.h"
39 #include "mojo/application/public/cpp/application_impl.h"
40 #include "mojo/application/public/cpp/connect.h"
41 #include "mojo/application/public/interfaces/shell.mojom.h"
42 #include "mojo/common/common_type_converters.h"
43 #include "mojo/converters/geometry/geometry_type_converters.h"
44 #include "skia/ext/refptr.h"
45 #include "third_party/WebKit/public/platform/Platform.h"
46 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
47 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
48 #include "third_party/WebKit/public/platform/WebSize.h"
49 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
50 #include "third_party/WebKit/public/web/WebDocument.h"
51 #include "third_party/WebKit/public/web/WebElement.h"
52 #include "third_party/WebKit/public/web/WebInputEvent.h"
53 #include "third_party/WebKit/public/web/WebKit.h"
54 #include "third_party/WebKit/public/web/WebLocalFrame.h"
55 #include "third_party/WebKit/public/web/WebNavigationPolicy.h"
56 #include "third_party/WebKit/public/web/WebRemoteFrame.h"
57 #include "third_party/WebKit/public/web/WebRemoteFrameClient.h"
58 #include "third_party/WebKit/public/web/WebScriptSource.h"
59 #include "third_party/WebKit/public/web/WebView.h"
60 #include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
61 #include "third_party/skia/include/core/SkCanvas.h"
62 #include "third_party/skia/include/core/SkColor.h"
63 #include "third_party/skia/include/core/SkDevice.h"
64 #include "ui/gfx/geometry/dip_util.h"
65 #include "ui/gfx/geometry/size.h"
66 #include "url/gurl.h"
67 #include "url/origin.h"
68 #include "url/url_constants.h"
70 using mojo::AxProvider;
71 using mojo::Rect;
72 using mojo::ServiceProviderPtr;
73 using mojo::URLResponsePtr;
74 using mus::View;
75 using web_view::mojom::HTMLMessageEvent;
76 using web_view::mojom::HTMLMessageEventPtr;
78 namespace html_viewer {
79 namespace {
81 const size_t kMaxTitleChars = 4 * 1024;
83 web_view::mojom::NavigationTargetType WebNavigationPolicyToNavigationTarget(
84 blink::WebNavigationPolicy policy) {
85 switch (policy) {
86 case blink::WebNavigationPolicyCurrentTab:
87 return web_view::mojom::NAVIGATION_TARGET_TYPE_EXISTING_FRAME;
88 case blink::WebNavigationPolicyNewBackgroundTab:
89 case blink::WebNavigationPolicyNewForegroundTab:
90 case blink::WebNavigationPolicyNewWindow:
91 case blink::WebNavigationPolicyNewPopup:
92 return web_view::mojom::NAVIGATION_TARGET_TYPE_NEW_FRAME;
93 default:
94 return web_view::mojom::NAVIGATION_TARGET_TYPE_NO_PREFERENCE;
98 HTMLFrame* GetPreviousSibling(HTMLFrame* frame) {
99 DCHECK(frame->parent());
100 auto iter = std::find(frame->parent()->children().begin(),
101 frame->parent()->children().end(), frame);
102 return (iter == frame->parent()->children().begin()) ? nullptr : *(--iter);
105 } // namespace
107 HTMLFrame::HTMLFrame(CreateParams* params)
108 : frame_tree_manager_(params->manager),
109 parent_(params->parent),
110 view_(nullptr),
111 id_(params->id),
112 web_frame_(nullptr),
113 delegate_(params->delegate),
114 weak_factory_(this) {
115 if (parent_)
116 parent_->children_.push_back(this);
118 if (params->view && params->view->id() == id_)
119 SetView(params->view);
121 SetReplicatedFrameStateFromClientProperties(params->properties, &state_);
123 if (!parent_) {
124 CreateRootWebWidget();
126 // This is the root of the tree (aka the main frame).
127 // Expected order for creating webframes is:
128 // . Create local webframe (first webframe must always be local).
129 // . Set as main frame on WebView.
130 // . Swap to remote (if not local).
131 blink::WebLocalFrame* local_web_frame =
132 blink::WebLocalFrame::create(state_.tree_scope, this);
133 // We need to set the main frame before creating children so that state is
134 // properly set up in blink.
135 web_view()->setMainFrame(local_web_frame);
137 // The resize and setDeviceScaleFactor() needs to be after setting the main
138 // frame.
139 const gfx::Size size_in_pixels(params->view->bounds().width,
140 params->view->bounds().height);
141 const gfx::Size size_in_dips = gfx::ConvertSizeToDIP(
142 params->view->viewport_metrics().device_pixel_ratio, size_in_pixels);
143 web_view()->resize(size_in_dips);
144 web_frame_ = local_web_frame;
145 web_view()->setDeviceScaleFactor(global_state()->device_pixel_ratio());
146 if (id_ != params->view->id()) {
147 blink::WebRemoteFrame* remote_web_frame =
148 blink::WebRemoteFrame::create(state_.tree_scope, this);
149 local_web_frame->swap(remote_web_frame);
150 web_frame_ = remote_web_frame;
151 } else {
152 // Setup a DevTools agent if this is the local main frame and the browser
153 // side has set relevant client properties.
154 mojo::Array<uint8_t> devtools_id =
155 GetValueFromClientProperties("devtools-id", params->properties);
156 if (!devtools_id.is_null()) {
157 mojo::Array<uint8_t> devtools_state =
158 GetValueFromClientProperties("devtools-state", params->properties);
159 std::string devtools_state_str = devtools_state.To<std::string>();
160 devtools_agent_.reset(new DevToolsAgentImpl(
161 web_frame_->toWebLocalFrame(), devtools_id.To<std::string>(),
162 devtools_state.is_null() ? nullptr : &devtools_state_str));
165 // Collect startup perf data for local main frames in test environments.
166 // Child frames aren't tracked, and tracking remote frames is redundant.
167 startup_performance_data_collector_ =
168 StatsCollectionController::Install(web_frame_, GetApp());
170 } else if (!params->is_local_create_child && params->view &&
171 id_ == params->view->id()) {
172 // Frame represents the local frame, and it isn't the root of the tree.
173 HTMLFrame* previous_sibling = GetPreviousSibling(this);
174 blink::WebFrame* previous_web_frame =
175 previous_sibling ? previous_sibling->web_frame() : nullptr;
176 CHECK(!parent_->IsLocal());
177 web_frame_ = parent_->web_frame()->toWebRemoteFrame()->createLocalChild(
178 state_.tree_scope, state_.name, state_.sandbox_flags, this,
179 previous_web_frame);
180 CreateLocalRootWebWidget(web_frame_->toWebLocalFrame());
181 } else if (!parent_->IsLocal()) {
182 web_frame_ = parent_->web_frame()->toWebRemoteFrame()->createRemoteChild(
183 state_.tree_scope, state_.name, state_.sandbox_flags, this);
184 } else {
185 CHECK(params->is_local_create_child);
187 blink::WebLocalFrame* child_web_frame =
188 blink::WebLocalFrame::create(state_.tree_scope, this);
189 web_frame_ = child_web_frame;
190 parent_->web_frame_->appendChild(child_web_frame);
193 if (!IsLocal()) {
194 blink::WebRemoteFrame* remote_web_frame = web_frame_->toWebRemoteFrame();
195 if (remote_web_frame) {
196 remote_web_frame->setReplicatedOrigin(state_.origin);
197 remote_web_frame->setReplicatedName(state_.name);
202 void HTMLFrame::Close() {
203 if (GetWebWidget()) {
204 // Closing the root widget (WebView) implicitly detaches. For children
205 // (which have a WebFrameWidget) a detach() is required. Use a temporary
206 // as if 'this' is the root the call to GetWebWidget()->close() deletes
207 // 'this'.
208 const bool is_child = parent_ != nullptr;
209 GetWebWidget()->close();
210 if (is_child)
211 web_frame_->detach();
212 } else {
213 web_frame_->detach();
217 const HTMLFrame* HTMLFrame::FindFrame(uint32_t id) const {
218 if (id == id_)
219 return this;
221 for (const HTMLFrame* child : children_) {
222 const HTMLFrame* match = child->FindFrame(id);
223 if (match)
224 return match;
226 return nullptr;
229 blink::WebView* HTMLFrame::web_view() {
230 blink::WebWidget* web_widget =
231 html_widget_ ? html_widget_->GetWidget() : nullptr;
232 return web_widget && web_widget->isWebView()
233 ? static_cast<blink::WebView*>(web_widget)
234 : nullptr;
237 blink::WebWidget* HTMLFrame::GetWebWidget() {
238 return html_widget_ ? html_widget_->GetWidget() : nullptr;
241 bool HTMLFrame::IsLocal() const {
242 return web_frame_->isWebLocalFrame();
245 bool HTMLFrame::HasLocalDescendant() const {
246 if (IsLocal())
247 return true;
249 for (HTMLFrame* child : children_) {
250 if (child->HasLocalDescendant())
251 return true;
253 return false;
256 HTMLFrame::~HTMLFrame() {
257 DCHECK(children_.empty());
259 if (parent_) {
260 auto iter =
261 std::find(parent_->children_.begin(), parent_->children_.end(), this);
262 parent_->children_.erase(iter);
264 parent_ = nullptr;
266 frame_tree_manager_->OnFrameDestroyed(this);
268 if (delegate_)
269 delegate_->OnFrameDestroyed();
271 if (view_) {
272 view_->RemoveObserver(this);
273 mus::ScopedViewPtr::DeleteViewOrViewManager(view_);
277 blink::WebMediaPlayer* HTMLFrame::createMediaPlayer(
278 blink::WebLocalFrame* frame,
279 const blink::WebURL& url,
280 blink::WebMediaPlayerClient* client,
281 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
282 blink::WebContentDecryptionModule* initial_cdm) {
283 return global_state()->media_factory()->CreateMediaPlayer(
284 frame, url, client, encrypted_client, initial_cdm, GetApp()->shell());
287 blink::WebFrame* HTMLFrame::createChildFrame(
288 blink::WebLocalFrame* parent,
289 blink::WebTreeScopeType scope,
290 const blink::WebString& frame_name,
291 blink::WebSandboxFlags sandbox_flags) {
292 DCHECK(IsLocal()); // Can't create children of remote frames.
293 DCHECK_EQ(parent, web_frame_);
294 DCHECK(view_); // If we're local we have to have a view.
295 // Create the view that will house the frame now. We embed once we know the
296 // url (see decidePolicyForNavigation()).
297 mus::View* child_view = view_->connection()->CreateView();
298 ReplicatedFrameState child_state;
299 child_state.name = frame_name;
300 child_state.tree_scope = scope;
301 child_state.sandbox_flags = sandbox_flags;
302 mojo::Map<mojo::String, mojo::Array<uint8_t>> client_properties;
303 client_properties.mark_non_null();
304 ClientPropertiesFromReplicatedFrameState(child_state, &client_properties);
306 child_view->SetVisible(true);
307 view_->AddChild(child_view);
309 HTMLFrame::CreateParams params(frame_tree_manager_, this, child_view->id(),
310 child_view, client_properties, nullptr);
311 params.is_local_create_child = true;
312 HTMLFrame* child_frame = GetFirstAncestorWithDelegate()
313 ->delegate_->GetHTMLFactory()
314 ->CreateHTMLFrame(&params);
315 child_frame->owned_view_.reset(new mus::ScopedViewPtr(child_view));
317 web_view::mojom::FrameClientPtr client_ptr;
318 child_frame->frame_client_binding_.reset(
319 new mojo::Binding<web_view::mojom::FrameClient>(
320 child_frame, mojo::GetProxy(&client_ptr)));
321 server_->OnCreatedFrame(GetProxy(&(child_frame->server_)), client_ptr.Pass(),
322 child_view->id(), client_properties.Pass());
323 return child_frame->web_frame_;
326 void HTMLFrame::frameDetached(blink::WebFrame* web_frame,
327 blink::WebFrameClient::DetachType type) {
328 if (type == blink::WebFrameClient::DetachType::Swap) {
329 web_frame->close();
330 return;
333 DCHECK(type == blink::WebFrameClient::DetachType::Remove);
334 FrameDetachedImpl(web_frame);
337 blink::WebCookieJar* HTMLFrame::cookieJar(blink::WebLocalFrame* frame) {
338 // TODO(darin): Blink does not fallback to the Platform provided WebCookieJar.
339 // Either it should, as it once did, or we should find another solution here.
340 return blink::Platform::current()->cookieJar();
343 blink::WebNavigationPolicy HTMLFrame::decidePolicyForNavigation(
344 const NavigationPolicyInfo& info) {
345 // If we have extraData() it means we already have the url response
346 // (presumably because we are being called via Navigate()). In that case we
347 // can go ahead and navigate locally.
348 if (info.urlRequest.extraData()) {
349 DCHECK_EQ(blink::WebNavigationPolicyCurrentTab, info.defaultPolicy);
350 return blink::WebNavigationPolicyCurrentTab;
353 // about:blank is treated as the same origin and is always allowed for
354 // frames.
355 if (parent_ && info.urlRequest.url() == GURL(url::kAboutBlankURL) &&
356 info.defaultPolicy == blink::WebNavigationPolicyCurrentTab) {
357 return blink::WebNavigationPolicyCurrentTab;
360 // Ask the Frame to handle the navigation. By returning
361 // WebNavigationPolicyIgnore the load is suppressed.
362 mojo::URLRequestPtr url_request = mojo::URLRequest::From(info.urlRequest);
363 server_->RequestNavigate(
364 WebNavigationPolicyToNavigationTarget(info.defaultPolicy), id_,
365 url_request.Pass());
367 return blink::WebNavigationPolicyIgnore;
370 void HTMLFrame::didHandleOnloadEvents(blink::WebLocalFrame* frame) {
371 static bool recorded = false;
372 if (!recorded && startup_performance_data_collector_) {
373 startup_performance_data_collector_->SetFirstWebContentsMainFrameLoadTime(
374 base::Time::Now().ToInternalValue());
375 recorded = true;
379 void HTMLFrame::didAddMessageToConsole(const blink::WebConsoleMessage& message,
380 const blink::WebString& source_name,
381 unsigned source_line,
382 const blink::WebString& stack_trace) {
383 VLOG(1) << "[" << source_name.utf8() << "(" << source_line << ")] "
384 << message.text.utf8();
387 void HTMLFrame::didFinishLoad(blink::WebLocalFrame* frame) {
388 if (GetFirstAncestorWithDelegate() == this)
389 delegate_->OnFrameDidFinishLoad();
392 void HTMLFrame::didNavigateWithinPage(blink::WebLocalFrame* frame,
393 const blink::WebHistoryItem& history_item,
394 blink::WebHistoryCommitType commit_type) {
395 server_->DidNavigateLocally(history_item.urlString().utf8());
398 blink::WebGeolocationClient* HTMLFrame::geolocationClient() {
399 if (!geolocation_client_impl_)
400 geolocation_client_impl_.reset(new GeolocationClientImpl);
401 return geolocation_client_impl_.get();
404 blink::WebEncryptedMediaClient* HTMLFrame::encryptedMediaClient() {
405 return global_state()->media_factory()->GetEncryptedMediaClient();
408 void HTMLFrame::didStartLoading(bool to_different_document) {
409 server_->LoadingStateChanged(true, 0.0);
412 void HTMLFrame::didStopLoading() {
413 server_->LoadingStateChanged(false, 1.0);
416 void HTMLFrame::didChangeLoadProgress(double load_progress) {
417 server_->LoadingStateChanged(true, load_progress);
420 void HTMLFrame::dispatchLoad() {
421 // According to comments of WebFrameClient::dispatchLoad(), this should only
422 // be called when the parent frame is remote.
423 DCHECK(parent_ && !parent_->IsLocal());
424 server_->DispatchLoadEventToParent();
427 void HTMLFrame::didChangeName(blink::WebLocalFrame* frame,
428 const blink::WebString& name) {
429 state_.name = name;
430 server_->SetClientProperty(kPropertyFrameName,
431 FrameNameToClientProperty(name));
434 void HTMLFrame::didCommitProvisionalLoad(
435 blink::WebLocalFrame* frame,
436 const blink::WebHistoryItem& item,
437 blink::WebHistoryCommitType commit_type) {
438 state_.origin = FrameOrigin(frame);
439 server_->SetClientProperty(kPropertyFrameOrigin,
440 FrameOriginToClientProperty(frame));
442 // TODO(erg): We need to pass way more information from here through to the
443 // other side. See FrameHostMsg_DidCommitProvisionalLoad_Params. It is a grab
444 // bag of everything and it looks like a combination of
445 // NavigatorImpl::DidNavigate and
446 // NavigationControllerImpl::RendererDidNavigate use everything passed
447 // through.
448 server_->DidCommitProvisionalLoad();
451 void HTMLFrame::didReceiveTitle(blink::WebLocalFrame* frame,
452 const blink::WebString& title,
453 blink::WebTextDirection direction) {
454 // TODO(beng): handle |direction|.
455 mojo::String formatted;
456 if (!title.isNull()) {
457 formatted =
458 mojo::String::From(base::string16(title).substr(0, kMaxTitleChars));
460 server_->TitleChanged(formatted);
463 void HTMLFrame::Bind(
464 web_view::mojom::FramePtr frame,
465 mojo::InterfaceRequest<web_view::mojom::FrameClient> frame_client_request) {
466 DCHECK(IsLocal());
467 server_ = frame.Pass();
468 server_.set_connection_error_handler(
469 base::Bind(&HTMLFrame::Close, base::Unretained(this)));
470 frame_client_binding_.reset(new mojo::Binding<web_view::mojom::FrameClient>(
471 this, frame_client_request.Pass()));
474 void HTMLFrame::SetValueFromClientProperty(const std::string& name,
475 mojo::Array<uint8_t> new_data) {
476 if (IsLocal())
477 return;
479 // Only the name and origin dynamically change.
480 if (name == kPropertyFrameOrigin) {
481 state_.origin = FrameOriginFromClientProperty(new_data);
482 web_frame_->toWebRemoteFrame()->setReplicatedOrigin(state_.origin);
483 } else if (name == kPropertyFrameName) {
484 state_.name = FrameNameFromClientProperty(new_data);
485 web_frame_->toWebRemoteFrame()->setReplicatedName(state_.name);
489 HTMLFrame* HTMLFrame::GetFirstAncestorWithDelegate() {
490 HTMLFrame* frame = this;
491 while (frame && !frame->delegate_)
492 frame = frame->parent_;
493 return frame;
496 mojo::ApplicationImpl* HTMLFrame::GetApp() {
497 return GetFirstAncestorWithDelegate()->delegate_->GetApp();
500 web_view::mojom::Frame* HTMLFrame::GetServerFrame() {
501 // Prefer an ancestor with a server Frame.
502 for (HTMLFrame* frame = this; frame; frame = frame->parent_) {
503 if (frame->server_.get())
504 return frame->server_.get();
507 // No local root. This means we're a remote frame with no local frame
508 // ancestors. Use the server Frame from the local root of the
509 // HTMLFrameTreeManager.
510 return frame_tree_manager_->local_root_->server_.get();
513 void HTMLFrame::SetView(mus::View* view) {
514 if (view_)
515 view_->RemoveObserver(this);
516 view_ = view;
517 if (view_)
518 view_->AddObserver(this);
521 void HTMLFrame::CreateRootWebWidget() {
522 DCHECK(!html_widget_);
523 if (view_) {
524 HTMLWidgetRootLocal::CreateParams create_params(GetApp(), global_state(),
525 view_);
526 html_widget_.reset(
527 delegate_->GetHTMLFactory()->CreateHTMLWidgetRootLocal(&create_params));
528 } else {
529 html_widget_.reset(new HTMLWidgetRootRemote);
533 void HTMLFrame::CreateLocalRootWebWidget(blink::WebLocalFrame* local_frame) {
534 DCHECK(!html_widget_);
535 DCHECK(IsLocal());
536 html_widget_.reset(
537 new HTMLWidgetLocalRoot(GetApp(), global_state(), view_, local_frame));
540 void HTMLFrame::UpdateFocus() {
541 blink::WebWidget* web_widget = GetWebWidget();
542 if (!web_widget || !view_)
543 return;
544 const bool is_focused = view_ && view_->HasFocus();
545 web_widget->setFocus(is_focused);
546 if (web_widget->isWebView())
547 static_cast<blink::WebView*>(web_widget)->setIsActive(is_focused);
550 void HTMLFrame::SwapToRemote() {
551 DCHECK(IsLocal());
553 HTMLFrameDelegate* delegate = delegate_;
554 delegate_ = nullptr;
556 blink::WebRemoteFrame* remote_frame =
557 blink::WebRemoteFrame::create(state_.tree_scope, this);
558 remote_frame->initializeFromFrame(web_frame_->toWebLocalFrame());
559 // swap() ends up calling us back and we then close the frame, which deletes
560 // it.
561 web_frame_->swap(remote_frame);
562 // TODO(sky): this isn't quite right, but WebLayerImpl is temporary.
563 if (owned_view_) {
564 web_layer_.reset(
565 new WebLayerImpl(owned_view_->view(),
566 global_state()->device_pixel_ratio()));
568 remote_frame->setRemoteWebLayer(web_layer_.get());
569 remote_frame->setReplicatedName(state_.name);
570 remote_frame->setReplicatedOrigin(state_.origin);
571 remote_frame->setReplicatedSandboxFlags(state_.sandbox_flags);
572 // Tell the frame that it is actually loading. This prevents its parent
573 // from prematurely dispatching load event.
574 remote_frame->didStartLoading();
575 web_frame_ = remote_frame;
576 SetView(nullptr);
577 server_.reset();
578 frame_client_binding_.reset();
579 if (delegate)
580 delegate->OnFrameSwappedToRemote();
583 void HTMLFrame::SwapToLocal(
584 HTMLFrameDelegate* delegate,
585 mus::View* view,
586 const mojo::Map<mojo::String, mojo::Array<uint8_t>>& properties) {
587 CHECK(!IsLocal());
588 // It doesn't make sense for the root to swap to local.
589 CHECK(parent_);
590 delegate_ = delegate;
591 SetView(view);
592 SetReplicatedFrameStateFromClientProperties(properties, &state_);
593 blink::WebLocalFrame* local_web_frame =
594 blink::WebLocalFrame::create(state_.tree_scope, this);
595 local_web_frame->initializeToReplaceRemoteFrame(
596 web_frame_->toWebRemoteFrame(), state_.name, state_.sandbox_flags);
597 // The swap() ends up calling to frameDetached() and deleting the old.
598 web_frame_->swap(local_web_frame);
599 web_frame_ = local_web_frame;
601 web_layer_.reset();
604 void HTMLFrame::SwapDelegate(HTMLFrameDelegate* delegate) {
605 DCHECK(IsLocal());
606 HTMLFrameDelegate* old_delegate = delegate_;
607 delegate_ = delegate;
608 delegate->OnSwap(this, old_delegate);
611 HTMLFrame* HTMLFrame::FindFrameWithWebFrame(blink::WebFrame* web_frame) {
612 if (web_frame_ == web_frame)
613 return this;
614 for (HTMLFrame* child_frame : children_) {
615 HTMLFrame* result = child_frame->FindFrameWithWebFrame(web_frame);
616 if (result)
617 return result;
619 return nullptr;
622 void HTMLFrame::FrameDetachedImpl(blink::WebFrame* web_frame) {
623 DCHECK_EQ(web_frame_, web_frame);
625 while (!children_.empty()) {
626 HTMLFrame* child = children_.front();
627 child->Close();
628 DCHECK(children_.empty() || children_.front() != child);
631 if (web_frame->parent())
632 web_frame->parent()->removeChild(web_frame);
634 delete this;
637 void HTMLFrame::OnViewBoundsChanged(View* view,
638 const Rect& old_bounds,
639 const Rect& new_bounds) {
640 DCHECK_EQ(view, view_);
641 if (html_widget_)
642 html_widget_->OnViewBoundsChanged(view);
645 void HTMLFrame::OnViewDestroyed(View* view) {
646 DCHECK_EQ(view, view_);
647 view_->RemoveObserver(this);
648 view_ = nullptr;
649 Close();
652 void HTMLFrame::OnViewInputEvent(View* view, const mojo::EventPtr& event) {
653 if (event->pointer_data) {
654 // Blink expects coordintes to be in DIPs.
655 event->pointer_data->location->x /= global_state()->device_pixel_ratio();
656 event->pointer_data->location->y /= global_state()->device_pixel_ratio();
657 event->pointer_data->location->screen_x /=
658 global_state()->device_pixel_ratio();
659 event->pointer_data->location->screen_y /=
660 global_state()->device_pixel_ratio();
663 blink::WebWidget* web_widget = GetWebWidget();
665 if (!touch_handler_ && web_widget)
666 touch_handler_.reset(new TouchHandler(web_widget));
668 if (touch_handler_ && (event->action == mojo::EVENT_TYPE_POINTER_DOWN ||
669 event->action == mojo::EVENT_TYPE_POINTER_UP ||
670 event->action == mojo::EVENT_TYPE_POINTER_CANCEL ||
671 event->action == mojo::EVENT_TYPE_POINTER_MOVE) &&
672 event->pointer_data->kind == mojo::POINTER_KIND_TOUCH) {
673 touch_handler_->OnTouchEvent(*event);
674 return;
677 if (!web_widget)
678 return;
680 scoped_ptr<blink::WebInputEvent> web_event =
681 event.To<scoped_ptr<blink::WebInputEvent>>();
682 if (web_event)
683 web_widget->handleInputEvent(*web_event);
686 void HTMLFrame::OnViewFocusChanged(mus::View* gained_focus,
687 mus::View* lost_focus) {
688 UpdateFocus();
691 void HTMLFrame::OnConnect(web_view::mojom::FramePtr frame,
692 uint32_t change_id,
693 uint32_t view_id,
694 web_view::mojom::ViewConnectType view_connect_type,
695 mojo::Array<web_view::mojom::FrameDataPtr> frame_data,
696 const OnConnectCallback& callback) {
697 // This is called if this frame is created by way of OnCreatedFrame().
698 callback.Run();
701 void HTMLFrame::OnFrameAdded(uint32_t change_id,
702 web_view::mojom::FrameDataPtr frame_data) {
703 frame_tree_manager_->ProcessOnFrameAdded(this, change_id, frame_data.Pass());
706 void HTMLFrame::OnFrameRemoved(uint32_t change_id, uint32_t frame_id) {
707 frame_tree_manager_->ProcessOnFrameRemoved(this, change_id, frame_id);
710 void HTMLFrame::OnFrameClientPropertyChanged(uint32_t frame_id,
711 const mojo::String& name,
712 mojo::Array<uint8_t> new_value) {
713 frame_tree_manager_->ProcessOnFrameClientPropertyChanged(this, frame_id, name,
714 new_value.Pass());
717 void HTMLFrame::OnPostMessageEvent(uint32_t source_frame_id,
718 uint32_t target_frame_id,
719 HTMLMessageEventPtr serialized_event) {
720 NOTIMPLEMENTED(); // For message ports.
722 HTMLFrame* target = frame_tree_manager_->root_->FindFrame(target_frame_id);
723 HTMLFrame* source = frame_tree_manager_->root_->FindFrame(source_frame_id);
724 if (!target || !source) {
725 DVLOG(1) << "Invalid source or target for PostMessage";
726 return;
729 if (!target->IsLocal()) {
730 DVLOG(1) << "Target for PostMessage is not lot local";
731 return;
734 blink::WebLocalFrame* target_web_frame =
735 target->web_frame_->toWebLocalFrame();
737 blink::WebSerializedScriptValue serialized_script_value;
738 serialized_script_value = blink::WebSerializedScriptValue::fromString(
739 serialized_event->data.To<blink::WebString>());
741 blink::WebMessagePortChannelArray channels;
743 // Create an event with the message. The next-to-last parameter to
744 // initMessageEvent is the last event ID, which is not used with postMessage.
745 blink::WebDOMEvent event =
746 target_web_frame->document().createEvent("MessageEvent");
747 blink::WebDOMMessageEvent msg_event = event.to<blink::WebDOMMessageEvent>();
748 msg_event.initMessageEvent(
749 "message",
750 // |canBubble| and |cancellable| are always false
751 false, false, serialized_script_value,
752 serialized_event->source_origin.To<blink::WebString>(),
753 source->web_frame_, target_web_frame->document(), "", channels);
755 // We must pass in the target_origin to do the security check on this side,
756 // since it may have changed since the original postMessage call was made.
757 blink::WebSecurityOrigin target_origin;
758 if (!serialized_event->target_origin.is_null()) {
759 target_origin = blink::WebSecurityOrigin::createFromString(
760 serialized_event->target_origin.To<blink::WebString>());
762 target_web_frame->dispatchMessageEventWithOriginCheck(target_origin,
763 msg_event);
766 void HTMLFrame::OnWillNavigate() {
767 if (IsLocal() && this != frame_tree_manager_->local_root_)
768 SwapToRemote();
771 void HTMLFrame::OnFrameLoadingStateChanged(uint32_t frame_id, bool loading) {
772 HTMLFrame* frame = frame_tree_manager_->root_->FindFrame(frame_id);
773 // TODO(yzshen): (Apply to this method and the one below.) Is it possible that
774 // at this point the frame is already hosting a different document?
775 if (frame && !frame->IsLocal()) {
776 if (loading)
777 frame->web_frame_->toWebRemoteFrame()->didStartLoading();
778 else
779 frame->web_frame_->toWebRemoteFrame()->didStopLoading();
783 void HTMLFrame::OnDispatchFrameLoadEvent(uint32_t frame_id) {
784 HTMLFrame* frame = frame_tree_manager_->root_->FindFrame(frame_id);
785 if (frame && !frame->IsLocal())
786 frame->web_frame_->toWebRemoteFrame()->DispatchLoadEventForFrameOwner();
789 void HTMLFrame::frameDetached(blink::WebRemoteFrameClient::DetachType type) {
790 if (type == blink::WebRemoteFrameClient::DetachType::Swap) {
791 web_frame_->close();
792 return;
795 DCHECK(type == blink::WebRemoteFrameClient::DetachType::Remove);
796 FrameDetachedImpl(web_frame_);
799 void HTMLFrame::postMessageEvent(blink::WebLocalFrame* source_web_frame,
800 blink::WebRemoteFrame* target_web_frame,
801 blink::WebSecurityOrigin target_origin,
802 blink::WebDOMMessageEvent web_event) {
803 NOTIMPLEMENTED(); // message_ports aren't implemented yet.
805 HTMLFrame* source_frame =
806 frame_tree_manager_->root_->FindFrameWithWebFrame(source_web_frame);
807 DCHECK(source_frame);
808 HTMLFrame* target_frame =
809 frame_tree_manager_->root_->FindFrameWithWebFrame(target_web_frame);
810 DCHECK(target_frame);
812 HTMLMessageEventPtr event(HTMLMessageEvent::New());
813 event->data = mojo::Array<uint8_t>::From(web_event.data().toString());
814 event->source_origin = mojo::String::From(web_event.origin());
815 if (!target_origin.isNull())
816 event->target_origin = mojo::String::From(target_origin.toString());
818 source_frame->server_->PostMessageEventToFrame(target_frame->id_,
819 event.Pass());
822 void HTMLFrame::initializeChildFrame(const blink::WebRect& frame_rect,
823 float scale_factor) {
824 // NOTE: |scale_factor| is always 1.
825 const gfx::Rect rect_in_dip(frame_rect.x, frame_rect.y, frame_rect.width,
826 frame_rect.height);
827 const gfx::Rect rect_in_pixels(gfx::ConvertRectToPixel(
828 global_state()->device_pixel_ratio(), rect_in_dip));
829 const mojo::RectPtr mojo_rect_in_pixels(mojo::Rect::From(rect_in_pixels));
830 view_->SetBounds(*mojo_rect_in_pixels);
833 void HTMLFrame::navigate(const blink::WebURLRequest& request,
834 bool should_replace_current_entry) {
835 // TODO: support |should_replace_current_entry|.
836 NOTIMPLEMENTED(); // for |should_replace_current_entry
837 mojo::URLRequestPtr url_request = mojo::URLRequest::From(request);
838 GetServerFrame()->RequestNavigate(
839 web_view::mojom::NAVIGATION_TARGET_TYPE_EXISTING_FRAME, id_,
840 url_request.Pass());
843 void HTMLFrame::reload(bool ignore_cache, bool is_client_redirect) {
844 NOTIMPLEMENTED();
847 void HTMLFrame::forwardInputEvent(const blink::WebInputEvent* event) {
848 NOTIMPLEMENTED();
851 } // namespace mojo