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