fix: remove memory leak when using webFrame and spell checker (#16770)
* fix: do not create native api::WebFrame in webFrame When reloading a page without restarting renderer process (for example sandbox mode), the blink::WebFrame is not destroyed, but api::WebFrame is always recreated for the new page context. This leaves a leak of api::WebFrame. * fix: remove spell checker when page context is released
This commit is contained in:
		
					parent
					
						
							
								3f52e18a38
							
						
					
				
			
			
				commit
				
					
						d16b581140
					
				
			
		
					 5 changed files with 354 additions and 348 deletions
				
			
		| 
						 | 
				
			
			@ -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 <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#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);
 | 
			
		||||
 | 
			
		||||
  DISALLOW_COPY_AND_ASSIGN(FrameSetSpellChecker);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SpellCheckerHolder : public content::RenderFrameObserver {
 | 
			
		||||
 public:
 | 
			
		||||
  // 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<SpellCheckClient> spell_check_client)
 | 
			
		||||
      : content::RenderFrameObserver(render_frame),
 | 
			
		||||
        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 {
 | 
			
		||||
    // 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<v8::Context> 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<SpellCheckerHolder*> instances_;
 | 
			
		||||
 | 
			
		||||
  std::unique_ptr<SpellCheckClient> spell_check_client_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
class AtomWebFrameObserver : public content::RenderFrameObserver {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit AtomWebFrameObserver(
 | 
			
		||||
      content::RenderFrame* render_frame,
 | 
			
		||||
      std::unique_ptr<SpellCheckClient> spell_check_client)
 | 
			
		||||
      : content::RenderFrameObserver(render_frame),
 | 
			
		||||
        spell_check_client_(std::move(spell_check_client)) {}
 | 
			
		||||
  ~AtomWebFrameObserver() final {}
 | 
			
		||||
// static
 | 
			
		||||
std::set<SpellCheckerHolder*> SpellCheckerHolder::instances_;
 | 
			
		||||
 | 
			
		||||
  // RenderFrameObserver implementation.
 | 
			
		||||
  void OnDestruct() final {
 | 
			
		||||
    spell_check_client_.reset();
 | 
			
		||||
    // Frame observers should delete themselves
 | 
			
		||||
    delete this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  std::unique_ptr<SpellCheckClient> spell_check_client_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
WebFrame::WebFrame(v8::Isolate* isolate)
 | 
			
		||||
    : web_frame_(blink::WebLocalFrame::FrameForCurrentContext()) {
 | 
			
		||||
  Init(isolate);
 | 
			
		||||
void SetName(v8::Local<v8::Value> window, const std::string& name) {
 | 
			
		||||
  GetRenderFrame(window)->GetWebFrame()->SetName(
 | 
			
		||||
      blink::WebString::FromUTF8(name));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WebFrame::WebFrame(v8::Isolate* isolate, blink::WebLocalFrame* blink_frame)
 | 
			
		||||
    : web_frame_(blink_frame) {
 | 
			
		||||
  Init(isolate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WebFrame::~WebFrame() {}
 | 
			
		||||
 | 
			
		||||
void WebFrame::SetName(const std::string& name) {
 | 
			
		||||
  web_frame_->SetName(blink::WebString::FromUTF8(name));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double WebFrame::SetZoomLevel(double level) {
 | 
			
		||||
double SetZoomLevel(v8::Local<v8::Value> 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<v8::Value> 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<v8::Value> 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<v8::Value> 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<v8::Value> 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<v8::Value> 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<v8::Object> context,
 | 
			
		||||
    v8::Local<v8::Function> register_cb) {
 | 
			
		||||
  v8::HandleScope handle_scope(isolate());
 | 
			
		||||
void AllowGuestViewElementDefinition(v8::Isolate* isolate,
 | 
			
		||||
                                     v8::Local<v8::Value> window,
 | 
			
		||||
                                     v8::Local<v8::Object> context,
 | 
			
		||||
                                     v8::Local<v8::Function> 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<v8::Value> content_window) {
 | 
			
		||||
int GetWebFrameId(v8::Local<v8::Value> window,
 | 
			
		||||
                  v8::Local<v8::Value> 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<v8::Value> content_window) {
 | 
			
		|||
  return render_frame->GetRoutingID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WebFrame::SetSpellCheckProvider(mate::Arguments* args,
 | 
			
		||||
                                     const std::string& language,
 | 
			
		||||
                                     v8::Local<v8::Object> provider) {
 | 
			
		||||
void SetSpellCheckProvider(mate::Arguments* args,
 | 
			
		||||
                           v8::Local<v8::Value> window,
 | 
			
		||||
                           const std::string& language,
 | 
			
		||||
                           v8::Local<v8::Object> 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<SpellCheckClient>(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<SpellCheckClient>(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::WebImeTextSpan>(), blink::WebRange(), 0);
 | 
			
		||||
void InsertText(v8::Local<v8::Value> 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::WebImeTextSpan>(),
 | 
			
		||||
                     blink::WebRange(), 0);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WebFrame::InsertCSS(const std::string& css) {
 | 
			
		||||
  web_frame_->GetDocument().InsertStyleSheet(blink::WebString::FromUTF8(css));
 | 
			
		||||
void InsertCSS(v8::Local<v8::Value> 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<v8::Value> 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<blink::WebScriptExecutionCallback> 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<v8::Value> window,
 | 
			
		||||
    int world_id,
 | 
			
		||||
    const std::vector<mate::Dictionary>& scripts,
 | 
			
		||||
    mate::Arguments* args) {
 | 
			
		||||
    const std::vector<mate::Dictionary>& scripts) {
 | 
			
		||||
  std::vector<blink::WebScriptSource> sources;
 | 
			
		||||
 | 
			
		||||
  for (const auto& script : scripts) {
 | 
			
		||||
| 
						 | 
				
			
			@ -319,182 +372,132 @@ void WebFrame::ExecuteJavaScriptInIsolatedWorld(
 | 
			
		|||
  std::unique_ptr<blink::WebScriptExecutionCallback> 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<v8::Value> 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<v8::Value> 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<v8::Value> window,
 | 
			
		||||
                                       int world_id,
 | 
			
		||||
                                       const std::string& name) {
 | 
			
		||||
  GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldHumanReadableName(
 | 
			
		||||
      world_id, blink::WebString::FromUTF8(name));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// static
 | 
			
		||||
mate::Handle<WebFrame> 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<v8::Value> WebFrame::Opener() const {
 | 
			
		||||
  blink::WebFrame* frame = web_frame_->Opener();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return mate::CreateHandle(isolate(),
 | 
			
		||||
                              new WebFrame(isolate(), frame->ToWebLocalFrame()))
 | 
			
		||||
        .ToV8();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> WebFrame::Parent() const {
 | 
			
		||||
  blink::WebFrame* frame = web_frame_->Parent();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return mate::CreateHandle(isolate(),
 | 
			
		||||
                              new WebFrame(isolate(), frame->ToWebLocalFrame()))
 | 
			
		||||
        .ToV8();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> WebFrame::Top() const {
 | 
			
		||||
  blink::WebFrame* frame = web_frame_->Top();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return mate::CreateHandle(isolate(),
 | 
			
		||||
                              new WebFrame(isolate(), frame->ToWebLocalFrame()))
 | 
			
		||||
        .ToV8();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> WebFrame::FirstChild() const {
 | 
			
		||||
  blink::WebFrame* frame = web_frame_->FirstChild();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return mate::CreateHandle(isolate(),
 | 
			
		||||
                              new WebFrame(isolate(), frame->ToWebLocalFrame()))
 | 
			
		||||
        .ToV8();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> WebFrame::NextSibling() const {
 | 
			
		||||
  blink::WebFrame* frame = web_frame_->NextSibling();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return mate::CreateHandle(isolate(),
 | 
			
		||||
                              new WebFrame(isolate(), frame->ToWebLocalFrame()))
 | 
			
		||||
        .ToV8();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> 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();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> 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<v8::Value> WebFrame::FindFrameByRoutingId(int routing_id) const {
 | 
			
		||||
v8::Local<v8::Value> FindFrameByRoutingId(v8::Isolate* isolate,
 | 
			
		||||
                                          v8::Local<v8::Value> window,
 | 
			
		||||
                                          int routing_id) {
 | 
			
		||||
  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();
 | 
			
		||||
    return render_frame->GetWebFrame()->MainWorldScriptContext()->Global();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate());
 | 
			
		||||
    return v8::Null(isolate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> WebFrame::RoutingId() const {
 | 
			
		||||
  int routing_id = content::RenderFrame::GetRoutingIdForWebFrame(web_frame_);
 | 
			
		||||
  return v8::Number::New(isolate(), routing_id);
 | 
			
		||||
v8::Local<v8::Value> GetOpener(v8::Isolate* isolate,
 | 
			
		||||
                               v8::Local<v8::Value> window) {
 | 
			
		||||
  blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Opener();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// static
 | 
			
		||||
void WebFrame::BuildPrototype(v8::Isolate* isolate,
 | 
			
		||||
                              v8::Local<v8::FunctionTemplate> 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);
 | 
			
		||||
// Don't name it as GetParent, Windows has API with same name.
 | 
			
		||||
v8::Local<v8::Value> GetFrameParent(v8::Isolate* isolate,
 | 
			
		||||
                                    v8::Local<v8::Value> window) {
 | 
			
		||||
  blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Parent();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> GetTop(v8::Isolate* isolate, v8::Local<v8::Value> window) {
 | 
			
		||||
  blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Top();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> GetFirstChild(v8::Isolate* isolate,
 | 
			
		||||
                                   v8::Local<v8::Value> window) {
 | 
			
		||||
  blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->FirstChild();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> GetNextSibling(v8::Isolate* isolate,
 | 
			
		||||
                                    v8::Local<v8::Value> window) {
 | 
			
		||||
  blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->NextSibling();
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> GetFrameForSelector(v8::Isolate* isolate,
 | 
			
		||||
                                         v8::Local<v8::Value> 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);
 | 
			
		||||
 | 
			
		||||
  blink::WebFrame* frame = blink::WebFrame::FromFrameOwnerElement(element);
 | 
			
		||||
  if (frame && frame->IsWebLocalFrame())
 | 
			
		||||
    return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
 | 
			
		||||
  else
 | 
			
		||||
    return v8::Null(isolate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
v8::Local<v8::Value> FindFrameByName(v8::Isolate* isolate,
 | 
			
		||||
                                     v8::Local<v8::Value> 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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int GetRoutingId(v8::Local<v8::Value> 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<v8::Object> exports,
 | 
			
		||||
                v8::Local<v8::Value> unused,
 | 
			
		||||
                v8::Local<v8::Context> 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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue