chore: remove native_mate (Part 11) (#20719)

* refactor: convert Menu and globalShortcut to gin

* refactor: convert api::Cookies to gin

* refactor: convert View and WebContentsView to gin

* refactor: convert WebContents related classes to gin

* refactor: convert powerMonitor to gin

* refactor: prepare for header change

* refactor: remove last uses of mate::EventEmitter

* refactor: remove mate::EventEmitter

* refactor: move trackable_object to gin_helper

* fix: custom converter should not use Handle

* fix: no more need to check if icon is empty

It was a bug that the Handle<NativeImage> can be non-empty when the
image file does not exist. The bug was caused by the converter code
writing out the image even when the convertion fails.

The bug was work-arounded by adding an additional check, but since the
original bug had been fixed, the additional check is no longer needed.

* fix: should always set frameId even when callback is null

* fix: do not mix gin/mate handles for NativeImage
This commit is contained in:
Cheng Zhao 2019-10-25 22:03:28 +09:00 committed by GitHub
parent 0e0d4fe990
commit 0fe6767d6b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
80 changed files with 823 additions and 1087 deletions

View file

@ -4,6 +4,8 @@
#include "shell/common/gin_helper/event_emitter.h"
#include "content/public/browser/render_frame_host.h"
#include "shell/browser/api/event.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/object_template_builder.h"
#include "ui/events/event_constants.h"
@ -62,6 +64,30 @@ v8::Local<v8::Object> CreateEventFromFlags(v8::Isolate* isolate, int flags) {
return obj.GetHandle();
}
v8::Local<v8::Object> CreateNativeEvent(
v8::Isolate* isolate,
v8::Local<v8::Object> sender,
content::RenderFrameHost* frame,
base::Optional<electron::mojom::ElectronBrowser::MessageSyncCallback>
callback) {
v8::Local<v8::Object> event;
if (frame && callback) {
mate::Handle<mate::Event> native_event = mate::Event::Create(isolate);
native_event->SetCallback(std::move(callback));
event = v8::Local<v8::Object>::Cast(native_event.ToV8());
} else {
// No need to create native event if we do not need to send reply.
event = CreateEvent(isolate);
}
Dictionary dict(isolate, event);
dict.Set("sender", sender);
// Should always set frameId even when callback is null.
if (frame)
dict.Set("frameId", frame->GetRoutingID());
return event;
}
} // namespace internal
} // namespace gin_helper

View file

@ -9,9 +9,15 @@
#include <vector>
#include "base/optional.h"
#include "content/public/browser/browser_thread.h"
#include "electron/shell/common/api/api.mojom.h"
#include "native_mate/wrappable.h"
#include "shell/common/gin_helper/event_emitter_caller.h"
namespace content {
class RenderFrameHost;
}
namespace gin_helper {
namespace internal {
@ -21,16 +27,21 @@ v8::Local<v8::Object> CreateEvent(
v8::Local<v8::Object> sender = v8::Local<v8::Object>(),
v8::Local<v8::Object> custom_event = v8::Local<v8::Object>());
v8::Local<v8::Object> CreateEventFromFlags(v8::Isolate* isolate, int flags);
v8::Local<v8::Object> CreateNativeEvent(
v8::Isolate* isolate,
v8::Local<v8::Object> sender,
content::RenderFrameHost* frame,
base::Optional<electron::mojom::ElectronBrowser::MessageSyncCallback>
callback);
} // namespace internal
// Provide helperers to emit event in JavaScript.
//
// TODO(zcbenz): Inherit from Wrappable directly after removing native_mate.
template <typename Base>
class EventEmitter : public Base {
template <typename T>
class EventEmitter : public mate::Wrappable<T> {
public:
typedef std::vector<v8::Local<v8::Value>> ValueArray;
using Base = mate::Wrappable<T>;
using ValueArray = std::vector<v8::Local<v8::Value>>;
// Make the convinient methods visible:
// https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members
@ -64,13 +75,30 @@ class EventEmitter : public Base {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
v8::Local<v8::Object> wrapper = GetWrapper();
if (wrapper.IsEmpty()) {
if (wrapper.IsEmpty())
return false;
}
v8::Local<v8::Object> event = internal::CreateEvent(isolate(), wrapper);
return EmitWithEvent(name, event, std::forward<Args>(args)...);
}
// this.emit(name, new Event(sender, message), args...);
template <typename... Args>
bool EmitWithSender(
base::StringPiece name,
content::RenderFrameHost* sender,
base::Optional<electron::mojom::ElectronBrowser::InvokeCallback> callback,
Args&&... args) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
v8::Local<v8::Object> wrapper = GetWrapper();
if (wrapper.IsEmpty())
return false;
v8::Local<v8::Object> event = internal::CreateNativeEvent(
isolate(), wrapper, sender, std::move(callback));
return EmitWithEvent(name, event, std::forward<Args>(args)...);
}
protected:
EventEmitter() {}

View file

@ -0,0 +1,71 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/common/gin_helper/trackable_object.h"
#include <memory>
#include "base/bind.h"
#include "base/supports_user_data.h"
#include "shell/browser/atom_browser_main_parts.h"
#include "shell/common/api/locker.h"
namespace gin_helper {
namespace {
const char* kTrackedObjectKey = "TrackedObjectKey";
class IDUserData : public base::SupportsUserData::Data {
public:
explicit IDUserData(int32_t id) : id_(id) {}
operator int32_t() const { return id_; }
private:
int32_t id_;
DISALLOW_COPY_AND_ASSIGN(IDUserData);
};
} // namespace
TrackableObjectBase::TrackableObjectBase() : weak_factory_(this) {
// TODO(zcbenz): Make TrackedObject work in renderer process.
DCHECK(mate::Locker::IsBrowserProcess())
<< "This class only works for browser process";
electron::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
GetDestroyClosure());
}
TrackableObjectBase::~TrackableObjectBase() = default;
base::OnceClosure TrackableObjectBase::GetDestroyClosure() {
return base::BindOnce(&TrackableObjectBase::Destroy,
weak_factory_.GetWeakPtr());
}
void TrackableObjectBase::Destroy() {
delete this;
}
void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) {
wrapped->SetUserData(kTrackedObjectKey,
std::make_unique<IDUserData>(weak_map_id_));
}
// static
int32_t TrackableObjectBase::GetIDFromWrappedClass(
base::SupportsUserData* wrapped) {
if (wrapped) {
auto* id =
static_cast<IDUserData*>(wrapped->GetUserData(kTrackedObjectKey));
if (id)
return *id;
}
return 0;
}
} // namespace gin_helper

