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/renderer/frame_impl.h"
6
7 #include "base/compiler_specific.h"
8
9 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
10 #if BUILDFLAG(IS_WIN)
11 #if defined(__clang__)
12 #pragma GCC diagnostic push
13 #pragma GCC diagnostic error "-Wdeprecated-declarations"
14 #else
15 #pragma warning(push)
16 #pragma warning(default : 4996)
17 #endif
18 #endif
19
20 #include "libcef/common/app_manager.h"
21 #include "libcef/common/frame_util.h"
22 #include "libcef/common/net/http_header_utils.h"
23 #include "libcef/common/process_message_impl.h"
24 #include "libcef/common/request_impl.h"
25 #include "libcef/common/string_util.h"
26 #include "libcef/renderer/blink_glue.h"
27 #include "libcef/renderer/browser_impl.h"
28 #include "libcef/renderer/dom_document_impl.h"
29 #include "libcef/renderer/render_frame_util.h"
30 #include "libcef/renderer/render_urlrequest_impl.h"
31 #include "libcef/renderer/thread_util.h"
32 #include "libcef/renderer/v8_impl.h"
33
34 #include "base/strings/utf_string_conversions.h"
35 #include "content/public/renderer/render_view.h"
36 #include "content/renderer/render_frame_impl.h"
37 #include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
38 #include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
39 #include "third_party/blink/public/platform/web_data.h"
40 #include "third_party/blink/public/platform/web_string.h"
41 #include "third_party/blink/public/platform/web_url.h"
42 #include "third_party/blink/public/web/blink.h"
43 #include "third_party/blink/public/web/web_document.h"
44 #include "third_party/blink/public/web/web_document_loader.h"
45 #include "third_party/blink/public/web/web_frame_content_dumper.h"
46 #include "third_party/blink/public/web/web_local_frame.h"
47 #include "third_party/blink/public/web/web_navigation_control.h"
48 #include "third_party/blink/public/web/web_script_source.h"
49 #include "third_party/blink/public/web/web_view.h"
50
51 namespace {
52
53 // Maximum number of times to retry the browser connection.
54 constexpr size_t kConnectionRetryMaxCt = 3U;
55
56 // Length of time to wait before initiating a browser connection retry.
57 constexpr auto kConnectionRetryDelay = base::Seconds(1);
58
59 // Length of time to wait for the browser connection ACK before timing out.
60 constexpr auto kConnectionTimeout = base::Seconds(4);
61
62 } // namespace
63
CefFrameImpl(CefBrowserImpl * browser,blink::WebLocalFrame * frame,int64_t frame_id)64 CefFrameImpl::CefFrameImpl(CefBrowserImpl* browser,
65 blink::WebLocalFrame* frame,
66 int64_t frame_id)
67 : browser_(browser), frame_(frame), frame_id_(frame_id) {}
68
~CefFrameImpl()69 CefFrameImpl::~CefFrameImpl() {}
70
IsValid()71 bool CefFrameImpl::IsValid() {
72 CEF_REQUIRE_RT_RETURN(false);
73
74 return (frame_ != nullptr);
75 }
76
Undo()77 void CefFrameImpl::Undo() {
78 SendCommand("Undo");
79 }
80
Redo()81 void CefFrameImpl::Redo() {
82 SendCommand("Redo");
83 }
84
Cut()85 void CefFrameImpl::Cut() {
86 SendCommand("Cut");
87 }
88
Copy()89 void CefFrameImpl::Copy() {
90 SendCommand("Copy");
91 }
92
Paste()93 void CefFrameImpl::Paste() {
94 SendCommand("Paste");
95 }
96
Delete()97 void CefFrameImpl::Delete() {
98 SendCommand("Delete");
99 }
100
SelectAll()101 void CefFrameImpl::SelectAll() {
102 SendCommand("SelectAll");
103 }
104
ViewSource()105 void CefFrameImpl::ViewSource() {
106 NOTREACHED() << "ViewSource cannot be called from the renderer process";
107 }
108
GetSource(CefRefPtr<CefStringVisitor> visitor)109 void CefFrameImpl::GetSource(CefRefPtr<CefStringVisitor> visitor) {
110 CEF_REQUIRE_RT_RETURN_VOID();
111 if (frame_) {
112 CefString content;
113 string_util::GetCefString(blink_glue::DumpDocumentMarkup(frame_), content);
114 visitor->Visit(content);
115 }
116 }
117
GetText(CefRefPtr<CefStringVisitor> visitor)118 void CefFrameImpl::GetText(CefRefPtr<CefStringVisitor> visitor) {
119 CEF_REQUIRE_RT_RETURN_VOID();
120 if (frame_) {
121 CefString content;
122 string_util::GetCefString(blink_glue::DumpDocumentText(frame_), content);
123 visitor->Visit(content);
124 }
125 }
126
LoadRequest(CefRefPtr<CefRequest> request)127 void CefFrameImpl::LoadRequest(CefRefPtr<CefRequest> request) {
128 CEF_REQUIRE_RT_RETURN_VOID();
129
130 if (!frame_)
131 return;
132
133 auto params = cef::mojom::RequestParams::New();
134 static_cast<CefRequestImpl*>(request.get())->Get(params);
135 LoadRequest(std::move(params));
136 }
137
LoadURL(const CefString & url)138 void CefFrameImpl::LoadURL(const CefString& url) {
139 CEF_REQUIRE_RT_RETURN_VOID();
140
141 if (!frame_)
142 return;
143
144 auto params = cef::mojom::RequestParams::New();
145 params->url = GURL(url.ToString());
146 params->method = "GET";
147 LoadRequest(std::move(params));
148 }
149
ExecuteJavaScript(const CefString & jsCode,const CefString & scriptUrl,int startLine)150 void CefFrameImpl::ExecuteJavaScript(const CefString& jsCode,
151 const CefString& scriptUrl,
152 int startLine) {
153 SendJavaScript(jsCode, scriptUrl, startLine);
154 }
155
IsMain()156 bool CefFrameImpl::IsMain() {
157 CEF_REQUIRE_RT_RETURN(false);
158
159 if (frame_)
160 return (frame_->Parent() == nullptr);
161 return false;
162 }
163
IsFocused()164 bool CefFrameImpl::IsFocused() {
165 CEF_REQUIRE_RT_RETURN(false);
166
167 if (frame_ && frame_->View())
168 return (frame_->View()->FocusedFrame() == frame_);
169 return false;
170 }
171
GetName()172 CefString CefFrameImpl::GetName() {
173 CefString name;
174 CEF_REQUIRE_RT_RETURN(name);
175
176 if (frame_)
177 name = render_frame_util::GetName(frame_);
178 return name;
179 }
180
GetIdentifier()181 int64 CefFrameImpl::GetIdentifier() {
182 CEF_REQUIRE_RT_RETURN(0);
183
184 return frame_id_;
185 }
186
GetParent()187 CefRefPtr<CefFrame> CefFrameImpl::GetParent() {
188 CEF_REQUIRE_RT_RETURN(nullptr);
189
190 if (frame_) {
191 blink::WebFrame* parent = frame_->Parent();
192 if (parent && parent->IsWebLocalFrame())
193 return browser_->GetWebFrameImpl(parent->ToWebLocalFrame()).get();
194 }
195
196 return nullptr;
197 }
198
GetURL()199 CefString CefFrameImpl::GetURL() {
200 CefString url;
201 CEF_REQUIRE_RT_RETURN(url);
202
203 if (frame_) {
204 GURL gurl = frame_->GetDocument().Url();
205 url = gurl.spec();
206 }
207 return url;
208 }
209
GetBrowser()210 CefRefPtr<CefBrowser> CefFrameImpl::GetBrowser() {
211 CEF_REQUIRE_RT_RETURN(nullptr);
212
213 return browser_;
214 }
215
GetV8Context()216 CefRefPtr<CefV8Context> CefFrameImpl::GetV8Context() {
217 CEF_REQUIRE_RT_RETURN(nullptr);
218
219 if (frame_) {
220 v8::Isolate* isolate = blink::MainThreadIsolate();
221 v8::HandleScope handle_scope(isolate);
222 return new CefV8ContextImpl(isolate, frame_->MainWorldScriptContext());
223 } else {
224 return nullptr;
225 }
226 }
227
VisitDOM(CefRefPtr<CefDOMVisitor> visitor)228 void CefFrameImpl::VisitDOM(CefRefPtr<CefDOMVisitor> visitor) {
229 CEF_REQUIRE_RT_RETURN_VOID();
230
231 if (!frame_)
232 return;
233
234 // Create a CefDOMDocumentImpl object that is valid only for the scope of this
235 // method.
236 CefRefPtr<CefDOMDocumentImpl> documentImpl;
237 const blink::WebDocument& document = frame_->GetDocument();
238 if (!document.IsNull())
239 documentImpl = new CefDOMDocumentImpl(browser_, frame_);
240
241 visitor->Visit(documentImpl.get());
242
243 if (documentImpl.get())
244 documentImpl->Detach();
245 }
246
CreateURLRequest(CefRefPtr<CefRequest> request,CefRefPtr<CefURLRequestClient> client)247 CefRefPtr<CefURLRequest> CefFrameImpl::CreateURLRequest(
248 CefRefPtr<CefRequest> request,
249 CefRefPtr<CefURLRequestClient> client) {
250 CEF_REQUIRE_RT_RETURN(nullptr);
251
252 if (!request || !client || !frame_)
253 return nullptr;
254
255 CefRefPtr<CefRenderURLRequest> impl =
256 new CefRenderURLRequest(this, request, client);
257 if (impl->Start())
258 return impl.get();
259 return nullptr;
260 }
261
SendProcessMessage(CefProcessId target_process,CefRefPtr<CefProcessMessage> message)262 void CefFrameImpl::SendProcessMessage(CefProcessId target_process,
263 CefRefPtr<CefProcessMessage> message) {
264 CEF_REQUIRE_RT_RETURN_VOID();
265 DCHECK_EQ(PID_BROWSER, target_process);
266 DCHECK(message && message->IsValid());
267 if (!message || !message->IsValid())
268 return;
269
270 SendToBrowserFrame(
271 __FUNCTION__,
272 base::BindOnce(
273 [](CefRefPtr<CefProcessMessage> message,
274 const BrowserFrameType& browser_frame) {
275 auto impl = static_cast<CefProcessMessageImpl*>(message.get());
276 browser_frame->SendMessage(impl->GetName(),
277 impl->TakeArgumentList());
278 },
279 message));
280 }
281
CreateURLLoader()282 std::unique_ptr<blink::WebURLLoader> CefFrameImpl::CreateURLLoader() {
283 CEF_REQUIRE_RT();
284 if (!frame_)
285 return nullptr;
286
287 if (!url_loader_factory_) {
288 auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
289 if (render_frame) {
290 url_loader_factory_ = render_frame->CreateURLLoaderFactory();
291 }
292 }
293 if (!url_loader_factory_)
294 return nullptr;
295
296 return url_loader_factory_->CreateURLLoader(
297 blink::WebURLRequest(),
298 blink_glue::CreateResourceLoadingTaskRunnerHandle(frame_),
299 blink_glue::CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle(frame_),
300 /*keep_alive_handle=*/mojo::NullRemote(),
301 blink::WebBackForwardCacheLoaderHelper());
302 }
303
304 std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
CreateResourceLoadInfoNotifierWrapper()305 CefFrameImpl::CreateResourceLoadInfoNotifierWrapper() {
306 CEF_REQUIRE_RT();
307 if (frame_) {
308 auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
309 if (render_frame)
310 return render_frame->CreateResourceLoadInfoNotifierWrapper();
311 }
312 return nullptr;
313 }
314
OnAttached()315 void CefFrameImpl::OnAttached() {
316 // Called indirectly from RenderFrameCreated.
317 ConnectBrowserFrame();
318 }
319
OnWasShown()320 void CefFrameImpl::OnWasShown() {
321 if (browser_connection_state_ == ConnectionState::DISCONNECTED) {
322 // Reconnect a frame that has exited the bfcache.
323 ConnectBrowserFrame();
324 }
325 }
326
OnDidFinishLoad()327 void CefFrameImpl::OnDidFinishLoad() {
328 // Ignore notifications from the embedded frame hosting a mime-type plugin.
329 // We'll eventually receive a notification from the owner frame.
330 if (blink_glue::HasPluginFrameOwner(frame_))
331 return;
332
333 blink::WebDocumentLoader* dl = frame_->GetDocumentLoader();
334 const int http_status_code = dl->GetResponse().HttpStatusCode();
335
336 SendToBrowserFrame(__FUNCTION__,
337 base::BindOnce(
338 [](const GURL& url, int http_status_code,
339 const BrowserFrameType& browser_frame) {
340 browser_frame->DidFinishFrameLoad(url,
341 http_status_code);
342 },
343 dl->GetUrl(), http_status_code));
344
345 CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
346 if (app) {
347 CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
348 if (handler) {
349 CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
350 if (load_handler) {
351 load_handler->OnLoadEnd(browser_, this, http_status_code);
352 }
353 }
354 }
355 }
356
OnDraggableRegionsChanged()357 void CefFrameImpl::OnDraggableRegionsChanged() {
358 // Match the behavior in ChromeRenderFrameObserver::DraggableRegionsChanged.
359 // Only the main frame is allowed to control draggable regions, to avoid other
360 // frames manipulate the regions in the browser process.
361 if (frame_->Parent() != nullptr)
362 return;
363
364 blink::WebVector<blink::WebDraggableRegion> webregions =
365 frame_->GetDocument().DraggableRegions();
366 std::vector<cef::mojom::DraggableRegionEntryPtr> regions;
367 if (!webregions.empty()) {
368 auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
369
370 regions.reserve(webregions.size());
371 for (const auto& webregion : webregions) {
372 auto region = cef::mojom::DraggableRegionEntry::New(webregion.bounds,
373 webregion.draggable);
374 render_frame->ConvertViewportToWindow(®ion->bounds);
375 regions.push_back(std::move(region));
376 }
377 }
378
379 using RegionsArg =
380 absl::optional<std::vector<cef::mojom::DraggableRegionEntryPtr>>;
381 RegionsArg regions_arg =
382 regions.empty() ? absl::nullopt : absl::make_optional(std::move(regions));
383
384 SendToBrowserFrame(
385 __FUNCTION__,
386 base::BindOnce(
387 [](RegionsArg regions_arg, const BrowserFrameType& browser_frame) {
388 browser_frame->UpdateDraggableRegions(std::move(regions_arg));
389 },
390 std::move(regions_arg)));
391 }
392
OnContextCreated()393 void CefFrameImpl::OnContextCreated() {
394 context_created_ = true;
395
396 CHECK(frame_);
397 while (!queued_context_actions_.empty()) {
398 auto& action = queued_context_actions_.front();
399 std::move(action.second).Run(frame_);
400 queued_context_actions_.pop();
401 }
402 }
403
OnDetached()404 void CefFrameImpl::OnDetached() {
405 // Called when this frame has been detached from the view. This *will* be
406 // called for child frames when a parent frame is detached.
407 // The browser may hold the last reference to |this|. Take a reference here to
408 // keep |this| alive until after this method returns.
409 CefRefPtr<CefFrameImpl> self = this;
410
411 frame_ = nullptr;
412
413 browser_->FrameDetached(frame_id_);
414
415 OnBrowserFrameDisconnect();
416
417 browser_ = nullptr;
418 url_loader_factory_.reset();
419
420 // In case we never attached.
421 while (!queued_browser_actions_.empty()) {
422 auto& action = queued_browser_actions_.front();
423 LOG(WARNING) << action.first << " sent to detached frame "
424 << frame_util::GetFrameDebugString(frame_id_)
425 << " will be ignored";
426 queued_browser_actions_.pop();
427 }
428
429 // In case we're destroyed without the context being created.
430 while (!queued_context_actions_.empty()) {
431 auto& action = queued_context_actions_.front();
432 LOG(WARNING) << action.first << " sent to detached frame "
433 << frame_util::GetFrameDebugString(frame_id_)
434 << " will be ignored";
435 queued_context_actions_.pop();
436 }
437 }
438
ExecuteOnLocalFrame(const std::string & function_name,LocalFrameAction action)439 void CefFrameImpl::ExecuteOnLocalFrame(const std::string& function_name,
440 LocalFrameAction action) {
441 CEF_REQUIRE_RT_RETURN_VOID();
442
443 if (!context_created_) {
444 queued_context_actions_.push(
445 std::make_pair(function_name, std::move(action)));
446 return;
447 }
448
449 if (frame_) {
450 std::move(action).Run(frame_);
451 } else {
452 LOG(WARNING) << function_name << " sent to detached frame "
453 << frame_util::GetFrameDebugString(frame_id_)
454 << " will be ignored";
455 }
456 }
457
ConnectBrowserFrame()458 void CefFrameImpl::ConnectBrowserFrame() {
459 DCHECK(browser_connection_state_ == ConnectionState::DISCONNECTED ||
460 browser_connection_state_ == ConnectionState::RECONNECT_PENDING);
461
462 // Don't attempt to connect an invalid or bfcache'd frame. If a bfcache'd
463 // frame returns to active status a reconnect will be triggered via
464 // OnWasShown().
465 if (!frame_ || blink_glue::IsInBackForwardCache(frame_)) {
466 browser_connection_state_ = ConnectionState::DISCONNECTED;
467 browser_connect_timer_.Stop();
468 LOG(INFO) << "Connection retry canceled for frame "
469 << frame_util::GetFrameDebugString(frame_id_);
470 return;
471 }
472
473 if (browser_connect_retry_ct_ > 0) {
474 LOG(INFO) << "Connection retry " << browser_connect_retry_ct_ << "/"
475 << kConnectionRetryMaxCt << " for frame "
476 << frame_util::GetFrameDebugString(frame_id_);
477 }
478
479 browser_connection_state_ = ConnectionState::CONNECTION_PENDING;
480 browser_connect_timer_.Start(FROM_HERE, kConnectionTimeout, this,
481 &CefFrameImpl::OnBrowserFrameTimeout);
482
483 auto& browser_frame = GetBrowserFrame(/*expect_acked=*/false);
484 CHECK(browser_frame);
485
486 // If the channel is working we should get a call to FrameAttachedAck().
487 // Otherwise, OnBrowserFrameDisconnect() should be called to retry the
488 // connection.
489 browser_frame->FrameAttached(receiver_.BindNewPipeAndPassRemote(),
490 browser_connect_retry_ct_ > 0);
491 receiver_.set_disconnect_handler(
492 base::BindOnce(&CefFrameImpl::OnBrowserFrameDisconnect, this));
493 }
494
GetBrowserFrame(bool expect_acked)495 const mojo::Remote<cef::mojom::BrowserFrame>& CefFrameImpl::GetBrowserFrame(
496 bool expect_acked) {
497 DCHECK_EQ(expect_acked,
498 browser_connection_state_ == ConnectionState::CONNECTION_ACKED);
499
500 if (!browser_frame_.is_bound()) {
501 auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
502 if (render_frame) {
503 // Triggers creation of a CefBrowserFrame in the browser process.
504 render_frame->GetBrowserInterfaceBroker()->GetInterface(
505 browser_frame_.BindNewPipeAndPassReceiver());
506 browser_frame_.set_disconnect_handler(
507 base::BindOnce(&CefFrameImpl::OnBrowserFrameDisconnect, this));
508 }
509 }
510 return browser_frame_;
511 }
512
OnBrowserFrameTimeout()513 void CefFrameImpl::OnBrowserFrameTimeout() {
514 LOG(ERROR) << "Connection timeout for frame "
515 << frame_util::GetFrameDebugString(frame_id_);
516 OnBrowserFrameDisconnect();
517 }
518
OnBrowserFrameDisconnect()519 void CefFrameImpl::OnBrowserFrameDisconnect() {
520 // Ignore multiple calls in close proximity (which may occur if both
521 // |browser_frame_| and |receiver_| disconnect). |frame_| will be nullptr
522 // when called from/after OnDetached().
523 if (frame_ &&
524 browser_connection_state_ == ConnectionState::RECONNECT_PENDING) {
525 return;
526 }
527
528 browser_frame_.reset();
529 receiver_.reset();
530 browser_connection_state_ = ConnectionState::DISCONNECTED;
531 browser_connect_timer_.Stop();
532
533 // Only retry if the frame is still valid.
534 if (frame_) {
535 if (browser_connect_retry_ct_++ < kConnectionRetryMaxCt) {
536 // Retry after a delay in case the frame is currently navigating, being
537 // destroyed, or entering the bfcache. In the navigation case the retry
538 // will likely succeed. In the destruction case the retry will be
539 // ignored/canceled due to OnDetached(). In the bfcache case the status
540 // may not be updated immediately, so we allow the reconnect timer to
541 // trigger and check the status in ConnectBrowserFrame() instead.
542 browser_connection_state_ = ConnectionState::RECONNECT_PENDING;
543 browser_connect_timer_.Start(FROM_HERE, kConnectionRetryDelay, this,
544 &CefFrameImpl::ConnectBrowserFrame);
545 } else {
546 // Trigger a crash in official builds.
547 LOG(FATAL) << "Connection retry failure for frame "
548 << frame_util::GetFrameDebugString(frame_id_);
549 }
550 }
551 }
552
SendToBrowserFrame(const std::string & function_name,BrowserFrameAction action)553 void CefFrameImpl::SendToBrowserFrame(const std::string& function_name,
554 BrowserFrameAction action) {
555 if (!frame_) {
556 // We've been detached.
557 LOG(WARNING) << function_name << " sent to detached frame "
558 << frame_util::GetFrameDebugString(frame_id_)
559 << " will be ignored";
560 return;
561 }
562
563 if (browser_connection_state_ != ConnectionState::CONNECTION_ACKED) {
564 // Queue actions until we're notified by the browser that it's ready to
565 // handle them.
566 queued_browser_actions_.push(
567 std::make_pair(function_name, std::move(action)));
568 return;
569 }
570
571 auto& browser_frame = GetBrowserFrame();
572 CHECK(browser_frame);
573
574 std::move(action).Run(browser_frame);
575 }
576
FrameAttachedAck()577 void CefFrameImpl::FrameAttachedAck() {
578 // Sent from the browser process in response to ConnectBrowserFrame() sending
579 // FrameAttached().
580 CHECK_EQ(ConnectionState::CONNECTION_PENDING, browser_connection_state_);
581 browser_connection_state_ = ConnectionState::CONNECTION_ACKED;
582 browser_connect_retry_ct_ = 0;
583 browser_connect_timer_.Stop();
584
585 auto& browser_frame = GetBrowserFrame();
586 CHECK(browser_frame);
587
588 while (!queued_browser_actions_.empty()) {
589 std::move(queued_browser_actions_.front().second).Run(browser_frame);
590 queued_browser_actions_.pop();
591 }
592 }
593
SendMessage(const std::string & name,base::Value arguments)594 void CefFrameImpl::SendMessage(const std::string& name, base::Value arguments) {
595 if (auto app = CefAppManager::Get()->GetApplication()) {
596 if (auto handler = app->GetRenderProcessHandler()) {
597 auto& list_value = base::Value::AsListValue(arguments);
598 CefRefPtr<CefProcessMessageImpl> message(new CefProcessMessageImpl(
599 name, std::move(const_cast<base::ListValue&>(list_value)),
600 /*read_only=*/true));
601 handler->OnProcessMessageReceived(browser_, this, PID_BROWSER,
602 message.get());
603 }
604 }
605 }
606
SendCommand(const std::string & command)607 void CefFrameImpl::SendCommand(const std::string& command) {
608 ExecuteOnLocalFrame(
609 __FUNCTION__,
610 base::BindOnce(
611 [](const std::string& command, blink::WebLocalFrame* frame) {
612 frame->ExecuteCommand(blink::WebString::FromUTF8(command));
613 },
614 command));
615 }
616
SendCommandWithResponse(const std::string & command,cef::mojom::RenderFrame::SendCommandWithResponseCallback callback)617 void CefFrameImpl::SendCommandWithResponse(
618 const std::string& command,
619 cef::mojom::RenderFrame::SendCommandWithResponseCallback callback) {
620 ExecuteOnLocalFrame(
621 __FUNCTION__,
622 base::BindOnce(
623 [](const std::string& command,
624 cef::mojom::RenderFrame::SendCommandWithResponseCallback callback,
625 blink::WebLocalFrame* frame) {
626 blink::WebString response;
627
628 if (base::LowerCaseEqualsASCII(command, "getsource")) {
629 response = blink_glue::DumpDocumentMarkup(frame);
630 } else if (base::LowerCaseEqualsASCII(command, "gettext")) {
631 response = blink_glue::DumpDocumentText(frame);
632 }
633
634 std::move(callback).Run(
635 string_util::CreateSharedMemoryRegion(response));
636 },
637 command, std::move(callback)));
638 }
639
SendJavaScript(const std::u16string & jsCode,const std::string & scriptUrl,int32_t startLine)640 void CefFrameImpl::SendJavaScript(const std::u16string& jsCode,
641 const std::string& scriptUrl,
642 int32_t startLine) {
643 ExecuteOnLocalFrame(
644 __FUNCTION__,
645 base::BindOnce(
646 [](const std::u16string& jsCode, const std::string& scriptUrl,
647 blink::WebLocalFrame* frame) {
648 frame->ExecuteScript(blink::WebScriptSource(
649 blink::WebString::FromUTF16(jsCode), GURL(scriptUrl)));
650 },
651 jsCode, scriptUrl));
652 }
653
LoadRequest(cef::mojom::RequestParamsPtr params)654 void CefFrameImpl::LoadRequest(cef::mojom::RequestParamsPtr params) {
655 ExecuteOnLocalFrame(
656 __FUNCTION__,
657 base::BindOnce(
658 [](cef::mojom::RequestParamsPtr params, blink::WebLocalFrame* frame) {
659 blink::WebURLRequest request;
660 CefRequestImpl::Get(params, request);
661 blink_glue::StartNavigation(frame, request);
662 },
663 std::move(params)));
664 }
665
DidStopLoading()666 void CefFrameImpl::DidStopLoading() {
667 // We should only receive this notification for the highest-level LocalFrame
668 // in this frame's in-process subtree. If there are multiple of these for
669 // the same browser then the other occurrences will be discarded in
670 // OnLoadingStateChange.
671 browser_->OnLoadingStateChange(false);
672
673 // Refresh draggable regions. Otherwise, we may not receive updated regions
674 // after navigation because LocalFrameView::UpdateDocumentAnnotatedRegion
675 // lacks sufficient context.
676 OnDraggableRegionsChanged();
677 }
678
MoveOrResizeStarted()679 void CefFrameImpl::MoveOrResizeStarted() {
680 if (frame_) {
681 auto web_view = frame_->View();
682 if (web_view)
683 web_view->CancelPagePopup();
684 }
685 }
686
687 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
688 #if BUILDFLAG(IS_WIN)
689 #if defined(__clang__)
690 #pragma GCC diagnostic pop
691 #else
692 #pragma warning(pop)
693 #endif
694 #endif
695