• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that can
3 // be found in the LICENSE file.
4 
5 #include "libcef/browser/frame_host_impl.h"
6 
7 #include "include/cef_request.h"
8 #include "include/cef_stream.h"
9 #include "include/cef_v8.h"
10 #include "include/test/cef_test_helpers.h"
11 #include "libcef/browser/browser_host_base.h"
12 #include "libcef/browser/net_service/browser_urlrequest_impl.h"
13 #include "libcef/common/frame_util.h"
14 #include "libcef/common/net/url_util.h"
15 #include "libcef/common/process_message_impl.h"
16 #include "libcef/common/request_impl.h"
17 #include "libcef/common/string_util.h"
18 #include "libcef/common/task_runner_impl.h"
19 
20 #include "content/browser/renderer_host/frame_tree_node.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "services/service_manager/public/cpp/interface_provider.h"
24 
25 namespace {
26 
StringVisitCallback(CefRefPtr<CefStringVisitor> visitor,base::ReadOnlySharedMemoryRegion response)27 void StringVisitCallback(CefRefPtr<CefStringVisitor> visitor,
28                          base::ReadOnlySharedMemoryRegion response) {
29   string_util::ExecuteWithScopedCefString(
30       std::move(response),
31       base::BindOnce([](CefRefPtr<CefStringVisitor> visitor,
32                         const CefString& str) { visitor->Visit(str); },
33                      visitor));
34 }
35 
ViewTextCallback(CefRefPtr<CefFrameHostImpl> frame,base::ReadOnlySharedMemoryRegion response)36 void ViewTextCallback(CefRefPtr<CefFrameHostImpl> frame,
37                       base::ReadOnlySharedMemoryRegion response) {
38   if (auto browser = frame->GetBrowser()) {
39     string_util::ExecuteWithScopedCefString(
40         std::move(response),
41         base::BindOnce(
42             [](CefRefPtr<CefBrowser> browser, const CefString& str) {
43               static_cast<CefBrowserHostBase*>(browser.get())->ViewText(str);
44             },
45             browser));
46   }
47 }
48 
49 }  // namespace
50 
CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,int64_t parent_frame_id)51 CefFrameHostImpl::CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
52                                    int64_t parent_frame_id)
53     : is_main_frame_(false),
54       frame_id_(kInvalidFrameId),
55       browser_info_(browser_info),
56       is_focused_(is_main_frame_),  // The main frame always starts focused.
57       parent_frame_id_(parent_frame_id) {
58 #if DCHECK_IS_ON()
59   DCHECK(browser_info_);
60   if (is_main_frame_) {
61     DCHECK_EQ(parent_frame_id_, kInvalidFrameId);
62   } else {
63     DCHECK_GT(parent_frame_id_, 0);
64   }
65 #endif
66 }
67 
CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,content::RenderFrameHost * render_frame_host)68 CefFrameHostImpl::CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
69                                    content::RenderFrameHost* render_frame_host)
70     : is_main_frame_(render_frame_host->GetParent() == nullptr),
71       frame_id_(frame_util::MakeFrameId(render_frame_host->GetGlobalId())),
72       browser_info_(browser_info),
73       is_focused_(is_main_frame_),  // The main frame always starts focused.
74       url_(render_frame_host->GetLastCommittedURL().spec()),
75       name_(render_frame_host->GetFrameName()),
76       parent_frame_id_(
77           is_main_frame_ ? kInvalidFrameId
78                          : frame_util::MakeFrameId(
79                                render_frame_host->GetParent()->GetGlobalId())),
80       render_frame_host_(render_frame_host) {
81   DCHECK(browser_info_);
82 }
83 
~CefFrameHostImpl()84 CefFrameHostImpl::~CefFrameHostImpl() {
85   // Should have been Detached if not temporary.
86   DCHECK(is_temporary() || !browser_info_);
87   DCHECK(!render_frame_host_);
88 }
89 
IsValid()90 bool CefFrameHostImpl::IsValid() {
91   return !!GetBrowserHostBase();
92 }
93 
Undo()94 void CefFrameHostImpl::Undo() {
95   SendCommand("Undo");
96 }
97 
Redo()98 void CefFrameHostImpl::Redo() {
99   SendCommand("Redo");
100 }
101 
Cut()102 void CefFrameHostImpl::Cut() {
103   SendCommand("Cut");
104 }
105 
Copy()106 void CefFrameHostImpl::Copy() {
107   SendCommand("Copy");
108 }
109 
Paste()110 void CefFrameHostImpl::Paste() {
111   SendCommand("Paste");
112 }
113 
Delete()114 void CefFrameHostImpl::Delete() {
115   SendCommand("Delete");
116 }
117 
SelectAll()118 void CefFrameHostImpl::SelectAll() {
119   SendCommand("SelectAll");
120 }
121 
ViewSource()122 void CefFrameHostImpl::ViewSource() {
123   SendCommandWithResponse(
124       "GetSource",
125       base::BindOnce(&ViewTextCallback, CefRefPtr<CefFrameHostImpl>(this)));
126 }
127 
GetSource(CefRefPtr<CefStringVisitor> visitor)128 void CefFrameHostImpl::GetSource(CefRefPtr<CefStringVisitor> visitor) {
129   SendCommandWithResponse("GetSource",
130                           base::BindOnce(&StringVisitCallback, visitor));
131 }
132 
GetText(CefRefPtr<CefStringVisitor> visitor)133 void CefFrameHostImpl::GetText(CefRefPtr<CefStringVisitor> visitor) {
134   SendCommandWithResponse("GetText",
135                           base::BindOnce(&StringVisitCallback, visitor));
136 }
137 
LoadRequest(CefRefPtr<CefRequest> request)138 void CefFrameHostImpl::LoadRequest(CefRefPtr<CefRequest> request) {
139   auto params = cef::mojom::RequestParams::New();
140   static_cast<CefRequestImpl*>(request.get())->Get(params);
141   LoadRequest(std::move(params));
142 }
143 
LoadURL(const CefString & url)144 void CefFrameHostImpl::LoadURL(const CefString& url) {
145   LoadURLWithExtras(url, content::Referrer(), kPageTransitionExplicit,
146                     std::string());
147 }
148 
ExecuteJavaScript(const CefString & jsCode,const CefString & scriptUrl,int startLine)149 void CefFrameHostImpl::ExecuteJavaScript(const CefString& jsCode,
150                                          const CefString& scriptUrl,
151                                          int startLine) {
152   SendJavaScript(jsCode, scriptUrl, startLine);
153 }
154 
IsMain()155 bool CefFrameHostImpl::IsMain() {
156   return is_main_frame_;
157 }
158 
IsFocused()159 bool CefFrameHostImpl::IsFocused() {
160   base::AutoLock lock_scope(state_lock_);
161   return is_focused_;
162 }
163 
GetName()164 CefString CefFrameHostImpl::GetName() {
165   base::AutoLock lock_scope(state_lock_);
166   return name_;
167 }
168 
GetIdentifier()169 int64 CefFrameHostImpl::GetIdentifier() {
170   base::AutoLock lock_scope(state_lock_);
171   return frame_id_;
172 }
173 
GetParent()174 CefRefPtr<CefFrame> CefFrameHostImpl::GetParent() {
175   int64 parent_frame_id;
176 
177   {
178     base::AutoLock lock_scope(state_lock_);
179     if (is_main_frame_ || parent_frame_id_ == kInvalidFrameId)
180       return nullptr;
181     parent_frame_id = parent_frame_id_;
182   }
183 
184   auto browser = GetBrowserHostBase();
185   if (browser)
186     return browser->GetFrame(parent_frame_id);
187 
188   return nullptr;
189 }
190 
GetURL()191 CefString CefFrameHostImpl::GetURL() {
192   base::AutoLock lock_scope(state_lock_);
193   return url_;
194 }
195 
GetBrowser()196 CefRefPtr<CefBrowser> CefFrameHostImpl::GetBrowser() {
197   return GetBrowserHostBase().get();
198 }
199 
GetV8Context()200 CefRefPtr<CefV8Context> CefFrameHostImpl::GetV8Context() {
201   NOTREACHED() << "GetV8Context cannot be called from the browser process";
202   return nullptr;
203 }
204 
VisitDOM(CefRefPtr<CefDOMVisitor> visitor)205 void CefFrameHostImpl::VisitDOM(CefRefPtr<CefDOMVisitor> visitor) {
206   NOTREACHED() << "VisitDOM cannot be called from the browser process";
207 }
208 
CreateURLRequest(CefRefPtr<CefRequest> request,CefRefPtr<CefURLRequestClient> client)209 CefRefPtr<CefURLRequest> CefFrameHostImpl::CreateURLRequest(
210     CefRefPtr<CefRequest> request,
211     CefRefPtr<CefURLRequestClient> client) {
212   if (!request || !client)
213     return nullptr;
214 
215   if (!CefTaskRunnerImpl::GetCurrentTaskRunner()) {
216     NOTREACHED() << "called on invalid thread";
217     return nullptr;
218   }
219 
220   auto browser = GetBrowserHostBase();
221   if (!browser)
222     return nullptr;
223 
224   auto request_context = browser->request_context();
225 
226   CefRefPtr<CefBrowserURLRequest> impl =
227       new CefBrowserURLRequest(this, request, client, request_context);
228   if (impl->Start())
229     return impl.get();
230   return nullptr;
231 }
232 
SendProcessMessage(CefProcessId target_process,CefRefPtr<CefProcessMessage> message)233 void CefFrameHostImpl::SendProcessMessage(
234     CefProcessId target_process,
235     CefRefPtr<CefProcessMessage> message) {
236   DCHECK_EQ(PID_RENDERER, target_process);
237   DCHECK(message && message->IsValid());
238   if (!message || !message->IsValid())
239     return;
240 
241   // Invalidate the message object immediately by taking the argument list.
242   auto argument_list =
243       static_cast<CefProcessMessageImpl*>(message.get())->TakeArgumentList();
244 
245   SendToRenderFrame(__FUNCTION__,
246                     base::BindOnce(
247                         [](const CefString& name, base::ListValue argument_list,
248                            const RenderFrameType& render_frame) {
249                           render_frame->SendMessage(name,
250                                                     std::move(argument_list));
251                         },
252                         message->GetName(), std::move(argument_list)));
253 }
254 
SetFocused(bool focused)255 void CefFrameHostImpl::SetFocused(bool focused) {
256   base::AutoLock lock_scope(state_lock_);
257   is_focused_ = focused;
258 }
259 
RefreshAttributes()260 void CefFrameHostImpl::RefreshAttributes() {
261   CEF_REQUIRE_UIT();
262 
263   base::AutoLock lock_scope(state_lock_);
264   if (!render_frame_host_)
265     return;
266   url_ = render_frame_host_->GetLastCommittedURL().spec();
267 
268   // Use the assigned name if it is non-empty. This represents the name property
269   // on the frame DOM element. If the assigned name is empty, revert to the
270   // internal unique name. This matches the logic in render_frame_util::GetName.
271   name_ = render_frame_host_->GetFrameName();
272   if (name_.empty()) {
273     const auto node = content::FrameTreeNode::GloballyFindByID(
274         render_frame_host_->GetFrameTreeNodeId());
275     if (node) {
276       name_ = node->unique_name();
277     }
278   }
279 
280   if (!is_main_frame_) {
281     parent_frame_id_ =
282         frame_util::MakeFrameId(render_frame_host_->GetParent()->GetGlobalId());
283   }
284 }
285 
NotifyMoveOrResizeStarted()286 void CefFrameHostImpl::NotifyMoveOrResizeStarted() {
287   SendToRenderFrame(__FUNCTION__,
288                     base::BindOnce([](const RenderFrameType& render_frame) {
289                       render_frame->MoveOrResizeStarted();
290                     }));
291 }
292 
LoadRequest(cef::mojom::RequestParamsPtr params)293 void CefFrameHostImpl::LoadRequest(cef::mojom::RequestParamsPtr params) {
294   if (!url_util::FixupGURL(params->url))
295     return;
296 
297   SendToRenderFrame(__FUNCTION__,
298                     base::BindOnce(
299                         [](cef::mojom::RequestParamsPtr params,
300                            const RenderFrameType& render_frame) {
301                           render_frame->LoadRequest(std::move(params));
302                         },
303                         std::move(params)));
304 
305   auto browser = GetBrowserHostBase();
306   if (browser)
307     browser->OnSetFocus(FOCUS_SOURCE_NAVIGATION);
308 }
309 
LoadURLWithExtras(const std::string & url,const content::Referrer & referrer,ui::PageTransition transition,const std::string & extra_headers)310 void CefFrameHostImpl::LoadURLWithExtras(const std::string& url,
311                                          const content::Referrer& referrer,
312                                          ui::PageTransition transition,
313                                          const std::string& extra_headers) {
314   // Only known frame ids or kMainFrameId are supported.
315   const auto frame_id = GetFrameId();
316   if (frame_id < CefFrameHostImpl::kMainFrameId)
317     return;
318 
319   // Any necessary fixup will occur in LoadRequest.
320   GURL gurl = url_util::MakeGURL(url, /*fixup=*/false);
321 
322   if (frame_id == CefFrameHostImpl::kMainFrameId) {
323     // Load via the browser using NavigationController.
324     auto browser = GetBrowserHostBase();
325     if (browser) {
326       content::OpenURLParams params(
327           gurl, referrer, WindowOpenDisposition::CURRENT_TAB, transition,
328           /*is_renderer_initiated=*/false);
329       params.extra_headers = extra_headers;
330 
331       browser->LoadMainFrameURL(params);
332     }
333   } else {
334     auto params = cef::mojom::RequestParams::New();
335     params->url = gurl;
336     params->referrer =
337         blink::mojom::Referrer::New(referrer.url, referrer.policy);
338     params->headers = extra_headers;
339     LoadRequest(std::move(params));
340   }
341 }
342 
SendCommand(const std::string & command)343 void CefFrameHostImpl::SendCommand(const std::string& command) {
344   DCHECK(!command.empty());
345   SendToRenderFrame(__FUNCTION__, base::BindOnce(
346                                       [](const std::string& command,
347                                          const RenderFrameType& render_frame) {
348                                         render_frame->SendCommand(command);
349                                       },
350                                       command));
351 }
352 
SendCommandWithResponse(const std::string & command,cef::mojom::RenderFrame::SendCommandWithResponseCallback response_callback)353 void CefFrameHostImpl::SendCommandWithResponse(
354     const std::string& command,
355     cef::mojom::RenderFrame::SendCommandWithResponseCallback
356         response_callback) {
357   DCHECK(!command.empty());
358   SendToRenderFrame(
359       __FUNCTION__,
360       base::BindOnce(
361           [](const std::string& command,
362              cef::mojom::RenderFrame::SendCommandWithResponseCallback
363                  response_callback,
364              const RenderFrameType& render_frame) {
365             render_frame->SendCommandWithResponse(command,
366                                                   std::move(response_callback));
367           },
368           command, std::move(response_callback)));
369 }
370 
SendJavaScript(const std::u16string & jsCode,const std::string & scriptUrl,int startLine)371 void CefFrameHostImpl::SendJavaScript(const std::u16string& jsCode,
372                                       const std::string& scriptUrl,
373                                       int startLine) {
374   if (jsCode.empty())
375     return;
376   if (startLine <= 0) {
377     // A value of 0 is v8::Message::kNoLineNumberInfo in V8. There is code in
378     // V8 that will assert on that value (e.g. V8StackTraceImpl::Frame::Frame
379     // if a JS exception is thrown) so make sure |startLine| > 0.
380     startLine = 1;
381   }
382 
383   SendToRenderFrame(
384       __FUNCTION__,
385       base::BindOnce(
386           [](const std::u16string& jsCode, const std::string& scriptUrl,
387              int startLine, const RenderFrameType& render_frame) {
388             render_frame->SendJavaScript(jsCode, scriptUrl, startLine);
389           },
390           jsCode, scriptUrl, startLine));
391 }
392 
MaybeSendDidStopLoading()393 void CefFrameHostImpl::MaybeSendDidStopLoading() {
394   auto rfh = GetRenderFrameHost();
395   if (!rfh)
396     return;
397 
398   // We only want to notify for the highest-level LocalFrame in this frame's
399   // renderer process subtree. If this frame has a parent in the same process
400   // then the notification will be sent via the parent instead.
401   auto rfh_parent = rfh->GetParent();
402   if (rfh_parent && rfh_parent->GetProcess() == rfh->GetProcess()) {
403     return;
404   }
405 
406   SendToRenderFrame(__FUNCTION__,
407                     base::BindOnce([](const RenderFrameType& render_frame) {
408                       render_frame->DidStopLoading();
409                     }));
410 }
411 
ExecuteJavaScriptWithUserGestureForTests(const CefString & javascript)412 void CefFrameHostImpl::ExecuteJavaScriptWithUserGestureForTests(
413     const CefString& javascript) {
414   if (!CEF_CURRENTLY_ON_UIT()) {
415     CEF_POST_TASK(
416         CEF_UIT,
417         base::BindOnce(
418             &CefFrameHostImpl::ExecuteJavaScriptWithUserGestureForTests, this,
419             javascript));
420     return;
421   }
422 
423   content::RenderFrameHost* rfh = GetRenderFrameHost();
424   if (rfh)
425     rfh->ExecuteJavaScriptWithUserGestureForTests(javascript);
426 }
427 
GetRenderFrameHost() const428 content::RenderFrameHost* CefFrameHostImpl::GetRenderFrameHost() const {
429   CEF_REQUIRE_UIT();
430   return render_frame_host_;
431 }
432 
Detach()433 bool CefFrameHostImpl::Detach() {
434   CEF_REQUIRE_UIT();
435 
436   // May be called multiple times (e.g. from CefBrowserInfo SetMainFrame and
437   // RemoveFrame).
438   bool first_detach = false;
439 
440   // Should not be called for temporary frames.
441   DCHECK(!is_temporary());
442 
443   {
444     base::AutoLock lock_scope(state_lock_);
445     if (browser_info_) {
446       first_detach = true;
447       browser_info_ = nullptr;
448     }
449   }
450 
451   // In case we never attached, clean up.
452   while (!queued_renderer_actions_.empty()) {
453     queued_renderer_actions_.pop();
454   }
455 
456   render_frame_.reset();
457   render_frame_host_ = nullptr;
458 
459   return first_detach;
460 }
461 
MaybeReAttach(scoped_refptr<CefBrowserInfo> browser_info,content::RenderFrameHost * render_frame_host)462 void CefFrameHostImpl::MaybeReAttach(
463     scoped_refptr<CefBrowserInfo> browser_info,
464     content::RenderFrameHost* render_frame_host) {
465   CEF_REQUIRE_UIT();
466   if (render_frame_.is_bound() && render_frame_host_ == render_frame_host) {
467     // Nothing to do here.
468     return;
469   }
470 
471   // We expect that Detach() was called previously.
472   CHECK(!is_temporary());
473   CHECK(!render_frame_.is_bound());
474   CHECK(!render_frame_host_);
475 
476   // The RFH may change but the GlobalId should remain the same.
477   CHECK_EQ(frame_id_,
478            frame_util::MakeFrameId(render_frame_host->GetGlobalId()));
479 
480   {
481     base::AutoLock lock_scope(state_lock_);
482     browser_info_ = browser_info;
483   }
484 
485   render_frame_host_ = render_frame_host;
486   RefreshAttributes();
487 
488   // We expect a reconnect to be triggered via FrameAttached().
489 }
490 
491 // kMainFrameId must be -1 to align with renderer expectations.
492 const int64_t CefFrameHostImpl::kMainFrameId = -1;
493 const int64_t CefFrameHostImpl::kFocusedFrameId = -2;
494 const int64_t CefFrameHostImpl::kUnspecifiedFrameId = -3;
495 const int64_t CefFrameHostImpl::kInvalidFrameId = -4;
496 
497 // This equates to (TT_EXPLICIT | TT_DIRECT_LOAD_FLAG).
498 const ui::PageTransition CefFrameHostImpl::kPageTransitionExplicit =
499     static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_TYPED |
500                                     ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
501 
GetFrameId() const502 int64 CefFrameHostImpl::GetFrameId() const {
503   base::AutoLock lock_scope(state_lock_);
504   return is_main_frame_ ? kMainFrameId : frame_id_;
505 }
506 
GetBrowserInfo() const507 scoped_refptr<CefBrowserInfo> CefFrameHostImpl::GetBrowserInfo() const {
508   base::AutoLock lock_scope(state_lock_);
509   return browser_info_;
510 }
511 
GetBrowserHostBase() const512 CefRefPtr<CefBrowserHostBase> CefFrameHostImpl::GetBrowserHostBase() const {
513   if (auto browser_info = GetBrowserInfo())
514     return browser_info->browser();
515   return nullptr;
516 }
517 
SendToRenderFrame(const std::string & function_name,RenderFrameAction action)518 void CefFrameHostImpl::SendToRenderFrame(const std::string& function_name,
519                                          RenderFrameAction action) {
520   if (!CEF_CURRENTLY_ON_UIT()) {
521     CEF_POST_TASK(CEF_UIT,
522                   base::BindOnce(&CefFrameHostImpl::SendToRenderFrame, this,
523                                  function_name, std::move(action)));
524     return;
525   }
526 
527   if (is_temporary()) {
528     LOG(WARNING) << function_name
529                  << " sent to temporary subframe will be ignored.";
530     return;
531   } else if (!render_frame_host_) {
532     // We've been detached.
533     LOG(WARNING) << function_name << " sent to detached "
534                  << (is_main_frame_ ? "main" : "sub") << "frame "
535                  << frame_util::GetFrameDebugString(frame_id_)
536                  << " will be ignored";
537     return;
538   }
539 
540   if (!render_frame_.is_bound()) {
541     // Queue actions until we're notified by the renderer that it's ready to
542     // handle them.
543     queued_renderer_actions_.push(
544         std::make_pair(function_name, std::move(action)));
545     return;
546   }
547 
548   std::move(action).Run(render_frame_);
549 }
550 
OnRenderFrameDisconnect()551 void CefFrameHostImpl::OnRenderFrameDisconnect() {
552   CEF_REQUIRE_UIT();
553 
554   // Reconnect, if any, will be triggered via FrameAttached().
555   render_frame_.reset();
556 }
557 
SendMessage(const std::string & name,base::Value arguments)558 void CefFrameHostImpl::SendMessage(const std::string& name,
559                                    base::Value arguments) {
560   if (auto browser = GetBrowserHostBase()) {
561     if (auto client = browser->GetClient()) {
562       auto& list_value = base::Value::AsListValue(arguments);
563       CefRefPtr<CefProcessMessageImpl> message(new CefProcessMessageImpl(
564           name, std::move(const_cast<base::ListValue&>(list_value)),
565           /*read_only=*/true));
566       browser->GetClient()->OnProcessMessageReceived(
567           browser.get(), this, PID_RENDERER, message.get());
568     }
569   }
570 }
571 
FrameAttached(mojo::PendingRemote<cef::mojom::RenderFrame> render_frame_remote,bool reattached)572 void CefFrameHostImpl::FrameAttached(
573     mojo::PendingRemote<cef::mojom::RenderFrame> render_frame_remote,
574     bool reattached) {
575   CEF_REQUIRE_UIT();
576   CHECK(render_frame_remote);
577 
578   auto browser_info = GetBrowserInfo();
579   if (!browser_info) {
580     // Already Detached.
581     return;
582   }
583 
584   if (reattached) {
585     LOG(INFO) << (is_main_frame_ ? "main" : "sub") << "frame "
586               << frame_util::GetFrameDebugString(frame_id_)
587               << " has reconnected";
588   }
589 
590   render_frame_.Bind(std::move(render_frame_remote));
591   render_frame_.set_disconnect_handler(
592       base::BindOnce(&CefFrameHostImpl::OnRenderFrameDisconnect, this));
593 
594   // Notify the renderer process that it can start sending messages.
595   render_frame_->FrameAttachedAck();
596 
597   while (!queued_renderer_actions_.empty()) {
598     std::move(queued_renderer_actions_.front().second).Run(render_frame_);
599     queued_renderer_actions_.pop();
600   }
601 
602   browser_info->MaybeExecuteFrameNotification(base::BindOnce(
603       [](CefRefPtr<CefFrameHostImpl> self, bool reattached,
604          CefRefPtr<CefFrameHandler> handler) {
605         if (auto browser = self->GetBrowserHostBase()) {
606           handler->OnFrameAttached(browser, self, reattached);
607         }
608       },
609       CefRefPtr<CefFrameHostImpl>(this), reattached));
610 }
611 
DidFinishFrameLoad(const GURL & validated_url,int http_status_code)612 void CefFrameHostImpl::DidFinishFrameLoad(const GURL& validated_url,
613                                           int http_status_code) {
614   auto browser = GetBrowserHostBase();
615   if (browser)
616     browser->OnDidFinishLoad(this, validated_url, http_status_code);
617 }
618 
UpdateDraggableRegions(absl::optional<std::vector<cef::mojom::DraggableRegionEntryPtr>> regions)619 void CefFrameHostImpl::UpdateDraggableRegions(
620     absl::optional<std::vector<cef::mojom::DraggableRegionEntryPtr>> regions) {
621   auto browser = GetBrowserHostBase();
622   if (!browser)
623     return;
624 
625   std::vector<CefDraggableRegion> draggable_regions;
626   if (regions) {
627     draggable_regions.reserve(regions->size());
628 
629     for (const auto& region : *regions) {
630       const auto& rect = region->bounds;
631       const CefRect bounds(rect.x(), rect.y(), rect.width(), rect.height());
632       draggable_regions.push_back(
633           CefDraggableRegion(bounds, region->draggable));
634     }
635   }
636 
637   // Delegate to BrowserInfo so that current state is maintained with
638   // cross-origin navigation.
639   browser_info_->MaybeNotifyDraggableRegionsChanged(
640       browser, this, std::move(draggable_regions));
641 }
642 
CefExecuteJavaScriptWithUserGestureForTests(CefRefPtr<CefFrame> frame,const CefString & javascript)643 void CefExecuteJavaScriptWithUserGestureForTests(CefRefPtr<CefFrame> frame,
644                                                  const CefString& javascript) {
645   CefFrameHostImpl* impl = static_cast<CefFrameHostImpl*>(frame.get());
646   if (impl)
647     impl->ExecuteJavaScriptWithUserGestureForTests(javascript);
648 }
649