View file

@ -0,0 +1,135 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef SHELL_COMMON_GIN_HELPER_TRACKABLE_OBJECT_H_
#define SHELL_COMMON_GIN_HELPER_TRACKABLE_OBJECT_H_
#include <vector>
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "shell/common/gin_helper/event_emitter.h"
#include "shell/common/key_weak_map.h"
namespace base {
class SupportsUserData;
}
namespace gin_helper {
// Users should use TrackableObject instead.
class TrackableObjectBase {
public:
TrackableObjectBase();
// The ID in weak map.
int32_t weak_map_id() const { return weak_map_id_; }
// Wrap TrackableObject into a class that SupportsUserData.
void AttachAsUserData(base::SupportsUserData* wrapped);
// Get the weak_map_id from SupportsUserData.
static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped);
protected:
virtual ~TrackableObjectBase();
// Returns a closure that can destroy the native class.
base::OnceClosure GetDestroyClosure();
int32_t weak_map_id_ = 0;
private:
void Destroy();
base::WeakPtrFactory<TrackableObjectBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase);
};
// All instances of TrackableObject will be kept in a weak map and can be got
// from its ID.
template <typename T>
class TrackableObject : public TrackableObjectBase, public EventEmitter<T> {
public:
// Mark the JS object as destroyed.
void MarkDestroyed() {
v8::Local<v8::Object> wrapper = mate::Wrappable<T>::GetWrapper();
if (!wrapper.IsEmpty()) {
wrapper->SetAlignedPointerInInternalField(0, nullptr);
}
}
bool IsDestroyed() {
v8::Local<v8::Object> wrapper = mate::Wrappable<T>::GetWrapper();
return wrapper->InternalFieldCount() == 0 ||
wrapper->GetAlignedPointerFromInternalField(0) == nullptr;
}
// Finds out the TrackableObject from its ID in weak map.
static T* FromWeakMapID(v8::Isolate* isolate, int32_t id) {
if (!weak_map_)
return nullptr;
v8::MaybeLocal<v8::Object> object = weak_map_->Get(isolate, id);
if (object.IsEmpty())
return nullptr;
T* self = nullptr;
gin::ConvertFromV8(isolate, object.ToLocalChecked(), &self);
return self;
}
// Finds out the TrackableObject from the class it wraps.
static T* FromWrappedClass(v8::Isolate* isolate,
base::SupportsUserData* wrapped) {
int32_t id = GetIDFromWrappedClass(wrapped);
if (!id)
return nullptr;
return FromWeakMapID(isolate, id);
}
// Returns all objects in this class's weak map.
static std::vector<v8::Local<v8::Object>> GetAll(v8::Isolate* isolate) {
if (weak_map_)
return weak_map_->Values(isolate);
else
return std::vector<v8::Local<v8::Object>>();
}
// Removes this instance from the weak map.
void RemoveFromWeakMap() {
if (weak_map_ && weak_map_->Has(weak_map_id()))
weak_map_->Remove(weak_map_id());
}
protected:
TrackableObject() { weak_map_id_ = ++next_id_; }
~TrackableObject() override { RemoveFromWeakMap(); }
void InitWith(v8::Isolate* isolate, v8::Local<v8::Object> wrapper) override {
mate::WrappableBase::InitWith(isolate, wrapper);
if (!weak_map_) {
weak_map_ = new electron::KeyWeakMap<int32_t>;
}
weak_map_->Set(isolate, weak_map_id_, wrapper);
}
private:
static int32_t next_id_;
static electron::KeyWeakMap<int32_t>* weak_map_; // leaked on purpose
DISALLOW_COPY_AND_ASSIGN(TrackableObject);
};
template <typename T>
int32_t TrackableObject<T>::next_id_ = 0;
template <typename T>
electron::KeyWeakMap<int32_t>* TrackableObject<T>::weak_map_ = nullptr;
} // namespace gin_helper
#endif // SHELL_COMMON_GIN_HELPER_TRACKABLE_OBJECT_H_