• 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/navigate_params.h"
13 #include "libcef/browser/net_service/browser_urlrequest_impl.h"
14 #include "libcef/common/cef_messages.h"
15 #include "libcef/common/frame_util.h"
16 #include "libcef/common/net/url_util.h"
17 #include "libcef/common/process_message_impl.h"
18 #include "libcef/common/request_impl.h"
19 #include "libcef/common/task_runner_impl.h"
20 
21 #include "content/browser/renderer_host/frame_tree_node.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/render_view_host.h"
24 
25 namespace {
26 
27 // Implementation of CommandResponseHandler for calling a CefStringVisitor.
28 class StringVisitHandler : public CefResponseManager::Handler {
29  public:
StringVisitHandler(CefRefPtr<CefStringVisitor> visitor)30   explicit StringVisitHandler(CefRefPtr<CefStringVisitor> visitor)
31       : visitor_(visitor) {}
OnResponse(const Cef_Response_Params & params)32   void OnResponse(const Cef_Response_Params& params) override {
33     visitor_->Visit(params.response);
34   }
35 
36  private:
37   CefRefPtr<CefStringVisitor> visitor_;
38 
39   IMPLEMENT_REFCOUNTING(StringVisitHandler);
40 };
41 
42 // Implementation of CommandResponseHandler for calling ViewText().
43 class ViewTextHandler : public CefResponseManager::Handler {
44  public:
ViewTextHandler(CefRefPtr<CefFrameHostImpl> frame)45   explicit ViewTextHandler(CefRefPtr<CefFrameHostImpl> frame) : frame_(frame) {}
OnResponse(const Cef_Response_Params & params)46   void OnResponse(const Cef_Response_Params& params) override {
47     CefRefPtr<CefBrowser> browser = frame_->GetBrowser();
48     if (browser.get()) {
49       static_cast<CefBrowserHostBase*>(browser.get())
50           ->ViewText(params.response);
51     }
52   }
53 
54  private:
55   CefRefPtr<CefFrameHostImpl> frame_;
56 
57   IMPLEMENT_REFCOUNTING(ViewTextHandler);
58 };
59 
60 }  // namespace
61 
CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,bool is_main_frame,int64_t parent_frame_id)62 CefFrameHostImpl::CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
63                                    bool is_main_frame,
64                                    int64_t parent_frame_id)
65     : is_main_frame_(is_main_frame),
66       frame_id_(kInvalidFrameId),
67       browser_info_(browser_info),
68       is_focused_(is_main_frame_),  // The main frame always starts focused.
69       parent_frame_id_(parent_frame_id) {
70 #if DCHECK_IS_ON()
71   DCHECK(browser_info_);
72   if (is_main_frame_) {
73     DCHECK_EQ(parent_frame_id_, kInvalidFrameId);
74   } else {
75     DCHECK_GT(parent_frame_id_, 0);
76   }
77 #endif
78 }
79 
CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,content::RenderFrameHost * render_frame_host)80 CefFrameHostImpl::CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
81                                    content::RenderFrameHost* render_frame_host)
82     : is_main_frame_(render_frame_host->GetParent() == nullptr),
83       frame_id_(MakeFrameId(render_frame_host)),
84       browser_info_(browser_info),
85       is_focused_(is_main_frame_),  // The main frame always starts focused.
86       url_(render_frame_host->GetLastCommittedURL().spec()),
87       name_(render_frame_host->GetFrameName()),
88       parent_frame_id_(is_main_frame_
89                            ? kInvalidFrameId
90                            : MakeFrameId(render_frame_host->GetParent())),
91       render_frame_host_(render_frame_host),
92       response_manager_(new CefResponseManager) {
93   DCHECK(browser_info_);
94 }
95 
~CefFrameHostImpl()96 CefFrameHostImpl::~CefFrameHostImpl() {}
97 
SetRenderFrameHost(content::RenderFrameHost * host)98 void CefFrameHostImpl::SetRenderFrameHost(content::RenderFrameHost* host) {
99   CEF_REQUIRE_UIT();
100 
101   base::AutoLock lock_scope(state_lock_);
102 
103   // We should not be detached.
104   CHECK(browser_info_);
105   // We should be the main frame.
106   CHECK(is_main_frame_);
107 
108   render_frame_host_ = host;
109   frame_id_ = MakeFrameId(host);
110   url_ = host->GetLastCommittedURL().spec();
111   name_ = host->GetFrameName();
112 
113   // Cancel any existing messages.
114   response_manager_.reset(new CefResponseManager);
115 }
116 
IsValid()117 bool CefFrameHostImpl::IsValid() {
118   return !!GetBrowserHostBase();
119 }
120 
Undo()121 void CefFrameHostImpl::Undo() {
122   SendCommand("Undo", nullptr);
123 }
124 
Redo()125 void CefFrameHostImpl::Redo() {
126   SendCommand("Redo", nullptr);
127 }
128 
Cut()129 void CefFrameHostImpl::Cut() {
130   SendCommand("Cut", nullptr);
131 }
132 
Copy()133 void CefFrameHostImpl::Copy() {
134   SendCommand("Copy", nullptr);
135 }
136 
Paste()137 void CefFrameHostImpl::Paste() {
138   SendCommand("Paste", nullptr);
139 }
140 
Delete()141 void CefFrameHostImpl::Delete() {
142   SendCommand("Delete", nullptr);
143 }
144 
SelectAll()145 void CefFrameHostImpl::SelectAll() {
146   SendCommand("SelectAll", nullptr);
147 }
148 
ViewSource()149 void CefFrameHostImpl::ViewSource() {
150   SendCommand("GetSource", new ViewTextHandler(this));
151 }
152 
GetSource(CefRefPtr<CefStringVisitor> visitor)153 void CefFrameHostImpl::GetSource(CefRefPtr<CefStringVisitor> visitor) {
154   SendCommand("GetSource", new StringVisitHandler(visitor));
155 }
156 
GetText(CefRefPtr<CefStringVisitor> visitor)157 void CefFrameHostImpl::GetText(CefRefPtr<CefStringVisitor> visitor) {
158   SendCommand("GetText", new StringVisitHandler(visitor));
159 }
160 
LoadRequest(CefRefPtr<CefRequest> request)161 void CefFrameHostImpl::LoadRequest(CefRefPtr<CefRequest> request) {
162   CefNavigateParams params(GURL(), kPageTransitionExplicit);
163   static_cast<CefRequestImpl*>(request.get())->Get(params);
164   Navigate(params);
165 }
166 
LoadURL(const CefString & url)167 void CefFrameHostImpl::LoadURL(const CefString& url) {
168   LoadURLWithExtras(url, content::Referrer(), kPageTransitionExplicit,
169                     std::string());
170 }
171 
ExecuteJavaScript(const CefString & jsCode,const CefString & scriptUrl,int startLine)172 void CefFrameHostImpl::ExecuteJavaScript(const CefString& jsCode,
173                                          const CefString& scriptUrl,
174                                          int startLine) {
175   SendJavaScript(jsCode, scriptUrl, startLine);
176 }
177 
IsMain()178 bool CefFrameHostImpl::IsMain() {
179   return is_main_frame_;
180 }
181 
IsFocused()182 bool CefFrameHostImpl::IsFocused() {
183   base::AutoLock lock_scope(state_lock_);
184   return is_focused_;
185 }
186 
GetName()187 CefString CefFrameHostImpl::GetName() {
188   base::AutoLock lock_scope(state_lock_);
189   return name_;
190 }
191 
GetIdentifier()192 int64 CefFrameHostImpl::GetIdentifier() {
193   base::AutoLock lock_scope(state_lock_);
194   return frame_id_;
195 }
196 
GetParent()197 CefRefPtr<CefFrame> CefFrameHostImpl::GetParent() {
198   int64 parent_frame_id;
199 
200   {
201     base::AutoLock lock_scope(state_lock_);
202     if (is_main_frame_ || parent_frame_id_ == kInvalidFrameId)
203       return nullptr;
204     parent_frame_id = parent_frame_id_;
205   }
206 
207   auto browser = GetBrowserHostBase();
208   if (browser)
209     return browser->GetFrame(parent_frame_id);
210 
211   return nullptr;
212 }
213 
GetURL()214 CefString CefFrameHostImpl::GetURL() {
215   base::AutoLock lock_scope(state_lock_);
216   return url_;
217 }
218 
GetBrowser()219 CefRefPtr<CefBrowser> CefFrameHostImpl::GetBrowser() {
220   return GetBrowserHostBase().get();
221 }
222 
GetV8Context()223 CefRefPtr<CefV8Context> CefFrameHostImpl::GetV8Context() {
224   NOTREACHED() << "GetV8Context cannot be called from the browser process";
225   return nullptr;
226 }
227 
VisitDOM(CefRefPtr<CefDOMVisitor> visitor)228 void CefFrameHostImpl::VisitDOM(CefRefPtr<CefDOMVisitor> visitor) {
229   NOTREACHED() << "VisitDOM cannot be called from the browser process";
230 }
231 
CreateURLRequest(CefRefPtr<CefRequest> request,CefRefPtr<CefURLRequestClient> client)232 CefRefPtr<CefURLRequest> CefFrameHostImpl::CreateURLRequest(
233     CefRefPtr<CefRequest> request,
234     CefRefPtr<CefURLRequestClient> client) {
235   if (!request || !client)
236     return nullptr;
237 
238   if (!CefTaskRunnerImpl::GetCurrentTaskRunner()) {
239     NOTREACHED() << "called on invalid thread";
240     return nullptr;
241   }
242 
243   auto browser = GetBrowserHostBase();
244   if (!browser)
245     return nullptr;
246 
247   auto request_context = browser->request_context();
248 
249   CefRefPtr<CefBrowserURLRequest> impl =
250       new CefBrowserURLRequest(this, request, client, request_context);
251   if (impl->Start())
252     return impl.get();
253   return nullptr;
254 }
255 
SendProcessMessage(CefProcessId target_process,CefRefPtr<CefProcessMessage> message)256 void CefFrameHostImpl::SendProcessMessage(
257     CefProcessId target_process,
258     CefRefPtr<CefProcessMessage> message) {
259   DCHECK_EQ(PID_RENDERER, target_process);
260   DCHECK(message.get());
261 
262   Cef_Request_Params params;
263   CefProcessMessageImpl* impl =
264       static_cast<CefProcessMessageImpl*>(message.get());
265   if (!impl->CopyTo(params))
266     return;
267 
268   DCHECK(!params.name.empty());
269 
270   params.user_initiated = true;
271   params.request_id = -1;
272   params.expect_response = false;
273 
274   Send(new CefMsg_Request(MSG_ROUTING_NONE, params));
275 }
276 
SetFocused(bool focused)277 void CefFrameHostImpl::SetFocused(bool focused) {
278   base::AutoLock lock_scope(state_lock_);
279   is_focused_ = focused;
280 }
281 
RefreshAttributes()282 void CefFrameHostImpl::RefreshAttributes() {
283   CEF_REQUIRE_UIT();
284 
285   base::AutoLock lock_scope(state_lock_);
286   if (!render_frame_host_)
287     return;
288   url_ = render_frame_host_->GetLastCommittedURL().spec();
289 
290   // Use the assigned name if it is non-empty. This represents the name property
291   // on the frame DOM element. If the assigned name is empty, revert to the
292   // internal unique name. This matches the logic in render_frame_util::GetName.
293   name_ = render_frame_host_->GetFrameName();
294   if (name_.empty()) {
295     const auto node = content::FrameTreeNode::GloballyFindByID(
296         render_frame_host_->GetFrameTreeNodeId());
297     if (node) {
298       name_ = node->unique_name();
299     }
300   }
301 
302   if (!is_main_frame_)
303     parent_frame_id_ = MakeFrameId(render_frame_host_->GetParent());
304 }
305 
NotifyMoveOrResizeStarted()306 void CefFrameHostImpl::NotifyMoveOrResizeStarted() {
307   Send(new CefMsg_MoveOrResizeStarted(MSG_ROUTING_NONE));
308 }
309 
Navigate(const CefNavigateParams & params)310 void CefFrameHostImpl::Navigate(const CefNavigateParams& params) {
311   CefMsg_LoadRequest_Params request;
312 
313   request.url = params.url;
314   if (!url_util::FixupGURL(request.url))
315     return;
316 
317   request.method = params.method;
318   request.referrer = params.referrer.url;
319   request.referrer_policy =
320       CefRequestImpl::BlinkReferrerPolicyToNetReferrerPolicy(
321           params.referrer.policy);
322   request.site_for_cookies = params.site_for_cookies;
323   request.headers = params.headers;
324   request.load_flags = params.load_flags;
325   request.upload_data = params.upload_data;
326 
327   Send(new CefMsg_LoadRequest(MSG_ROUTING_NONE, request));
328 
329   auto browser = GetBrowserHostBase();
330   if (browser)
331     browser->OnSetFocus(FOCUS_SOURCE_NAVIGATION);
332 }
333 
LoadURLWithExtras(const std::string & url,const content::Referrer & referrer,ui::PageTransition transition,const std::string & extra_headers)334 void CefFrameHostImpl::LoadURLWithExtras(const std::string& url,
335                                          const content::Referrer& referrer,
336                                          ui::PageTransition transition,
337                                          const std::string& extra_headers) {
338   // Only known frame ids or kMainFrameId are supported.
339   const auto frame_id = GetFrameId();
340   if (frame_id < CefFrameHostImpl::kMainFrameId)
341     return;
342 
343   // Any necessary fixup will occur in Navigate.
344   GURL gurl = url_util::MakeGURL(url, /*fixup=*/false);
345 
346   if (frame_id == CefFrameHostImpl::kMainFrameId) {
347     // Load via the browser using NavigationController.
348     auto browser = GetBrowserHostBase();
349     if (browser) {
350       content::OpenURLParams params(
351           gurl, referrer, WindowOpenDisposition::CURRENT_TAB, transition,
352           /*is_renderer_initiated=*/false);
353       params.extra_headers = extra_headers;
354 
355       browser->LoadMainFrameURL(params);
356     }
357   } else {
358     CefNavigateParams params(gurl, transition);
359     params.referrer = referrer;
360     params.headers = extra_headers;
361     Navigate(params);
362   }
363 }
364 
SendCommand(const std::string & command,CefRefPtr<CefResponseManager::Handler> responseHandler)365 void CefFrameHostImpl::SendCommand(
366     const std::string& command,
367     CefRefPtr<CefResponseManager::Handler> responseHandler) {
368   DCHECK(!command.empty());
369 
370   if (!CEF_CURRENTLY_ON_UIT()) {
371     CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefFrameHostImpl::SendCommand, this,
372                                           command, responseHandler));
373     return;
374   }
375 
376   // Only known frame ids or kMainFrameId are supported.
377   const auto frame_id = GetFrameId();
378   if (frame_id < CefFrameHostImpl::kMainFrameId)
379     return;
380 
381   if (!render_frame_host_ || !response_manager_) {
382     // detached frame has no response_manager_
383     return;
384   }
385 
386   TRACE_EVENT2("cef", "CefFrameHostImpl::SendCommand", "frame_id", frame_id,
387                "needsResponse", responseHandler.get() ? 1 : 0);
388   Cef_Request_Params params;
389   params.name = "execute-command";
390   params.user_initiated = false;
391 
392   if (responseHandler.get()) {
393     params.request_id = response_manager_->RegisterHandler(responseHandler);
394     params.expect_response = true;
395   } else {
396     params.request_id = -1;
397     params.expect_response = false;
398   }
399 
400   params.arguments.AppendString(command);
401 
402   Send(new CefMsg_Request(MSG_ROUTING_NONE, params));
403 }
404 
SendCode(bool is_javascript,const std::string & code,const std::string & script_url,int script_start_line,CefRefPtr<CefResponseManager::Handler> responseHandler)405 void CefFrameHostImpl::SendCode(
406     bool is_javascript,
407     const std::string& code,
408     const std::string& script_url,
409     int script_start_line,
410     CefRefPtr<CefResponseManager::Handler> responseHandler) {
411   DCHECK(!code.empty());
412   DCHECK_GE(script_start_line, 0);
413 
414   if (!CEF_CURRENTLY_ON_UIT()) {
415     CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefFrameHostImpl::SendCode, this,
416                                           is_javascript, code, script_url,
417                                           script_start_line, responseHandler));
418     return;
419   }
420 
421   // Only known frame ids or kMainFrameId are supported.
422   auto frame_id = GetFrameId();
423   if (frame_id < CefFrameHostImpl::kMainFrameId)
424     return;
425 
426   if (!render_frame_host_ || !response_manager_) {
427     // detached frame has no response_manager_
428     return;
429   }
430 
431   TRACE_EVENT2("cef", "CefFrameHostImpl::SendCommand", "frame_id", frame_id,
432                "needsResponse", responseHandler.get() ? 1 : 0);
433   Cef_Request_Params params;
434   params.name = "execute-code";
435   params.user_initiated = false;
436 
437   if (responseHandler.get()) {
438     params.request_id = response_manager_->RegisterHandler(responseHandler);
439     params.expect_response = true;
440   } else {
441     params.request_id = -1;
442     params.expect_response = false;
443   }
444 
445   params.arguments.AppendBoolean(is_javascript);
446   params.arguments.AppendString(code);
447   params.arguments.AppendString(script_url);
448   params.arguments.AppendInteger(script_start_line);
449 
450   Send(new CefMsg_Request(MSG_ROUTING_NONE, params));
451 }
452 
SendJavaScript(const std::string & jsCode,const std::string & scriptUrl,int startLine)453 void CefFrameHostImpl::SendJavaScript(const std::string& jsCode,
454                                       const std::string& scriptUrl,
455                                       int startLine) {
456   if (jsCode.empty())
457     return;
458   if (startLine <= 0) {
459     // A value of 0 is v8::Message::kNoLineNumberInfo in V8. There is code in
460     // V8 that will assert on that value (e.g. V8StackTraceImpl::Frame::Frame
461     // if a JS exception is thrown) so make sure |startLine| > 0.
462     startLine = 1;
463   }
464 
465   SendCode(true, jsCode, scriptUrl, startLine, nullptr);
466 }
467 
MaybeSendDidStopLoading()468 void CefFrameHostImpl::MaybeSendDidStopLoading() {
469   auto rfh = GetRenderFrameHost();
470   if (!rfh)
471     return;
472 
473   // We only want to notify for the highest-level LocalFrame in this frame's
474   // renderer process subtree. If this frame has a parent in the same process
475   // then the notification will be sent via the parent instead.
476   auto rfh_parent = rfh->GetParent();
477   if (rfh_parent && rfh_parent->GetProcess() == rfh->GetProcess()) {
478     return;
479   }
480 
481   Send(new CefMsg_DidStopLoading(MSG_ROUTING_NONE));
482 }
483 
OnMessageReceived(const IPC::Message & message)484 bool CefFrameHostImpl::OnMessageReceived(const IPC::Message& message) {
485   bool handled = true;
486   IPC_BEGIN_MESSAGE_MAP(CefFrameHostImpl, message)
487     IPC_MESSAGE_HANDLER(CefHostMsg_FrameAttached, OnAttached)
488     IPC_MESSAGE_HANDLER(CefHostMsg_DidFinishLoad, OnDidFinishLoad)
489     IPC_MESSAGE_HANDLER(CefHostMsg_UpdateDraggableRegions,
490                         OnUpdateDraggableRegions)
491     IPC_MESSAGE_HANDLER(CefHostMsg_Request, OnRequest)
492     IPC_MESSAGE_HANDLER(CefHostMsg_Response, OnResponse)
493     IPC_MESSAGE_HANDLER(CefHostMsg_ResponseAck, OnResponseAck)
494     IPC_MESSAGE_UNHANDLED(handled = false)
495   IPC_END_MESSAGE_MAP()
496   return handled;
497 }
498 
ExecuteJavaScriptWithUserGestureForTests(const CefString & javascript)499 void CefFrameHostImpl::ExecuteJavaScriptWithUserGestureForTests(
500     const CefString& javascript) {
501   if (!CEF_CURRENTLY_ON_UIT()) {
502     CEF_POST_TASK(
503         CEF_UIT,
504         base::BindOnce(
505             &CefFrameHostImpl::ExecuteJavaScriptWithUserGestureForTests, this,
506             javascript));
507     return;
508   }
509 
510   content::RenderFrameHost* rfh = GetRenderFrameHost();
511   if (rfh)
512     rfh->ExecuteJavaScriptWithUserGestureForTests(javascript);
513 }
514 
GetRenderFrameHost() const515 content::RenderFrameHost* CefFrameHostImpl::GetRenderFrameHost() const {
516   CEF_REQUIRE_UIT();
517   return render_frame_host_;
518 }
519 
Detach()520 void CefFrameHostImpl::Detach() {
521   CEF_REQUIRE_UIT();
522 
523   {
524     base::AutoLock lock_scope(state_lock_);
525     browser_info_ = nullptr;
526   }
527 
528   // In case we never attached, clean up.
529   while (!queued_messages_.empty()) {
530     queued_messages_.pop();
531   }
532 
533   response_manager_.reset();
534   render_frame_host_ = nullptr;
535 }
536 
537 // static
MakeFrameId(const content::RenderFrameHost * host)538 int64_t CefFrameHostImpl::MakeFrameId(const content::RenderFrameHost* host) {
539   CEF_REQUIRE_UIT();
540   auto host_nonconst = const_cast<content::RenderFrameHost*>(host);
541   return MakeFrameId(host_nonconst->GetProcess()->GetID(),
542                      host_nonconst->GetRoutingID());
543 }
544 
545 // static
MakeFrameId(int32_t render_process_id,int32_t render_routing_id)546 int64_t CefFrameHostImpl::MakeFrameId(int32_t render_process_id,
547                                       int32_t render_routing_id) {
548   return frame_util::MakeFrameId(render_process_id, render_routing_id);
549 }
550 
551 // kMainFrameId must be -1 to align with renderer expectations.
552 const int64_t CefFrameHostImpl::kMainFrameId = -1;
553 const int64_t CefFrameHostImpl::kFocusedFrameId = -2;
554 const int64_t CefFrameHostImpl::kUnspecifiedFrameId = -3;
555 const int64_t CefFrameHostImpl::kInvalidFrameId = -4;
556 
557 // This equates to (TT_EXPLICIT | TT_DIRECT_LOAD_FLAG).
558 const ui::PageTransition CefFrameHostImpl::kPageTransitionExplicit =
559     static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_TYPED |
560                                     ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
561 
GetFrameId() const562 int64 CefFrameHostImpl::GetFrameId() const {
563   base::AutoLock lock_scope(state_lock_);
564   return is_main_frame_ ? kMainFrameId : frame_id_;
565 }
566 
GetBrowserHostBase() const567 CefRefPtr<CefBrowserHostBase> CefFrameHostImpl::GetBrowserHostBase() const {
568   base::AutoLock lock_scope(state_lock_);
569   if (browser_info_)
570     return browser_info_->browser();
571   return nullptr;
572 }
573 
OnAttached()574 void CefFrameHostImpl::OnAttached() {
575   if (!is_attached_) {
576     is_attached_ = true;
577     while (!queued_messages_.empty()) {
578       Send(queued_messages_.front().release());
579       queued_messages_.pop();
580     }
581   }
582 }
583 
OnDidFinishLoad(const GURL & validated_url,int http_status_code)584 void CefFrameHostImpl::OnDidFinishLoad(const GURL& validated_url,
585                                        int http_status_code) {
586   auto browser = GetBrowserHostBase();
587   if (browser)
588     browser->OnDidFinishLoad(this, validated_url, http_status_code);
589 }
590 
OnUpdateDraggableRegions(const std::vector<Cef_DraggableRegion_Params> & regions)591 void CefFrameHostImpl::OnUpdateDraggableRegions(
592     const std::vector<Cef_DraggableRegion_Params>& regions) {
593   auto browser = GetBrowserHostBase();
594   if (!browser)
595     return;
596 
597   CefRefPtr<CefDragHandler> handler;
598   auto client = browser->GetClient();
599   if (client)
600     handler = client->GetDragHandler();
601   if (!handler)
602     return;
603 
604   std::vector<CefDraggableRegion> draggable_regions;
605   draggable_regions.reserve(regions.size());
606 
607   std::vector<Cef_DraggableRegion_Params>::const_iterator it = regions.begin();
608   for (; it != regions.end(); ++it) {
609     const gfx::Rect& rect(it->bounds);
610     const CefRect bounds(rect.x(), rect.y(), rect.width(), rect.height());
611     draggable_regions.push_back(CefDraggableRegion(bounds, it->draggable));
612   }
613 
614   handler->OnDraggableRegionsChanged(browser.get(), this, draggable_regions);
615 }
616 
OnRequest(const Cef_Request_Params & params)617 void CefFrameHostImpl::OnRequest(const Cef_Request_Params& params) {
618   CEF_REQUIRE_UIT();
619 
620   bool success = false;
621   std::string response;
622   bool expect_response_ack = false;
623 
624   if (params.user_initiated) {
625     auto browser = GetBrowserHostBase();
626     if (browser && browser->GetClient()) {
627       // Give the user a chance to handle the request.
628       CefRefPtr<CefProcessMessageImpl> message(new CefProcessMessageImpl(
629           const_cast<Cef_Request_Params*>(&params), false, true));
630       success = browser->GetClient()->OnProcessMessageReceived(
631           browser.get(), this, PID_RENDERER, message.get());
632       message->Detach(nullptr);
633     }
634   } else {
635     // Invalid request.
636     NOTREACHED();
637   }
638 
639   if (params.expect_response) {
640     DCHECK_GE(params.request_id, 0);
641 
642     // Send a response to the renderer.
643     Cef_Response_Params response_params;
644     response_params.request_id = params.request_id;
645     response_params.success = success;
646     response_params.response = response;
647     response_params.expect_response_ack = expect_response_ack;
648     Send(new CefMsg_Response(MSG_ROUTING_NONE, response_params));
649   }
650 }
651 
OnResponse(const Cef_Response_Params & params)652 void CefFrameHostImpl::OnResponse(const Cef_Response_Params& params) {
653   CEF_REQUIRE_UIT();
654 
655   response_manager_->RunHandler(params);
656   if (params.expect_response_ack)
657     Send(new CefMsg_ResponseAck(MSG_ROUTING_NONE, params.request_id));
658 }
659 
OnResponseAck(int request_id)660 void CefFrameHostImpl::OnResponseAck(int request_id) {
661   response_manager_->RunAckHandler(request_id);
662 }
663 
Send(IPC::Message * message)664 void CefFrameHostImpl::Send(IPC::Message* message) {
665   if (!CEF_CURRENTLY_ON_UIT()) {
666     CEF_POST_TASK(CEF_UIT,
667                   base::BindOnce(base::IgnoreResult(&CefFrameHostImpl::Send),
668                                  this, message));
669     return;
670   }
671 
672   if (!render_frame_host_) {
673     // Either we're a placeholder frame without a renderer representation, or
674     // we've been detached.
675     delete message;
676     return;
677   }
678 
679   if (!is_attached_) {
680     // Queue messages until we're notified by the renderer that it's ready to
681     // handle them.
682     queued_messages_.push(base::WrapUnique(message));
683     return;
684   }
685 
686   message->set_routing_id(render_frame_host_->GetRoutingID());
687   render_frame_host_->Send(message);
688 }
689 
CefExecuteJavaScriptWithUserGestureForTests(CefRefPtr<CefFrame> frame,const CefString & javascript)690 void CefExecuteJavaScriptWithUserGestureForTests(CefRefPtr<CefFrame> frame,
691                                                  const CefString& javascript) {
692   CefFrameHostImpl* impl = static_cast<CefFrameHostImpl*>(frame.get());
693   if (impl)
694     impl->ExecuteJavaScriptWithUserGestureForTests(javascript);
695 }
696