diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index a37bd0f22d88d..ab38f8d607ec7 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -2,9 +2,10 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -#include "atom/renderer/api/atom_api_web_frame.h" - +#include +#include #include +#include #include "atom/common/api/api_messages.h" #include "atom/common/api/event_emitter_caller.h" @@ -112,15 +113,15 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback { DISALLOW_COPY_AND_ASSIGN(ScriptExecutionCallback); }; -class FrameSpellChecker : public content::RenderFrameVisitor { +class FrameSetSpellChecker : public content::RenderFrameVisitor { public: - explicit FrameSpellChecker(SpellCheckClient* spell_check_client, - content::RenderFrame* main_frame) - : spell_check_client_(spell_check_client), main_frame_(main_frame) {} - ~FrameSpellChecker() override { - spell_check_client_ = nullptr; - main_frame_ = nullptr; + FrameSetSpellChecker(SpellCheckClient* spell_check_client, + content::RenderFrame* main_frame) + : spell_check_client_(spell_check_client), main_frame_(main_frame) { + content::RenderFrame::ForEach(this); + main_frame->GetWebFrame()->SetSpellCheckPanelHostClient(spell_check_client); } + bool Visit(content::RenderFrame* render_frame) override { auto* view = render_frame->GetRenderView(); if (view->GetMainRenderFrame() == main_frame_ || @@ -133,95 +134,129 @@ class FrameSpellChecker : public content::RenderFrameVisitor { private: SpellCheckClient* spell_check_client_; content::RenderFrame* main_frame_; - DISALLOW_COPY_AND_ASSIGN(FrameSpellChecker); -}; -} // namespace + DISALLOW_COPY_AND_ASSIGN(FrameSetSpellChecker); +}; -class AtomWebFrameObserver : public content::RenderFrameObserver { +class SpellCheckerHolder : public content::RenderFrameObserver { public: - explicit AtomWebFrameObserver( - content::RenderFrame* render_frame, - std::unique_ptr spell_check_client) + // Find existing holder for the |render_frame|. + static SpellCheckerHolder* FromRenderFrame( + content::RenderFrame* render_frame) { + for (auto* holder : instances_) { + if (holder->render_frame() == render_frame) + return holder; + } + return nullptr; + } + + SpellCheckerHolder(content::RenderFrame* render_frame, + std::unique_ptr spell_check_client) : content::RenderFrameObserver(render_frame), - spell_check_client_(std::move(spell_check_client)) {} - ~AtomWebFrameObserver() final {} + spell_check_client_(std::move(spell_check_client)) { + DCHECK(!FromRenderFrame(render_frame)); + instances_.insert(this); + } + + ~SpellCheckerHolder() final { instances_.erase(this); } + + void UnsetAndDestroy() { + FrameSetSpellChecker set_spell_checker(nullptr, render_frame()); + delete this; + } // RenderFrameObserver implementation. void OnDestruct() final { - spell_check_client_.reset(); - // Frame observers should delete themselves + // Since we delete this in WillReleaseScriptContext, this method is unlikely + // to be called, but override anyway since I'm not sure if there are some + // corner cases. + // + // Note that while there are two "delete this", it is totally fine as the + // observer unsubscribes automatically in destructor and the other one won't + // be called. + // + // Also note that we should not call UnsetAndDestroy here, as the render + // frame is going to be destroyed. delete this; } + void WillReleaseScriptContext(v8::Local context, + int world_id) final { + // Unset spell checker when the script context is going to be released, as + // the spell check implementation lives there. + UnsetAndDestroy(); + } + private: + static std::set instances_; + std::unique_ptr spell_check_client_; }; -WebFrame::WebFrame(v8::Isolate* isolate) - : web_frame_(blink::WebLocalFrame::FrameForCurrentContext()) { - Init(isolate); -} - -WebFrame::WebFrame(v8::Isolate* isolate, blink::WebLocalFrame* blink_frame) - : web_frame_(blink_frame) { - Init(isolate); -} +} // namespace -WebFrame::~WebFrame() {} +// static +std::set SpellCheckerHolder::instances_; -void WebFrame::SetName(const std::string& name) { - web_frame_->SetName(blink::WebString::FromUTF8(name)); +void SetName(v8::Local window, const std::string& name) { + GetRenderFrame(window)->GetWebFrame()->SetName( + blink::WebString::FromUTF8(name)); } -double WebFrame::SetZoomLevel(double level) { +double SetZoomLevel(v8::Local window, double level) { double result = 0.0; - content::RenderFrame* render_frame = - content::RenderFrame::FromWebFrame(web_frame_); + content::RenderFrame* render_frame = GetRenderFrame(window); render_frame->Send(new AtomFrameHostMsg_SetTemporaryZoomLevel( render_frame->GetRoutingID(), level, &result)); return result; } -double WebFrame::GetZoomLevel() const { +double GetZoomLevel(v8::Local window) { double result = 0.0; - content::RenderFrame* render_frame = - content::RenderFrame::FromWebFrame(web_frame_); + content::RenderFrame* render_frame = GetRenderFrame(window); render_frame->Send( new AtomFrameHostMsg_GetZoomLevel(render_frame->GetRoutingID(), &result)); return result; } -double WebFrame::SetZoomFactor(double factor) { +double SetZoomFactor(v8::Local window, double factor) { return blink::WebView::ZoomLevelToZoomFactor( - SetZoomLevel(blink::WebView::ZoomFactorToZoomLevel(factor))); + SetZoomLevel(window, blink::WebView::ZoomFactorToZoomLevel(factor))); } -double WebFrame::GetZoomFactor() const { - return blink::WebView::ZoomLevelToZoomFactor(GetZoomLevel()); +double GetZoomFactor(v8::Local window) { + return blink::WebView::ZoomLevelToZoomFactor(GetZoomLevel(window)); } -void WebFrame::SetVisualZoomLevelLimits(double min_level, double max_level) { - web_frame_->View()->SetDefaultPageScaleLimits(min_level, max_level); - web_frame_->View()->SetIgnoreViewportTagScaleLimits(true); +void SetVisualZoomLevelLimits(v8::Local window, + double min_level, + double max_level) { + blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame(); + web_frame->View()->SetDefaultPageScaleLimits(min_level, max_level); + web_frame->View()->SetIgnoreViewportTagScaleLimits(true); } -void WebFrame::SetLayoutZoomLevelLimits(double min_level, double max_level) { - web_frame_->View()->ZoomLimitsChanged(min_level, max_level); +void SetLayoutZoomLevelLimits(v8::Local window, + double min_level, + double max_level) { + blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame(); + web_frame->View()->ZoomLimitsChanged(min_level, max_level); } -void WebFrame::AllowGuestViewElementDefinition( - v8::Local context, - v8::Local register_cb) { - v8::HandleScope handle_scope(isolate()); +void AllowGuestViewElementDefinition(v8::Isolate* isolate, + v8::Local window, + v8::Local context, + v8::Local register_cb) { + v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context->CreationContext()); blink::WebCustomElement::EmbedderNamesAllowedScope embedder_names_scope; - web_frame_->RequestExecuteV8Function(context->CreationContext(), register_cb, - v8::Null(isolate()), 0, nullptr, - nullptr); + GetRenderFrame(context)->GetWebFrame()->RequestExecuteV8Function( + context->CreationContext(), register_cb, v8::Null(isolate), 0, nullptr, + nullptr); } -int WebFrame::GetWebFrameId(v8::Local content_window) { +int GetWebFrameId(v8::Local window, + v8::Local content_window) { // Get the WebLocalFrame before (possibly) executing any user-space JS while // getting the |params|. We track the status of the RenderFrame via an // observer in case it is deleted during user code execution. @@ -240,9 +275,10 @@ int WebFrame::GetWebFrameId(v8::Local content_window) { return render_frame->GetRoutingID(); } -void WebFrame::SetSpellCheckProvider(mate::Arguments* args, - const std::string& language, - v8::Local provider) { +void SetSpellCheckProvider(mate::Arguments* args, + v8::Local window, + const std::string& language, + v8::Local provider) { auto context = args->isolate()->GetCurrentContext(); if (!provider->Has(context, mate::StringToV8(args->isolate(), "spellCheck")) .ToChecked()) { @@ -250,44 +286,61 @@ void WebFrame::SetSpellCheckProvider(mate::Arguments* args, return; } - auto spell_check_client = - std::make_unique(language, args->isolate(), provider); + // Remove the old client. + content::RenderFrame* render_frame = GetRenderFrame(window); + auto* existing = SpellCheckerHolder::FromRenderFrame(render_frame); + if (existing) + existing->UnsetAndDestroy(); + // Set spellchecker for all live frames in the same process or // in the sandbox mode for all live sub frames to this WebFrame. - auto* render_frame = content::RenderFrame::FromWebFrame(web_frame_); - FrameSpellChecker spell_checker(spell_check_client.get(), render_frame); - content::RenderFrame::ForEach(&spell_checker); - web_frame_->SetSpellCheckPanelHostClient(spell_check_client.get()); - new AtomWebFrameObserver(render_frame, std::move(spell_check_client)); + auto spell_check_client = + std::make_unique(language, args->isolate(), provider); + FrameSetSpellChecker spell_checker(spell_check_client.get(), render_frame); + + // Attach the spell checker to RenderFrame. + new SpellCheckerHolder(render_frame, std::move(spell_check_client)); } -void WebFrame::InsertText(const std::string& text) { - web_frame_->FrameWidget()->GetActiveWebInputMethodController()->CommitText( - blink::WebString::FromUTF8(text), - blink::WebVector(), blink::WebRange(), 0); +void InsertText(v8::Local window, const std::string& text) { + blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame(); + if (web_frame->IsWebLocalFrame()) { + web_frame->ToWebLocalFrame() + ->FrameWidget() + ->GetActiveWebInputMethodController() + ->CommitText(blink::WebString::FromUTF8(text), + blink::WebVector(), + blink::WebRange(), 0); + } } -void WebFrame::InsertCSS(const std::string& css) { - web_frame_->GetDocument().InsertStyleSheet(blink::WebString::FromUTF8(css)); +void InsertCSS(v8::Local window, const std::string& css) { + blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame(); + if (web_frame->IsWebLocalFrame()) { + web_frame->ToWebLocalFrame()->GetDocument().InsertStyleSheet( + blink::WebString::FromUTF8(css)); + } } -void WebFrame::ExecuteJavaScript(const base::string16& code, - mate::Arguments* args) { +void ExecuteJavaScript(mate::Arguments* args, + v8::Local window, + const base::string16& code) { bool has_user_gesture = false; args->GetNext(&has_user_gesture); ScriptExecutionCallback::CompletionCallback completion_callback; args->GetNext(&completion_callback); std::unique_ptr callback( new ScriptExecutionCallback(completion_callback)); - web_frame_->RequestExecuteScriptAndReturnValue( + GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptAndReturnValue( blink::WebScriptSource(blink::WebString::FromUTF16(code)), has_user_gesture, callback.release()); } -void WebFrame::ExecuteJavaScriptInIsolatedWorld( +void ExecuteJavaScriptInIsolatedWorld( + mate::Arguments* args, + v8::Local window, int world_id, - const std::vector& scripts, - mate::Arguments* args) { + const std::vector& scripts) { std::vector sources; for (const auto& script : scripts) { @@ -319,182 +372,132 @@ void WebFrame::ExecuteJavaScriptInIsolatedWorld( std::unique_ptr callback( new ScriptExecutionCallback(completion_callback)); - web_frame_->RequestExecuteScriptInIsolatedWorld( + GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptInIsolatedWorld( world_id, &sources.front(), sources.size(), has_user_gesture, scriptExecutionType, callback.release()); } -void WebFrame::SetIsolatedWorldSecurityOrigin(int world_id, - const std::string& origin_url) { - web_frame_->SetIsolatedWorldSecurityOrigin( +void SetIsolatedWorldSecurityOrigin(v8::Local window, + int world_id, + const std::string& origin_url) { + GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldSecurityOrigin( world_id, blink::WebSecurityOrigin::CreateFromString( blink::WebString::FromUTF8(origin_url))); } -void WebFrame::SetIsolatedWorldContentSecurityPolicy( - int world_id, - const std::string& security_policy) { - web_frame_->SetIsolatedWorldContentSecurityPolicy( +void SetIsolatedWorldContentSecurityPolicy(v8::Local window, + int world_id, + const std::string& security_policy) { + GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldContentSecurityPolicy( world_id, blink::WebString::FromUTF8(security_policy)); } -void WebFrame::SetIsolatedWorldHumanReadableName(int world_id, - const std::string& name) { - web_frame_->SetIsolatedWorldHumanReadableName( +void SetIsolatedWorldHumanReadableName(v8::Local window, + int world_id, + const std::string& name) { + GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldHumanReadableName( world_id, blink::WebString::FromUTF8(name)); } -// static -mate::Handle WebFrame::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new WebFrame(isolate)); -} - -blink::WebCache::ResourceTypeStats WebFrame::GetResourceUsage( - v8::Isolate* isolate) { +blink::WebCache::ResourceTypeStats GetResourceUsage(v8::Isolate* isolate) { blink::WebCache::ResourceTypeStats stats; blink::WebCache::GetResourceTypeStats(&stats); return stats; } -void WebFrame::ClearCache(v8::Isolate* isolate) { +void ClearCache(v8::Isolate* isolate) { isolate->IdleNotificationDeadline(0.5); blink::WebCache::Clear(); base::MemoryPressureListener::NotifyMemoryPressure( base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); } -v8::Local WebFrame::Opener() const { - blink::WebFrame* frame = web_frame_->Opener(); - if (frame && frame->IsWebLocalFrame()) - return mate::CreateHandle(isolate(), - new WebFrame(isolate(), frame->ToWebLocalFrame())) - .ToV8(); +v8::Local FindFrameByRoutingId(v8::Isolate* isolate, + v8::Local window, + int routing_id) { + content::RenderFrame* render_frame = + content::RenderFrame::FromRoutingID(routing_id); + if (render_frame) + return render_frame->GetWebFrame()->MainWorldScriptContext()->Global(); else - return v8::Null(isolate()); + return v8::Null(isolate); } -v8::Local WebFrame::Parent() const { - blink::WebFrame* frame = web_frame_->Parent(); +v8::Local GetOpener(v8::Isolate* isolate, + v8::Local window) { + blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Opener(); if (frame && frame->IsWebLocalFrame()) - return mate::CreateHandle(isolate(), - new WebFrame(isolate(), frame->ToWebLocalFrame())) - .ToV8(); + return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global(); else - return v8::Null(isolate()); + return v8::Null(isolate); } -v8::Local WebFrame::Top() const { - blink::WebFrame* frame = web_frame_->Top(); +// Don't name it as GetParent, Windows has API with same name. +v8::Local GetFrameParent(v8::Isolate* isolate, + v8::Local window) { + blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Parent(); if (frame && frame->IsWebLocalFrame()) - return mate::CreateHandle(isolate(), - new WebFrame(isolate(), frame->ToWebLocalFrame())) - .ToV8(); + return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global(); else - return v8::Null(isolate()); + return v8::Null(isolate); } -v8::Local WebFrame::FirstChild() const { - blink::WebFrame* frame = web_frame_->FirstChild(); +v8::Local GetTop(v8::Isolate* isolate, v8::Local window) { + blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Top(); if (frame && frame->IsWebLocalFrame()) - return mate::CreateHandle(isolate(), - new WebFrame(isolate(), frame->ToWebLocalFrame())) - .ToV8(); + return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global(); else - return v8::Null(isolate()); + return v8::Null(isolate); } -v8::Local WebFrame::NextSibling() const { - blink::WebFrame* frame = web_frame_->NextSibling(); +v8::Local GetFirstChild(v8::Isolate* isolate, + v8::Local window) { + blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->FirstChild(); if (frame && frame->IsWebLocalFrame()) - return mate::CreateHandle(isolate(), - new WebFrame(isolate(), frame->ToWebLocalFrame())) - .ToV8(); + return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global(); else - return v8::Null(isolate()); + return v8::Null(isolate); } -v8::Local WebFrame::GetFrameForSelector( - const std::string& selector) const { - blink::WebElement element = web_frame_->GetDocument().QuerySelector( - blink::WebString::FromUTF8(selector)); - blink::WebLocalFrame* element_frame = - blink::WebLocalFrame::FromFrameOwnerElement(element); - if (element_frame) - return mate::CreateHandle(isolate(), new WebFrame(isolate(), element_frame)) - .ToV8(); +v8::Local GetNextSibling(v8::Isolate* isolate, + v8::Local window) { + blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->NextSibling(); + if (frame && frame->IsWebLocalFrame()) + return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global(); else - return v8::Null(isolate()); + return v8::Null(isolate); } -v8::Local WebFrame::FindFrameByName(const std::string& name) const { - blink::WebLocalFrame* local_frame = - web_frame_->FindFrameByName(blink::WebString::FromUTF8(name)) - ->ToWebLocalFrame(); - if (local_frame) - return mate::CreateHandle(isolate(), new WebFrame(isolate(), local_frame)) - .ToV8(); - else - return v8::Null(isolate()); -} +v8::Local GetFrameForSelector(v8::Isolate* isolate, + v8::Local window, + const std::string& selector) { + blink::WebElement element = + GetRenderFrame(window)->GetWebFrame()->GetDocument().QuerySelector( + blink::WebString::FromUTF8(selector)); + if (element.IsNull()) // not found + return v8::Null(isolate); -v8::Local WebFrame::FindFrameByRoutingId(int routing_id) const { - content::RenderFrame* render_frame = - content::RenderFrame::FromRoutingID(routing_id); - blink::WebLocalFrame* local_frame = nullptr; - if (render_frame) - local_frame = render_frame->GetWebFrame(); - if (local_frame) - return mate::CreateHandle(isolate(), new WebFrame(isolate(), local_frame)) - .ToV8(); + blink::WebFrame* frame = blink::WebFrame::FromFrameOwnerElement(element); + if (frame && frame->IsWebLocalFrame()) + return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global(); else - return v8::Null(isolate()); + return v8::Null(isolate); } -v8::Local WebFrame::RoutingId() const { - int routing_id = content::RenderFrame::GetRoutingIdForWebFrame(web_frame_); - return v8::Number::New(isolate(), routing_id); +v8::Local FindFrameByName(v8::Isolate* isolate, + v8::Local window, + const std::string& name) { + blink::WebFrame* frame = + GetRenderFrame(window)->GetWebFrame()->FindFrameByName( + blink::WebString::FromUTF8(name)); + if (frame && frame->IsWebLocalFrame()) + return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global(); + else + return v8::Null(isolate); } -// static -void WebFrame::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "WebFrame")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("setName", &WebFrame::SetName) - .SetMethod("setZoomLevel", &WebFrame::SetZoomLevel) - .SetMethod("getZoomLevel", &WebFrame::GetZoomLevel) - .SetMethod("setZoomFactor", &WebFrame::SetZoomFactor) - .SetMethod("getZoomFactor", &WebFrame::GetZoomFactor) - .SetMethod("setVisualZoomLevelLimits", - &WebFrame::SetVisualZoomLevelLimits) - .SetMethod("setLayoutZoomLevelLimits", - &WebFrame::SetLayoutZoomLevelLimits) - .SetMethod("allowGuestViewElementDefinition", - &WebFrame::AllowGuestViewElementDefinition) - .SetMethod("getWebFrameId", &WebFrame::GetWebFrameId) - .SetMethod("setSpellCheckProvider", &WebFrame::SetSpellCheckProvider) - .SetMethod("insertText", &WebFrame::InsertText) - .SetMethod("insertCSS", &WebFrame::InsertCSS) - .SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript) - .SetMethod("executeJavaScriptInIsolatedWorld", - &WebFrame::ExecuteJavaScriptInIsolatedWorld) - .SetMethod("setIsolatedWorldSecurityOrigin", - &WebFrame::SetIsolatedWorldSecurityOrigin) - .SetMethod("setIsolatedWorldContentSecurityPolicy", - &WebFrame::SetIsolatedWorldContentSecurityPolicy) - .SetMethod("setIsolatedWorldHumanReadableName", - &WebFrame::SetIsolatedWorldHumanReadableName) - .SetMethod("getResourceUsage", &WebFrame::GetResourceUsage) - .SetMethod("clearCache", &WebFrame::ClearCache) - .SetMethod("getFrameForSelector", &WebFrame::GetFrameForSelector) - .SetMethod("findFrameByName", &WebFrame::FindFrameByName) - .SetProperty("opener", &WebFrame::Opener) - .SetProperty("parent", &WebFrame::Parent) - .SetProperty("top", &WebFrame::Top) - .SetProperty("firstChild", &WebFrame::FirstChild) - .SetProperty("nextSibling", &WebFrame::NextSibling) - .SetProperty("routingId", &WebFrame::RoutingId) - .SetMethod("findFrameByRoutingId", &WebFrame::FindFrameByRoutingId); +int GetRoutingId(v8::Local window) { + return GetRenderFrame(window)->GetRoutingID(); } } // namespace api @@ -503,18 +506,47 @@ void WebFrame::BuildPrototype(v8::Isolate* isolate, namespace { -using atom::api::WebFrame; - void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { + using namespace atom::api; // NOLINT(build/namespaces) + v8::Isolate* isolate = context->GetIsolate(); mate::Dictionary dict(isolate, exports); - dict.Set("webFrame", WebFrame::Create(isolate)); - dict.Set( - "WebFrame", - WebFrame::GetConstructor(isolate)->GetFunction(context).ToLocalChecked()); + dict.SetMethod("setName", &SetName); + dict.SetMethod("setZoomLevel", &SetZoomLevel); + dict.SetMethod("getZoomLevel", &GetZoomLevel); + dict.SetMethod("setZoomFactor", &SetZoomFactor); + dict.SetMethod("getZoomFactor", &GetZoomFactor); + dict.SetMethod("setVisualZoomLevelLimits", &SetVisualZoomLevelLimits); + dict.SetMethod("setLayoutZoomLevelLimits", &SetLayoutZoomLevelLimits); + dict.SetMethod("allowGuestViewElementDefinition", + &AllowGuestViewElementDefinition); + dict.SetMethod("getWebFrameId", &GetWebFrameId); + dict.SetMethod("setSpellCheckProvider", &SetSpellCheckProvider); + dict.SetMethod("insertText", &InsertText); + dict.SetMethod("insertCSS", &InsertCSS); + dict.SetMethod("executeJavaScript", &ExecuteJavaScript); + dict.SetMethod("executeJavaScriptInIsolatedWorld", + &ExecuteJavaScriptInIsolatedWorld); + dict.SetMethod("setIsolatedWorldSecurityOrigin", + &SetIsolatedWorldSecurityOrigin); + dict.SetMethod("setIsolatedWorldContentSecurityPolicy", + &SetIsolatedWorldContentSecurityPolicy); + dict.SetMethod("setIsolatedWorldHumanReadableName", + &SetIsolatedWorldHumanReadableName); + dict.SetMethod("getResourceUsage", &GetResourceUsage); + dict.SetMethod("clearCache", &ClearCache); + dict.SetMethod("_findFrameByRoutingId", &FindFrameByRoutingId); + dict.SetMethod("_getFrameForSelector", &GetFrameForSelector); + dict.SetMethod("_findFrameByName", &FindFrameByName); + dict.SetMethod("_getOpener", &GetOpener); + dict.SetMethod("_getParent", &GetFrameParent); + dict.SetMethod("_getTop", &GetTop); + dict.SetMethod("_getFirstChild", &GetFirstChild); + dict.SetMethod("_getNextSibling", &GetNextSibling); + dict.SetMethod("_getRoutingId", &GetRoutingId); } } // namespace diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h deleted file mode 100644 index 133ece4c3b84a..0000000000000 --- a/atom/renderer/api/atom_api_web_frame.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_ -#define ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_ - -#include -#include -#include - -#include "native_mate/handle.h" -#include "native_mate/wrappable.h" -#include "third_party/blink/public/platform/web_cache.h" - -namespace blink { -class WebLocalFrame; -} - -namespace mate { -class Dictionary; -class Arguments; -} // namespace mate - -namespace atom { - -namespace api { - -class WebFrame : public mate::Wrappable { - public: - static mate::Handle Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - private: - explicit WebFrame(v8::Isolate* isolate); - explicit WebFrame(v8::Isolate* isolate, blink::WebLocalFrame* blink_frame); - ~WebFrame() override; - - void SetName(const std::string& name); - - double SetZoomLevel(double level); - double GetZoomLevel() const; - double SetZoomFactor(double factor); - double GetZoomFactor() const; - - void SetVisualZoomLevelLimits(double min_level, double max_level); - void SetLayoutZoomLevelLimits(double min_level, double max_level); - - void AllowGuestViewElementDefinition(v8::Local context, - v8::Local register_cb); - int GetWebFrameId(v8::Local content_window); - - // Set the provider that will be used by SpellCheckClient for spell check. - void SetSpellCheckProvider(mate::Arguments* args, - const std::string& language, - v8::Local provider); - - // Editing. - void InsertText(const std::string& text); - void InsertCSS(const std::string& css); - - // Executing scripts. - void ExecuteJavaScript(const base::string16& code, mate::Arguments* args); - void ExecuteJavaScriptInIsolatedWorld( - int world_id, - const std::vector& scripts, - mate::Arguments* args); - - // Isolated world related methods - void SetIsolatedWorldSecurityOrigin(int world_id, - const std::string& origin_url); - void SetIsolatedWorldContentSecurityPolicy( - int world_id, - const std::string& security_policy); - void SetIsolatedWorldHumanReadableName(int world_id, const std::string& name); - - // Resource related methods - blink::WebCache::ResourceTypeStats GetResourceUsage(v8::Isolate* isolate); - void ClearCache(v8::Isolate* isolate); - - // Frame navigation - v8::Local Opener() const; - v8::Local Parent() const; - v8::Local Top() const; - v8::Local FirstChild() const; - v8::Local NextSibling() const; - v8::Local GetFrameForSelector(const std::string& selector) const; - v8::Local FindFrameByName(const std::string& name) const; - v8::Local FindFrameByRoutingId(int routing_id) const; - v8::Local RoutingId() const; - - blink::WebLocalFrame* web_frame_; - - DISALLOW_COPY_AND_ASSIGN(WebFrame); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_ diff --git a/filenames.gni b/filenames.gni index d913ad232fd14..9636e1c5d2699 100644 --- a/filenames.gni +++ b/filenames.gni @@ -635,7 +635,6 @@ filenames = { "atom/renderer/api/atom_api_spell_check_client.cc", "atom/renderer/api/atom_api_spell_check_client.h", "atom/renderer/api/atom_api_web_frame.cc", - "atom/renderer/api/atom_api_web_frame.h", "atom/renderer/atom_autofill_agent.cc", "atom/renderer/atom_autofill_agent.h", "atom/renderer/atom_render_frame_observer.cc", diff --git a/lib/renderer/api/web-frame.js b/lib/renderer/api/web-frame.js index 78ab231af9a4d..90803a396caac 100644 --- a/lib/renderer/api/web-frame.js +++ b/lib/renderer/api/web-frame.js @@ -1,13 +1,67 @@ 'use strict' const { EventEmitter } = require('events') -const { webFrame, WebFrame } = process.atomBinding('web_frame') +const binding = process.atomBinding('web_frame') -// WebFrame is an EventEmitter. -Object.setPrototypeOf(WebFrame.prototype, EventEmitter.prototype) -EventEmitter.call(webFrame) +class WebFrame extends EventEmitter { + constructor (context) { + super() -// Lots of webview would subscribe to webFrame's events. -webFrame.setMaxListeners(0) + this.context = context + // Lots of webview would subscribe to webFrame's events. + this.setMaxListeners(0) + } -module.exports = webFrame + findFrameByRoutingId (...args) { + return getWebFrame(binding._findFrameByRoutingId(this.context, ...args)) + } + + getFrameForSelector (...args) { + return getWebFrame(binding._getFrameForSelector(this.context, ...args)) + } + + findFrameByName (...args) { + return getWebFrame(binding._findFrameByName(this.context, ...args)) + } + + get opener () { + return getWebFrame(binding._getOpener(this.context)) + } + + get parent () { + return getWebFrame(binding._getParent(this.context)) + } + + get top () { + return getWebFrame(binding._getTop(this.context)) + } + + get firstChild () { + return getWebFrame(binding._getFirstChild(this.context)) + } + + get nextSibling () { + return getWebFrame(binding._getNextSibling(this.context)) + } + + get routingId () { + return binding._getRoutingId(this.context) + } +} + +// Populate the methods. +for (const name in binding) { + if (!name.startsWith('_')) { // some methods are manully populated above + WebFrame.prototype[name] = function (...args) { + return binding[name](this.context, ...args) + } + } +} + +// Helper to return WebFrame or null depending on context. +// TODO(zcbenz): Consider returning same WebFrame for the same frame. +function getWebFrame (context) { + return context ? new WebFrame(context) : null +} + +module.exports = new WebFrame(window) diff --git a/spec/api-web-frame-spec.js b/spec/api-web-frame-spec.js index 6852a48a8c046..a80e585ea59f4 100644 --- a/spec/api-web-frame-spec.js +++ b/spec/api-web-frame-spec.js @@ -56,4 +56,28 @@ describe('webFrame module', function () { expect(words).to.deep.equal(['spleling', 'test']) expect(callback).to.be.true() }) + + it('top is self for top frame', () => { + expect(webFrame.top.context).to.equal(webFrame.context) + }) + + it('opener is null for top frame', () => { + expect(webFrame.opener).to.be.null() + }) + + it('firstChild is null for top frame', () => { + expect(webFrame.firstChild).to.be.null() + }) + + it('getFrameForSelector() does not crash when not found', () => { + expect(webFrame.getFrameForSelector('unexist-selector')).to.be.null() + }) + + it('findFrameByName() does not crash when not found', () => { + expect(webFrame.findFrameByName('unexist-name')).to.be.null() + }) + + it('findFrameByRoutingId() does not crash when not found', () => { + expect(webFrame.findFrameByRoutingId(-1)).to.be.null() + }) })