// Copyright (c) 2012 The Chromium Embedded Framework Authors. // Portions copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "libcef/renderer/blink_glue.h" #include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/platform/web_url_response.h" #include "third_party/blink/public/web/web_document.h" #include "third_party/blink/public/web/web_element.h" #include "third_party/blink/public/web/web_local_frame_client.h" #include "third_party/blink/public/web/web_node.h" #include "third_party/blink/public/web/web_view_client.h" #include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h" #include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/node.h" #include "third_party/blink/renderer/core/editing/serializers/serialization.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h" #include "third_party/blink/renderer/core/exported/web_view_impl.h" #include "third_party/blink/renderer/core/frame/frame_owner.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" #include "third_party/blink/renderer/core/loader/frame_load_request.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/script/classic_script.h" #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h" #include "third_party/blink/renderer/platform/bindings/v8_binding.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" #include "third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h" #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" #undef LOG #include "base/logging.h" namespace blink_glue { namespace { blink::ExecutionContext* GetExecutionContext(v8::Local context) { blink::LocalFrame* frame = blink::ToLocalFrameIfNotDetached(context); if (frame && frame->DomWindow()->CanExecuteScripts(blink::kAboutToExecuteScript)) { return frame->GetDocument()->GetExecutionContext(); } return nullptr; } } // namespace const int64_t kInvalidFrameId = -1; bool CanGoBack(blink::WebView* view) { if (!view) { return false; } return view->HistoryBackListCount() > 0; } bool CanGoForward(blink::WebView* view) { if (!view) { return false; } return view->HistoryForwardListCount() > 0; } void GoBack(blink::WebView* view) { if (!view) { return; } blink::WebFrame* main_frame = view->MainFrame(); if (main_frame && main_frame->IsWebLocalFrame()) { if (view->HistoryBackListCount() > 0) { blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*main_frame); blink::To(core_frame) ->GetLocalFrameHostRemote() .GoToEntryAtOffset(-1, /*has_user_gesture=*/true, absl::nullopt); } } } void GoForward(blink::WebView* view) { if (!view) { return; } blink::WebFrame* main_frame = view->MainFrame(); if (main_frame && main_frame->IsWebLocalFrame()) { if (view->HistoryForwardListCount() > 0) { blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*main_frame); blink::To(core_frame) ->GetLocalFrameHostRemote() .GoToEntryAtOffset(1, /*has_user_gesture=*/true, absl::nullopt); } } } bool IsInBackForwardCache(blink::WebLocalFrame* frame) { blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*frame); return blink::To(core_frame) ->GetPage() ->GetPageScheduler() ->IsInBackForwardCache(); } blink::WebString DumpDocumentText(blink::WebLocalFrame* frame) { // We use the document element's text instead of the body text here because // not all documents have a body, such as XML documents. blink::WebElement document_element = frame->GetDocument().DocumentElement(); if (document_element.IsNull()) { return blink::WebString(); } blink::Element* web_element = document_element.Unwrap(); return blink::WebString(web_element->innerText()); } blink::WebString DumpDocumentMarkup(blink::WebLocalFrame* frame) { return blink::CreateMarkup( blink::To(frame)->GetFrame()->GetDocument()); } cef_dom_node_type_t GetNodeType(const blink::WebNode& node) { const blink::Node* web_node = node.ConstUnwrap(); switch (web_node->getNodeType()) { case blink::Node::kElementNode: return DOM_NODE_TYPE_ELEMENT; case blink::Node::kAttributeNode: return DOM_NODE_TYPE_ATTRIBUTE; case blink::Node::kTextNode: return DOM_NODE_TYPE_TEXT; case blink::Node::kCdataSectionNode: return DOM_NODE_TYPE_CDATA_SECTION; case blink::Node::kProcessingInstructionNode: return DOM_NODE_TYPE_PROCESSING_INSTRUCTIONS; case blink::Node::kCommentNode: return DOM_NODE_TYPE_COMMENT; case blink::Node::kDocumentNode: return DOM_NODE_TYPE_DOCUMENT; case blink::Node::kDocumentTypeNode: return DOM_NODE_TYPE_DOCUMENT_TYPE; case blink::Node::kDocumentFragmentNode: return DOM_NODE_TYPE_DOCUMENT_FRAGMENT; } return DOM_NODE_TYPE_UNSUPPORTED; } blink::WebString GetNodeName(const blink::WebNode& node) { const blink::Node* web_node = node.ConstUnwrap(); return web_node->nodeName(); } blink::WebString CreateNodeMarkup(const blink::WebNode& node) { const blink::Node* web_node = node.ConstUnwrap(); return blink::CreateMarkup(web_node); } bool SetNodeValue(blink::WebNode& node, const blink::WebString& value) { blink::Node* web_node = node.Unwrap(); web_node->setNodeValue(value); return true; } v8::MaybeLocal CallV8Function(v8::Local context, v8::Local function, v8::Local receiver, int argc, v8::Local args[], v8::Isolate* isolate) { v8::MaybeLocal func_rv; // Execute the function call using the V8ScriptRunner so that inspector // instrumentation works. if (auto execution_context = GetExecutionContext(context)) { func_rv = blink::V8ScriptRunner::CallFunction( function, execution_context, receiver, argc, args, isolate); } return func_rv; } bool IsTextControlElement(const blink::WebElement& element) { const blink::Element* web_element = element.ConstUnwrap(); return web_element->IsTextControl(); } v8::Local ExecuteV8ScriptAndReturnValue( const blink::WebString& source, const blink::WebString& source_url, int start_line, v8::Local context, v8::TryCatch& tryCatch) { if (start_line < 1) { start_line = 1; } blink::LocalFrame* frame = blink::ToLocalFrameIfNotDetached(context); if (!frame) { return v8::Local(); } auto* script = blink::ClassicScript::Create( source, blink::KURL(source_url), blink::KURL(source_url), blink::ScriptFetchOptions(), blink::ScriptSourceLocationType::kInternal, blink::SanitizeScriptErrors::kDoNotSanitize, /*cache_handler=*/nullptr, WTF::TextPosition(WTF::OrdinalNumber::FromOneBasedInt(start_line), WTF::OrdinalNumber::FromZeroBasedInt(0))); // The Rethrow() message is unused due to kDoNotSanitize but it still needs // to be non-nullopt for exceptions to be re-thrown as expected. auto result = blink::V8ScriptRunner::CompileAndRunScript( blink::ScriptState::From(context), script, blink::ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled, blink::V8ScriptRunner::RethrowErrorsOption::Rethrow("")); if (result.GetResultType() == blink::ScriptEvaluationResult::ResultType::kSuccess) { return result.GetSuccessValue(); } DCHECK(tryCatch.HasCaught()); return v8::Local(); } v8::MicrotaskQueue* GetMicrotaskQueue(v8::Local context) { if (auto execution_context = GetExecutionContext(context)) { return execution_context->GetMicrotaskQueue(); } return nullptr; } bool IsScriptForbidden() { return blink::ScriptForbiddenScope::IsScriptForbidden(); } std::unique_ptr RegisterExecutionContextLifecycleStateObserver( v8::Local context, CefExecutionContextLifecycleStateObserver* observer) { class Observer : public blink::GarbageCollected, public blink::ExecutionContextLifecycleStateObserver { public: Observer(blink::ExecutionContext* execution_context, CefExecutionContextLifecycleStateObserver* observer) : blink::ExecutionContextLifecycleStateObserver(execution_context), observer_(observer) { UpdateStateIfNeeded(); } void ContextLifecycleStateChanged( blink::mojom::blink::FrameLifecycleState state) override { observer_->ContextLifecycleStateChanged(state); } void ContextDestroyed() override {} private: CefExecutionContextLifecycleStateObserver* observer_; }; class Registration : public CefObserverRegistration { public: Registration(blink::Persistent observer) : observer_(observer) {} private: blink::Persistent observer_; }; return std::make_unique(blink::MakeGarbageCollected( blink::ExecutionContext::From(context), observer)); } void RegisterURLSchemeAsSupportingFetchAPI(const blink::WebString& scheme) { blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI(scheme); } struct CefScriptForbiddenScope::Impl { blink::ScriptForbiddenScope scope_; }; CefScriptForbiddenScope::CefScriptForbiddenScope() : impl_(new Impl()) {} CefScriptForbiddenScope::~CefScriptForbiddenScope() {} bool ResponseWasCached(const blink::WebURLResponse& response) { return response.ToResourceResponse().WasCached(); } bool HasPluginFrameOwner(blink::WebLocalFrame* frame) { blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*frame); return core_frame->Owner() && core_frame->Owner()->IsPlugin(); } // Based on WebLocalFrameImpl::StartNavigation which was removed in // https://crrev.com/de4fc2a5fe. void StartNavigation(blink::WebLocalFrame* frame, const blink::WebURLRequest& request) { DCHECK(!request.IsNull()); DCHECK(!request.Url().ProtocolIs("javascript")); blink::FrameLoadRequest frame_load_request(nullptr, request.ToResourceRequest()); blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*frame); blink::To(core_frame) ->Loader() .StartNavigation(frame_load_request, blink::WebFrameLoadType::kStandard); } } // namespace blink_glue