refactor: rename the atom directory to shell

This commit is contained in:
Samuel Attard 2019-06-19 13:43:10 -07:00 committed by Samuel Attard
parent 4575a4aae3
commit d7f07e8a80
631 changed files with 0 additions and 0 deletions

12
shell/common/api/BUILD.gn Normal file
View file

@ -0,0 +1,12 @@
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojo") {
sources = [
"api.mojom",
]
public_deps = [
"//mojo/public/mojom/base",
"//ui/gfx/geometry/mojo",
]
}

View file

@ -0,0 +1,78 @@
module atom.mojom;
import "mojo/public/mojom/base/values.mojom";
import "mojo/public/mojom/base/string16.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
interface ElectronRenderer {
Message(
bool internal,
bool send_to_all,
string channel,
mojo_base.mojom.ListValue arguments,
int32 sender_id);
UpdateCrashpadPipeName(string pipe_name);
TakeHeapSnapshot(handle file) => (bool success);
};
interface ElectronAutofillAgent {
AcceptDataListSuggestion(mojo_base.mojom.String16 value);
};
struct DraggableRegion {
bool draggable;
gfx.mojom.Rect bounds;
};
interface ElectronBrowser {
// Emits an event on |channel| from the ipcMain JavaScript object in the main
// process.
Message(
bool internal,
string channel,
mojo_base.mojom.ListValue arguments);
// Emits an event on |channel| from the ipcMain JavaScript object in the main
// process, and returns the response.
Invoke(
string channel,
mojo_base.mojom.ListValue arguments) => (mojo_base.mojom.Value result);
// Emits an event on |channel| from the ipcMain JavaScript object in the main
// process, and waits synchronously for a response.
//
// NB. this is not marked [Sync] because mojo synchronous methods can be
// reordered with respect to asynchronous methods on the same channel.
// Instead, callers can manually block on the response to this method.
MessageSync(
bool internal,
string channel,
mojo_base.mojom.ListValue arguments) => (mojo_base.mojom.Value result);
// Emits an event from the |ipcRenderer| JavaScript object in the target
// WebContents's main frame, specified by |web_contents_id|.
MessageTo(
bool internal,
bool send_to_all,
int32 web_contents_id,
string channel,
mojo_base.mojom.ListValue arguments);
MessageHost(
string channel,
mojo_base.mojom.ListValue arguments);
UpdateDraggableRegions(
array<DraggableRegion> regions);
SetTemporaryZoomLevel(double zoom_level);
[Sync]
DoGetZoomLevel() => (double result);
// TODO: move these into a separate interface
ShowAutofillPopup(gfx.mojom.RectF bounds, array<mojo_base.mojom.String16> values, array<mojo_base.mojom.String16> labels);
HideAutofillPopup();
};

View file

@ -0,0 +1,141 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <vector>
#include "atom/common/asar/archive.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/node_includes.h"
#include "native_mate/arguments.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "native_mate/wrappable.h"
#include "third_party/electron_node/src/node_native_module.h"
namespace {
class Archive : public mate::Wrappable<Archive> {
public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate,
const base::FilePath& path) {
auto archive = std::make_unique<asar::Archive>(path);
if (!archive->Init())
return v8::False(isolate);
return (new Archive(isolate, std::move(archive)))->GetWrapper();
}
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(mate::StringToV8(isolate, "Archive"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.SetProperty("path", &Archive::GetPath)
.SetMethod("getFileInfo", &Archive::GetFileInfo)
.SetMethod("stat", &Archive::Stat)
.SetMethod("readdir", &Archive::Readdir)
.SetMethod("realpath", &Archive::Realpath)
.SetMethod("copyFileOut", &Archive::CopyFileOut)
.SetMethod("getFd", &Archive::GetFD);
}
protected:
Archive(v8::Isolate* isolate, std::unique_ptr<asar::Archive> archive)
: archive_(std::move(archive)) {
Init(isolate);
}
// Returns the path of the file.
base::FilePath GetPath() { return archive_->path(); }
// Reads the offset and size of file.
v8::Local<v8::Value> GetFileInfo(v8::Isolate* isolate,
const base::FilePath& path) {
asar::Archive::FileInfo info;
if (!archive_ || !archive_->GetFileInfo(path, &info))
return v8::False(isolate);
mate::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("size", info.size);
dict.Set("unpacked", info.unpacked);
dict.Set("offset", info.offset);
return dict.GetHandle();
}
// Returns a fake result of fs.stat(path).
v8::Local<v8::Value> Stat(v8::Isolate* isolate, const base::FilePath& path) {
asar::Archive::Stats stats;
if (!archive_ || !archive_->Stat(path, &stats))
return v8::False(isolate);
mate::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("size", stats.size);
dict.Set("offset", stats.offset);
dict.Set("isFile", stats.is_file);
dict.Set("isDirectory", stats.is_directory);
dict.Set("isLink", stats.is_link);
return dict.GetHandle();
}
// Returns all files under a directory.
v8::Local<v8::Value> Readdir(v8::Isolate* isolate,
const base::FilePath& path) {
std::vector<base::FilePath> files;
if (!archive_ || !archive_->Readdir(path, &files))
return v8::False(isolate);
return mate::ConvertToV8(isolate, files);
}
// Returns the path of file with symbol link resolved.
v8::Local<v8::Value> Realpath(v8::Isolate* isolate,
const base::FilePath& path) {
base::FilePath realpath;
if (!archive_ || !archive_->Realpath(path, &realpath))
return v8::False(isolate);
return mate::ConvertToV8(isolate, realpath);
}
// Copy the file out into a temporary file and returns the new path.
v8::Local<v8::Value> CopyFileOut(v8::Isolate* isolate,
const base::FilePath& path) {
base::FilePath new_path;
if (!archive_ || !archive_->CopyFileOut(path, &new_path))
return v8::False(isolate);
return mate::ConvertToV8(isolate, new_path);
}
// Return the file descriptor.
int GetFD() const {
if (!archive_)
return -1;
return archive_->GetFD();
}
private:
std::unique_ptr<asar::Archive> archive_;
DISALLOW_COPY_AND_ASSIGN(Archive);
};
void InitAsarSupport(v8::Isolate* isolate, v8::Local<v8::Value> require) {
// Evaluate asar_init.js.
std::vector<v8::Local<v8::String>> asar_init_params = {
node::FIXED_ONE_BYTE_STRING(isolate, "require")};
std::vector<v8::Local<v8::Value>> asar_init_args = {require};
node::per_process::native_module_loader.CompileAndCall(
isolate->GetCurrentContext(), "electron/js2c/asar_init",
&asar_init_params, &asar_init_args, nullptr);
}
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("createArchive", &Archive::Create);
dict.SetMethod("initAsarSupport", &InitAsarSupport);
}
} // namespace
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_asar, Initialize)

View file

@ -0,0 +1,229 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/api/atom_api_clipboard.h"
#include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/node_includes.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkPixmap.h"
#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
namespace atom {
namespace api {
ui::ClipboardType Clipboard::GetClipboardType(mate::Arguments* args) {
std::string type;
if (args->GetNext(&type) && type == "selection")
return ui::CLIPBOARD_TYPE_SELECTION;
else
return ui::CLIPBOARD_TYPE_COPY_PASTE;
}
std::vector<base::string16> Clipboard::AvailableFormats(mate::Arguments* args) {
std::vector<base::string16> format_types;
bool ignore;
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
clipboard->ReadAvailableTypes(GetClipboardType(args), &format_types, &ignore);
return format_types;
}
bool Clipboard::Has(const std::string& format_string, mate::Arguments* args) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
ui::ClipboardFormatType format(
ui::ClipboardFormatType::GetType(format_string));
return clipboard->IsFormatAvailable(format, GetClipboardType(args));
}
std::string Clipboard::Read(const std::string& format_string) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
ui::ClipboardFormatType format(
ui::ClipboardFormatType::GetType(format_string));
std::string data;
clipboard->ReadData(format, &data);
return data;
}
v8::Local<v8::Value> Clipboard::ReadBuffer(const std::string& format_string,
mate::Arguments* args) {
std::string data = Read(format_string);
return node::Buffer::Copy(args->isolate(), data.data(), data.length())
.ToLocalChecked();
}
void Clipboard::WriteBuffer(const std::string& format,
const v8::Local<v8::Value> buffer,
mate::Arguments* args) {
if (!node::Buffer::HasInstance(buffer)) {
args->ThrowError("buffer must be a node Buffer");
return;
}
ui::ScopedClipboardWriter writer(GetClipboardType(args));
writer.WriteData(
ui::ClipboardFormatType::GetType(format).Serialize(),
std::string(node::Buffer::Data(buffer), node::Buffer::Length(buffer)));
}
void Clipboard::Write(const mate::Dictionary& data, mate::Arguments* args) {
ui::ScopedClipboardWriter writer(GetClipboardType(args));
base::string16 text, html, bookmark;
gfx::Image image;
if (data.Get("text", &text)) {
writer.WriteText(text);
if (data.Get("bookmark", &bookmark))
writer.WriteBookmark(bookmark, base::UTF16ToUTF8(text));
}
if (data.Get("rtf", &text)) {
std::string rtf = base::UTF16ToUTF8(text);
writer.WriteRTF(rtf);
}
if (data.Get("html", &html))
writer.WriteHTML(html, std::string());
if (data.Get("image", &image))
writer.WriteImage(image.AsBitmap());
}
base::string16 Clipboard::ReadText(mate::Arguments* args) {
base::string16 data;
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
auto type = GetClipboardType(args);
if (clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetPlainTextWType(),
type)) {
clipboard->ReadText(type, &data);
} else if (clipboard->IsFormatAvailable(
ui::ClipboardFormatType::GetPlainTextType(), type)) {
std::string result;
clipboard->ReadAsciiText(type, &result);
data = base::ASCIIToUTF16(result);
}
return data;
}
void Clipboard::WriteText(const base::string16& text, mate::Arguments* args) {
ui::ScopedClipboardWriter writer(GetClipboardType(args));
writer.WriteText(text);
}
base::string16 Clipboard::ReadRTF(mate::Arguments* args) {
std::string data;
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
clipboard->ReadRTF(GetClipboardType(args), &data);
return base::UTF8ToUTF16(data);
}
void Clipboard::WriteRTF(const std::string& text, mate::Arguments* args) {
ui::ScopedClipboardWriter writer(GetClipboardType(args));
writer.WriteRTF(text);
}
base::string16 Clipboard::ReadHTML(mate::Arguments* args) {
base::string16 data;
base::string16 html;
std::string url;
uint32_t start;
uint32_t end;
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
clipboard->ReadHTML(GetClipboardType(args), &html, &url, &start, &end);
data = html.substr(start, end - start);
return data;
}
void Clipboard::WriteHTML(const base::string16& html, mate::Arguments* args) {
ui::ScopedClipboardWriter writer(GetClipboardType(args));
writer.WriteHTML(html, std::string());
}
v8::Local<v8::Value> Clipboard::ReadBookmark(mate::Arguments* args) {
base::string16 title;
std::string url;
mate::Dictionary dict = mate::Dictionary::CreateEmpty(args->isolate());
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
clipboard->ReadBookmark(&title, &url);
dict.Set("title", title);
dict.Set("url", url);
return dict.GetHandle();
}
void Clipboard::WriteBookmark(const base::string16& title,
const std::string& url,
mate::Arguments* args) {
ui::ScopedClipboardWriter writer(GetClipboardType(args));
writer.WriteBookmark(title, url);
}
gfx::Image Clipboard::ReadImage(mate::Arguments* args) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
SkBitmap bitmap = clipboard->ReadImage(GetClipboardType(args));
return gfx::Image::CreateFrom1xBitmap(bitmap);
}
void Clipboard::WriteImage(const gfx::Image& image, mate::Arguments* args) {
ui::ScopedClipboardWriter writer(GetClipboardType(args));
SkBitmap orig = image.AsBitmap();
SkBitmap bmp;
if (bmp.tryAllocPixels(orig.info()) &&
orig.readPixels(bmp.info(), bmp.getPixels(), bmp.rowBytes(), 0, 0)) {
writer.WriteImage(bmp);
}
}
#if !defined(OS_MACOSX)
void Clipboard::WriteFindText(const base::string16& text) {}
base::string16 Clipboard::ReadFindText() {
return base::string16();
}
#endif
void Clipboard::Clear(mate::Arguments* args) {
ui::Clipboard::GetForCurrentThread()->Clear(GetClipboardType(args));
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("availableFormats", &atom::api::Clipboard::AvailableFormats);
dict.SetMethod("has", &atom::api::Clipboard::Has);
dict.SetMethod("read", &atom::api::Clipboard::Read);
dict.SetMethod("write", &atom::api::Clipboard::Write);
dict.SetMethod("readText", &atom::api::Clipboard::ReadText);
dict.SetMethod("writeText", &atom::api::Clipboard::WriteText);
dict.SetMethod("readRTF", &atom::api::Clipboard::ReadRTF);
dict.SetMethod("writeRTF", &atom::api::Clipboard::WriteRTF);
dict.SetMethod("readHTML", &atom::api::Clipboard::ReadHTML);
dict.SetMethod("writeHTML", &atom::api::Clipboard::WriteHTML);
dict.SetMethod("readBookmark", &atom::api::Clipboard::ReadBookmark);
dict.SetMethod("writeBookmark", &atom::api::Clipboard::WriteBookmark);
dict.SetMethod("readImage", &atom::api::Clipboard::ReadImage);
dict.SetMethod("writeImage", &atom::api::Clipboard::WriteImage);
dict.SetMethod("readFindText", &atom::api::Clipboard::ReadFindText);
dict.SetMethod("writeFindText", &atom::api::Clipboard::WriteFindText);
dict.SetMethod("readBuffer", &atom::api::Clipboard::ReadBuffer);
dict.SetMethod("writeBuffer", &atom::api::Clipboard::WriteBuffer);
dict.SetMethod("clear", &atom::api::Clipboard::Clear);
}
} // namespace
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_clipboard, Initialize)

View file

@ -0,0 +1,64 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_ATOM_API_CLIPBOARD_H_
#define ATOM_COMMON_API_ATOM_API_CLIPBOARD_H_
#include <string>
#include <vector>
#include "native_mate/arguments.h"
#include "native_mate/dictionary.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/gfx/image/image.h"
namespace atom {
namespace api {
class Clipboard {
public:
static ui::ClipboardType GetClipboardType(mate::Arguments* args);
static std::vector<base::string16> AvailableFormats(mate::Arguments* args);
static bool Has(const std::string& format_string, mate::Arguments* args);
static void Clear(mate::Arguments* args);
static std::string Read(const std::string& format_string);
static void Write(const mate::Dictionary& data, mate::Arguments* args);
static base::string16 ReadText(mate::Arguments* args);
static void WriteText(const base::string16& text, mate::Arguments* args);
static base::string16 ReadRTF(mate::Arguments* args);
static void WriteRTF(const std::string& text, mate::Arguments* args);
static base::string16 ReadHTML(mate::Arguments* args);
static void WriteHTML(const base::string16& html, mate::Arguments* args);
static v8::Local<v8::Value> ReadBookmark(mate::Arguments* args);
static void WriteBookmark(const base::string16& title,
const std::string& url,
mate::Arguments* args);
static gfx::Image ReadImage(mate::Arguments* args);
static void WriteImage(const gfx::Image& image, mate::Arguments* args);
static base::string16 ReadFindText();
static void WriteFindText(const base::string16& text);
static v8::Local<v8::Value> ReadBuffer(const std::string& format_string,
mate::Arguments* args);
static void WriteBuffer(const std::string& format_string,
const v8::Local<v8::Value> buffer,
mate::Arguments* args);
private:
DISALLOW_COPY_AND_ASSIGN(Clipboard);
};
} // namespace api
} // namespace atom
#endif // ATOM_COMMON_API_ATOM_API_CLIPBOARD_H_

View file

@ -0,0 +1,24 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/api/atom_api_clipboard.h"
#include "base/strings/sys_string_conversions.h"
#include "ui/base/cocoa/find_pasteboard.h"
namespace atom {
namespace api {
void Clipboard::WriteFindText(const base::string16& text) {
NSString* text_ns = base::SysUTF16ToNSString(text);
[[FindPasteboard sharedInstance] setFindText:text_ns];
}
base::string16 Clipboard::ReadFindText() {
return GetFindPboardText();
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,61 @@
// Copyright (c) 2019 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/node_includes.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/strings/string_util.h"
#include "native_mate/converter.h"
#include "native_mate/dictionary.h"
#include "services/network/public/cpp/network_switches.h"
namespace {
bool HasSwitch(const std::string& name) {
return base::CommandLine::ForCurrentProcess()->HasSwitch(name.c_str());
}
base::CommandLine::StringType GetSwitchValue(const std::string& name) {
return base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
name.c_str());
}
void AppendSwitch(const std::string& switch_string, mate::Arguments* args) {
auto* command_line = base::CommandLine::ForCurrentProcess();
if (base::EndsWith(switch_string, "-path",
base::CompareCase::INSENSITIVE_ASCII) ||
switch_string == network::switches::kLogNetLog) {
base::FilePath path;
args->GetNext(&path);
command_line->AppendSwitchPath(switch_string, path);
return;
}
base::CommandLine::StringType value;
if (args->GetNext(&value))
command_line->AppendSwitchNative(switch_string, value);
else
command_line->AppendSwitch(switch_string);
}
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
auto* command_line = base::CommandLine::ForCurrentProcess();
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("hasSwitch", &HasSwitch);
dict.SetMethod("getSwitchValue", &GetSwitchValue);
dict.SetMethod("appendSwitch", &AppendSwitch);
dict.SetMethod("appendArgument",
base::BindRepeating(&base::CommandLine::AppendArg,
base::Unretained(command_line)));
}
} // namespace
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_command_line, Initialize)

View file

@ -0,0 +1,65 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <map>
#include <string>
#include "atom/common/crash_reporter/crash_reporter.h"
#include "atom/common/gin_util.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/map_converter.h"
#include "base/bind.h"
#include "gin/data_object_builder.h"
#include "gin/dictionary.h"
#include "atom/common/node_includes.h"
using crash_reporter::CrashReporter;
namespace gin {
template <>
struct Converter<CrashReporter::UploadReportResult> {
static v8::Local<v8::Value> ToV8(
v8::Isolate* isolate,
const CrashReporter::UploadReportResult& reports) {
return gin::DataObjectBuilder(isolate)
.Set("date",
v8::Date::New(isolate->GetCurrentContext(), reports.first * 1000.0)
.ToLocalChecked())
.Set("id", reports.second)
.Build();
}
};
} // namespace gin
namespace {
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
using gin_util::SetMethod;
auto reporter = base::Unretained(CrashReporter::GetInstance());
SetMethod(exports, "start",
base::BindRepeating(&CrashReporter::Start, reporter));
SetMethod(exports, "addExtraParameter",
base::BindRepeating(&CrashReporter::AddExtraParameter, reporter));
SetMethod(
exports, "removeExtraParameter",
base::BindRepeating(&CrashReporter::RemoveExtraParameter, reporter));
SetMethod(exports, "getParameters",
base::BindRepeating(&CrashReporter::GetParameters, reporter));
SetMethod(exports, "getUploadedReports",
base::BindRepeating(&CrashReporter::GetUploadedReports, reporter));
SetMethod(exports, "setUploadToServer",
base::BindRepeating(&CrashReporter::SetUploadToServer, reporter));
SetMethod(exports, "getUploadToServer",
base::BindRepeating(&CrashReporter::GetUploadToServer, reporter));
}
} // namespace
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_crash_reporter, Initialize)

View file

@ -0,0 +1,63 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_ATOM_API_KEY_WEAK_MAP_H_
#define ATOM_COMMON_API_ATOM_API_KEY_WEAK_MAP_H_
#include "atom/common/key_weak_map.h"
#include "native_mate/handle.h"
#include "native_mate/object_template_builder.h"
#include "native_mate/wrappable.h"
namespace atom {
namespace api {
template <typename K>
class KeyWeakMap : public mate::Wrappable<KeyWeakMap<K>> {
public:
static mate::Handle<KeyWeakMap<K>> Create(v8::Isolate* isolate) {
return mate::CreateHandle(isolate, new KeyWeakMap<K>(isolate));
}
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(mate::StringToV8(isolate, "KeyWeakMap"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.SetMethod("set", &KeyWeakMap<K>::Set)
.SetMethod("get", &KeyWeakMap<K>::Get)
.SetMethod("has", &KeyWeakMap<K>::Has)
.SetMethod("remove", &KeyWeakMap<K>::Remove);
}
protected:
explicit KeyWeakMap(v8::Isolate* isolate) {
mate::Wrappable<KeyWeakMap<K>>::Init(isolate);
}
~KeyWeakMap() override {}
private:
// API for KeyWeakMap.
void Set(v8::Isolate* isolate, const K& key, v8::Local<v8::Object> object) {
key_weak_map_.Set(isolate, key, object);
}
v8::Local<v8::Object> Get(v8::Isolate* isolate, const K& key) {
return key_weak_map_.Get(isolate, key).ToLocalChecked();
}
bool Has(const K& key) { return key_weak_map_.Has(key); }
void Remove(const K& key) { key_weak_map_.Remove(key); }
atom::KeyWeakMap<K> key_weak_map_;
DISALLOW_COPY_AND_ASSIGN(KeyWeakMap);
};
} // namespace api
} // namespace atom
#endif // ATOM_COMMON_API_ATOM_API_KEY_WEAK_MAP_H_

View file

@ -0,0 +1,713 @@
// 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 "atom/common/api/atom_api_native_image.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "atom/common/asar/asar_util.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/node_includes.h"
#include "base/files/file_util.h"
#include "base/strings/pattern.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "native_mate/object_template_builder.h"
#include "net/base/data_url.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkPixelRef.h"
#include "ui/base/layout.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_util.h"
#if defined(OS_WIN)
#include "atom/common/asar/archive.h"
#include "base/win/scoped_gdi_object.h"
#include "ui/gfx/icon_util.h"
#endif
namespace atom {
namespace api {
namespace {
struct ScaleFactorPair {
const char* name;
float scale;
};
ScaleFactorPair kScaleFactorPairs[] = {
// The "@2x" is put as first one to make scale matching faster.
{"@2x", 2.0f}, {"@3x", 3.0f}, {"@1x", 1.0f}, {"@4x", 4.0f},
{"@5x", 5.0f}, {"@1.25x", 1.25f}, {"@1.33x", 1.33f}, {"@1.4x", 1.4f},
{"@1.5x", 1.5f}, {"@1.8x", 1.8f}, {"@2.5x", 2.5f},
};
float GetScaleFactorFromPath(const base::FilePath& path) {
std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe());
// We don't try to convert string to float here because it is very very
// expensive.
for (const auto& kScaleFactorPair : kScaleFactorPairs) {
if (base::EndsWith(filename, kScaleFactorPair.name,
base::CompareCase::INSENSITIVE_ASCII))
return kScaleFactorPair.scale;
}
return 1.0f;
}
// Get the scale factor from options object at the first argument
float GetScaleFactorFromOptions(mate::Arguments* args) {
float scale_factor = 1.0f;
mate::Dictionary options;
if (args->GetNext(&options))
options.Get("scaleFactor", &scale_factor);
return scale_factor;
}
bool AddImageSkiaRepFromPNG(gfx::ImageSkia* image,
const unsigned char* data,
size_t size,
double scale_factor) {
SkBitmap bitmap;
if (!gfx::PNGCodec::Decode(data, size, &bitmap))
return false;
image->AddRepresentation(gfx::ImageSkiaRep(bitmap, scale_factor));
return true;
}
bool AddImageSkiaRepFromJPEG(gfx::ImageSkia* image,
const unsigned char* data,
size_t size,
double scale_factor) {
auto bitmap = gfx::JPEGCodec::Decode(data, size);
if (!bitmap)
return false;
// `JPEGCodec::Decode()` doesn't tell `SkBitmap` instance it creates
// that all of its pixels are opaque, that's why the bitmap gets
// an alpha type `kPremul_SkAlphaType` instead of `kOpaque_SkAlphaType`.
// Let's fix it here.
// TODO(alexeykuzmin): This workaround should be removed
// when the `JPEGCodec::Decode()` code is fixed.
// See https://github.com/electron/electron/issues/11294.
bitmap->setAlphaType(SkAlphaType::kOpaque_SkAlphaType);
image->AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale_factor));
return true;
}
bool AddImageSkiaRepFromBuffer(gfx::ImageSkia* image,
const unsigned char* data,
size_t size,
int width,
int height,
double scale_factor) {
// Try PNG first.
if (AddImageSkiaRepFromPNG(image, data, size, scale_factor))
return true;
// Try JPEG second.
if (AddImageSkiaRepFromJPEG(image, data, size, scale_factor))
return true;
if (width == 0 || height == 0)
return false;
auto info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType);
if (size < info.computeMinByteSize())
return false;
SkBitmap bitmap;
bitmap.allocN32Pixels(width, height, false);
bitmap.writePixels({info, data, bitmap.rowBytes()});
image->AddRepresentation(gfx::ImageSkiaRep(bitmap, scale_factor));
return true;
}
bool AddImageSkiaRepFromPath(gfx::ImageSkia* image,
const base::FilePath& path,
double scale_factor) {
std::string file_contents;
{
base::ThreadRestrictions::ScopedAllowIO allow_io;
if (!asar::ReadFileToString(path, &file_contents))
return false;
}
const unsigned char* data =
reinterpret_cast<const unsigned char*>(file_contents.data());
size_t size = file_contents.size();
return AddImageSkiaRepFromBuffer(image, data, size, 0, 0, scale_factor);
}
bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image,
const base::FilePath& path) {
bool succeed = false;
std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe());
if (base::MatchPattern(filename, "*@*x"))
// Don't search for other representations if the DPI has been specified.
return AddImageSkiaRepFromPath(image, path, GetScaleFactorFromPath(path));
else
succeed |= AddImageSkiaRepFromPath(image, path, 1.0f);
for (const ScaleFactorPair& pair : kScaleFactorPairs)
succeed |= AddImageSkiaRepFromPath(
image, path.InsertBeforeExtensionASCII(pair.name), pair.scale);
return succeed;
}
base::FilePath NormalizePath(const base::FilePath& path) {
if (!path.ReferencesParent()) {
return path;
}
base::FilePath absolute_path = MakeAbsoluteFilePath(path);
// MakeAbsoluteFilePath returns an empty path on failures so use original path
if (absolute_path.empty()) {
return path;
} else {
return absolute_path;
}
}
#if defined(OS_MACOSX)
bool IsTemplateFilename(const base::FilePath& path) {
return (base::MatchPattern(path.value(), "*Template.*") ||
base::MatchPattern(path.value(), "*Template@*x.*"));
}
#endif
#if defined(OS_WIN)
base::win::ScopedHICON ReadICOFromPath(int size, const base::FilePath& path) {
// If file is in asar archive, we extract it to a temp file so LoadImage can
// load it.
base::FilePath asar_path, relative_path;
base::FilePath image_path(path);
if (asar::GetAsarArchivePath(image_path, &asar_path, &relative_path)) {
std::shared_ptr<asar::Archive> archive =
asar::GetOrCreateAsarArchive(asar_path);
if (archive)
archive->CopyFileOut(relative_path, &image_path);
}
// Load the icon from file.
return base::win::ScopedHICON(
static_cast<HICON>(LoadImage(NULL, image_path.value().c_str(), IMAGE_ICON,
size, size, LR_LOADFROMFILE)));
}
bool ReadImageSkiaFromICO(gfx::ImageSkia* image, HICON icon) {
// Convert the icon from the Windows specific HICON to gfx::ImageSkia.
SkBitmap bitmap = IconUtil::CreateSkBitmapFromHICON(icon);
if (bitmap.isNull())
return false;
image->AddRepresentation(gfx::ImageSkiaRep(bitmap, 1.0f));
return true;
}
#endif
void Noop(char*, void*) {}
} // namespace
NativeImage::NativeImage(v8::Isolate* isolate, const gfx::Image& image)
: image_(image) {
Init(isolate);
if (image_.HasRepresentation(gfx::Image::kImageRepSkia)) {
isolate->AdjustAmountOfExternalAllocatedMemory(
image_.ToImageSkia()->bitmap()->computeByteSize());
}
}
#if defined(OS_WIN)
NativeImage::NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path)
: hicon_path_(hicon_path) {
// Use the 256x256 icon as fallback icon.
gfx::ImageSkia image_skia;
ReadImageSkiaFromICO(&image_skia, GetHICON(256));
image_ = gfx::Image(image_skia);
Init(isolate);
if (image_.HasRepresentation(gfx::Image::kImageRepSkia)) {
isolate->AdjustAmountOfExternalAllocatedMemory(
image_.ToImageSkia()->bitmap()->computeByteSize());
}
}
#endif
NativeImage::~NativeImage() {
if (image_.HasRepresentation(gfx::Image::kImageRepSkia)) {
isolate()->AdjustAmountOfExternalAllocatedMemory(-static_cast<int64_t>(
image_.ToImageSkia()->bitmap()->computeByteSize()));
}
}
#if defined(OS_WIN)
HICON NativeImage::GetHICON(int size) {
auto iter = hicons_.find(size);
if (iter != hicons_.end())
return iter->second.get();
// First try loading the icon with specified size.
if (!hicon_path_.empty()) {
hicons_[size] = ReadICOFromPath(size, hicon_path_);
return hicons_[size].get();
}
// Then convert the image to ICO.
if (image_.IsEmpty())
return NULL;
hicons_[size] = IconUtil::CreateHICONFromSkBitmap(image_.AsBitmap());
return hicons_[size].get();
}
#endif
v8::Local<v8::Value> NativeImage::ToPNG(mate::Arguments* args) {
float scale_factor = GetScaleFactorFromOptions(args);
if (scale_factor == 1.0f) {
// Use raw 1x PNG bytes when available
scoped_refptr<base::RefCountedMemory> png = image_.As1xPNGBytes();
if (png->size() > 0) {
const char* data = reinterpret_cast<const char*>(png->front());
size_t size = png->size();
return node::Buffer::Copy(args->isolate(), data, size).ToLocalChecked();
}
}
const SkBitmap bitmap =
image_.AsImageSkia().GetRepresentation(scale_factor).GetBitmap();
std::vector<unsigned char> encoded;
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &encoded);
const char* data = reinterpret_cast<char*>(encoded.data());
size_t size = encoded.size();
return node::Buffer::Copy(args->isolate(), data, size).ToLocalChecked();
}
v8::Local<v8::Value> NativeImage::ToBitmap(mate::Arguments* args) {
float scale_factor = GetScaleFactorFromOptions(args);
const SkBitmap bitmap =
image_.AsImageSkia().GetRepresentation(scale_factor).GetBitmap();
SkPixelRef* ref = bitmap.pixelRef();
if (!ref)
return node::Buffer::New(args->isolate(), 0).ToLocalChecked();
return node::Buffer::Copy(args->isolate(),
reinterpret_cast<const char*>(ref->pixels()),
bitmap.computeByteSize())
.ToLocalChecked();
}
v8::Local<v8::Value> NativeImage::ToJPEG(v8::Isolate* isolate, int quality) {
std::vector<unsigned char> output;
gfx::JPEG1xEncodedDataFromImage(image_, quality, &output);
if (output.empty())
return node::Buffer::New(isolate, 0).ToLocalChecked();
return node::Buffer::Copy(isolate,
reinterpret_cast<const char*>(&output.front()),
output.size())
.ToLocalChecked();
}
std::string NativeImage::ToDataURL(mate::Arguments* args) {
float scale_factor = GetScaleFactorFromOptions(args);
if (scale_factor == 1.0f) {
// Use raw 1x PNG bytes when available
scoped_refptr<base::RefCountedMemory> png = image_.As1xPNGBytes();
if (png->size() > 0)
return webui::GetPngDataUrl(png->front(), png->size());
}
return webui::GetBitmapDataUrl(
image_.AsImageSkia().GetRepresentation(scale_factor).GetBitmap());
}
v8::Local<v8::Value> NativeImage::GetBitmap(mate::Arguments* args) {
float scale_factor = GetScaleFactorFromOptions(args);
const SkBitmap bitmap =
image_.AsImageSkia().GetRepresentation(scale_factor).GetBitmap();
SkPixelRef* ref = bitmap.pixelRef();
if (!ref)
return node::Buffer::New(args->isolate(), 0).ToLocalChecked();
return node::Buffer::New(args->isolate(),
reinterpret_cast<char*>(ref->pixels()),
bitmap.computeByteSize(), &Noop, nullptr)
.ToLocalChecked();
}
v8::Local<v8::Value> NativeImage::GetNativeHandle(v8::Isolate* isolate,
mate::Arguments* args) {
#if defined(OS_MACOSX)
if (IsEmpty())
return node::Buffer::New(isolate, 0).ToLocalChecked();
NSImage* ptr = image_.AsNSImage();
return node::Buffer::Copy(isolate, reinterpret_cast<char*>(ptr),
sizeof(void*))
.ToLocalChecked();
#else
args->ThrowError("Not implemented");
return v8::Undefined(isolate);
#endif
}
bool NativeImage::IsEmpty() {
return image_.IsEmpty();
}
gfx::Size NativeImage::GetSize() {
return image_.Size();
}
float NativeImage::GetAspectRatio() {
gfx::Size size = GetSize();
if (size.IsEmpty())
return 1.f;
else
return static_cast<float>(size.width()) / static_cast<float>(size.height());
}
mate::Handle<NativeImage> NativeImage::Resize(
v8::Isolate* isolate,
const base::DictionaryValue& options) {
gfx::Size size = GetSize();
int width = size.width();
int height = size.height();
bool width_set = options.GetInteger("width", &width);
bool height_set = options.GetInteger("height", &height);
size.SetSize(width, height);
if (width_set && !height_set) {
// Scale height to preserve original aspect ratio
size.set_height(width);
size = gfx::ScaleToRoundedSize(size, 1.f, 1.f / GetAspectRatio());
} else if (height_set && !width_set) {
// Scale width to preserve original aspect ratio
size.set_width(height);
size = gfx::ScaleToRoundedSize(size, GetAspectRatio(), 1.f);
}
skia::ImageOperations::ResizeMethod method =
skia::ImageOperations::ResizeMethod::RESIZE_BEST;
std::string quality;
options.GetString("quality", &quality);
if (quality == "good")
method = skia::ImageOperations::ResizeMethod::RESIZE_GOOD;
else if (quality == "better")
method = skia::ImageOperations::ResizeMethod::RESIZE_BETTER;
gfx::ImageSkia resized = gfx::ImageSkiaOperations::CreateResizedImage(
image_.AsImageSkia(), method, size);
return mate::CreateHandle(isolate,
new NativeImage(isolate, gfx::Image(resized)));
}
mate::Handle<NativeImage> NativeImage::Crop(v8::Isolate* isolate,
const gfx::Rect& rect) {
gfx::ImageSkia cropped =
gfx::ImageSkiaOperations::ExtractSubset(image_.AsImageSkia(), rect);
return mate::CreateHandle(isolate,
new NativeImage(isolate, gfx::Image(cropped)));
}
void NativeImage::AddRepresentation(const mate::Dictionary& options) {
int width = 0;
int height = 0;
float scale_factor = 1.0f;
options.Get("width", &width);
options.Get("height", &height);
options.Get("scaleFactor", &scale_factor);
bool skia_rep_added = false;
gfx::ImageSkia image_skia = image_.AsImageSkia();
v8::Local<v8::Value> buffer;
GURL url;
if (options.Get("buffer", &buffer) && node::Buffer::HasInstance(buffer)) {
auto* data = reinterpret_cast<unsigned char*>(node::Buffer::Data(buffer));
auto size = node::Buffer::Length(buffer);
skia_rep_added = AddImageSkiaRepFromBuffer(&image_skia, data, size, width,
height, scale_factor);
} else if (options.Get("dataURL", &url)) {
std::string mime_type, charset, data;
if (net::DataURL::Parse(url, &mime_type, &charset, &data)) {
auto* data_ptr = reinterpret_cast<const unsigned char*>(data.c_str());
if (mime_type == "image/png") {
skia_rep_added = AddImageSkiaRepFromPNG(&image_skia, data_ptr,
data.size(), scale_factor);
} else if (mime_type == "image/jpeg") {
skia_rep_added = AddImageSkiaRepFromJPEG(&image_skia, data_ptr,
data.size(), scale_factor);
}
}
}
// Re-initialize image when first representation is added to an empty image
if (skia_rep_added && IsEmpty()) {
gfx::Image image(image_skia);
image_ = std::move(image);
}
}
#if !defined(OS_MACOSX)
void NativeImage::SetTemplateImage(bool setAsTemplate) {}
bool NativeImage::IsTemplateImage() {
return false;
}
#endif
// static
mate::Handle<NativeImage> NativeImage::CreateEmpty(v8::Isolate* isolate) {
return mate::CreateHandle(isolate, new NativeImage(isolate, gfx::Image()));
}
// static
mate::Handle<NativeImage> NativeImage::Create(v8::Isolate* isolate,
const gfx::Image& image) {
return mate::CreateHandle(isolate, new NativeImage(isolate, image));
}
// static
mate::Handle<NativeImage> NativeImage::CreateFromPNG(v8::Isolate* isolate,
const char* buffer,
size_t length) {
gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
reinterpret_cast<const unsigned char*>(buffer), length);
return Create(isolate, image);
}
// static
mate::Handle<NativeImage> NativeImage::CreateFromJPEG(v8::Isolate* isolate,
const char* buffer,
size_t length) {
gfx::Image image = gfx::ImageFrom1xJPEGEncodedData(
reinterpret_cast<const unsigned char*>(buffer), length);
return Create(isolate, image);
}
// static
mate::Handle<NativeImage> NativeImage::CreateFromPath(
v8::Isolate* isolate,
const base::FilePath& path) {
base::FilePath image_path = NormalizePath(path);
#if defined(OS_WIN)
if (image_path.MatchesExtension(FILE_PATH_LITERAL(".ico"))) {
return mate::CreateHandle(isolate, new NativeImage(isolate, image_path));
}
#endif
gfx::ImageSkia image_skia;
PopulateImageSkiaRepsFromPath(&image_skia, image_path);
gfx::Image image(image_skia);
mate::Handle<NativeImage> handle = Create(isolate, image);
#if defined(OS_MACOSX)
if (IsTemplateFilename(image_path))
handle->SetTemplateImage(true);
#endif
return handle;
}
// static
mate::Handle<NativeImage> NativeImage::CreateFromBitmap(
mate::Arguments* args,
v8::Local<v8::Value> buffer,
const mate::Dictionary& options) {
if (!node::Buffer::HasInstance(buffer)) {
args->ThrowError("buffer must be a node Buffer");
return mate::Handle<NativeImage>();
}
unsigned int width = 0;
unsigned int height = 0;
double scale_factor = 1.;
if (!options.Get("width", &width)) {
args->ThrowError("width is required");
return mate::Handle<NativeImage>();
}
if (!options.Get("height", &height)) {
args->ThrowError("height is required");
return mate::Handle<NativeImage>();
}
auto info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType);
auto size_bytes = info.computeMinByteSize();
if (size_bytes != node::Buffer::Length(buffer)) {
args->ThrowError("invalid buffer size");
return mate::Handle<NativeImage>();
}
options.Get("scaleFactor", &scale_factor);
if (width == 0 || height == 0) {
return CreateEmpty(args->isolate());
}
SkBitmap bitmap;
bitmap.allocN32Pixels(width, height, false);
bitmap.writePixels({info, node::Buffer::Data(buffer), bitmap.rowBytes()});
gfx::ImageSkia image_skia;
image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale_factor));
return Create(args->isolate(), gfx::Image(image_skia));
}
// static
mate::Handle<NativeImage> NativeImage::CreateFromBuffer(
mate::Arguments* args,
v8::Local<v8::Value> buffer) {
if (!node::Buffer::HasInstance(buffer)) {
args->ThrowError("buffer must be a node Buffer");
return mate::Handle<NativeImage>();
}
int width = 0;
int height = 0;
double scale_factor = 1.;
mate::Dictionary options;
if (args->GetNext(&options)) {
options.Get("width", &width);
options.Get("height", &height);
options.Get("scaleFactor", &scale_factor);
}
gfx::ImageSkia image_skia;
AddImageSkiaRepFromBuffer(
&image_skia, reinterpret_cast<unsigned char*>(node::Buffer::Data(buffer)),
node::Buffer::Length(buffer), width, height, scale_factor);
return Create(args->isolate(), gfx::Image(image_skia));
}
// static
mate::Handle<NativeImage> NativeImage::CreateFromDataURL(v8::Isolate* isolate,
const GURL& url) {
std::string mime_type, charset, data;
if (net::DataURL::Parse(url, &mime_type, &charset, &data)) {
if (mime_type == "image/png")
return CreateFromPNG(isolate, data.c_str(), data.size());
else if (mime_type == "image/jpeg")
return CreateFromJPEG(isolate, data.c_str(), data.size());
}
return CreateEmpty(isolate);
}
#if !defined(OS_MACOSX)
mate::Handle<NativeImage> NativeImage::CreateFromNamedImage(
mate::Arguments* args,
const std::string& name) {
return CreateEmpty(args->isolate());
}
#endif
// static
void NativeImage::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(mate::StringToV8(isolate, "NativeImage"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.SetMethod("toPNG", &NativeImage::ToPNG)
.SetMethod("toJPEG", &NativeImage::ToJPEG)
.SetMethod("toBitmap", &NativeImage::ToBitmap)
.SetMethod("getBitmap", &NativeImage::GetBitmap)
.SetMethod("getNativeHandle", &NativeImage::GetNativeHandle)
.SetMethod("toDataURL", &NativeImage::ToDataURL)
.SetMethod("isEmpty", &NativeImage::IsEmpty)
.SetMethod("getSize", &NativeImage::GetSize)
.SetMethod("_setTemplateImage", &NativeImage::SetTemplateImage)
.SetMethod("_isTemplateImage", &NativeImage::IsTemplateImage)
.SetProperty("isMacTemplateImage", &NativeImage::IsTemplateImage,
&NativeImage::SetTemplateImage)
.SetMethod("resize", &NativeImage::Resize)
.SetMethod("crop", &NativeImage::Crop)
.SetMethod("getAspectRatio", &NativeImage::GetAspectRatio)
.SetMethod("addRepresentation", &NativeImage::AddRepresentation);
}
} // namespace api
} // namespace atom
namespace mate {
v8::Local<v8::Value> Converter<mate::Handle<atom::api::NativeImage>>::ToV8(
v8::Isolate* isolate,
const mate::Handle<atom::api::NativeImage>& val) {
return val.ToV8();
}
bool Converter<mate::Handle<atom::api::NativeImage>>::FromV8(
v8::Isolate* isolate,
v8::Local<v8::Value> val,
mate::Handle<atom::api::NativeImage>* out) {
// Try converting from file path.
base::FilePath path;
if (ConvertFromV8(isolate, val, &path)) {
*out = atom::api::NativeImage::CreateFromPath(isolate, path);
// Should throw when failed to initialize from path.
return !(*out)->image().IsEmpty();
}
WrappableBase* wrapper =
static_cast<WrappableBase*>(internal::FromV8Impl(isolate, val));
if (!wrapper)
return false;
*out = CreateHandle(isolate, static_cast<atom::api::NativeImage*>(wrapper));
return true;
}
} // namespace mate
namespace {
using atom::api::NativeImage;
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.Set("NativeImage", NativeImage::GetConstructor(isolate)
->GetFunction(context)
.ToLocalChecked());
mate::Dictionary native_image = mate::Dictionary::CreateEmpty(isolate);
dict.Set("nativeImage", native_image);
native_image.SetMethod("createEmpty", &NativeImage::CreateEmpty);
native_image.SetMethod("createFromPath", &NativeImage::CreateFromPath);
native_image.SetMethod("createFromBitmap", &NativeImage::CreateFromBitmap);
native_image.SetMethod("createFromBuffer", &NativeImage::CreateFromBuffer);
native_image.SetMethod("createFromDataURL", &NativeImage::CreateFromDataURL);
native_image.SetMethod("createFromNamedImage",
&NativeImage::CreateFromNamedImage);
}
} // namespace
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_native_image, Initialize)

View file

@ -0,0 +1,133 @@
// 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 ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_
#define ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_
#include <map>
#include <string>
#include "base/values.h"
#include "native_mate/dictionary.h"
#include "native_mate/handle.h"
#include "native_mate/wrappable.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/image/image.h"
#if defined(OS_WIN)
#include "base/files/file_path.h"
#include "base/win/scoped_gdi_object.h"
#endif
class GURL;
namespace base {
class FilePath;
}
namespace gfx {
class Size;
}
namespace mate {
class Arguments;
}
namespace atom {
namespace api {
class NativeImage : public mate::Wrappable<NativeImage> {
public:
static mate::Handle<NativeImage> CreateEmpty(v8::Isolate* isolate);
static mate::Handle<NativeImage> Create(v8::Isolate* isolate,
const gfx::Image& image);
static mate::Handle<NativeImage> CreateFromPNG(v8::Isolate* isolate,
const char* buffer,
size_t length);
static mate::Handle<NativeImage> CreateFromJPEG(v8::Isolate* isolate,
const char* buffer,
size_t length);
static mate::Handle<NativeImage> CreateFromPath(v8::Isolate* isolate,
const base::FilePath& path);
static mate::Handle<NativeImage> CreateFromBitmap(
mate::Arguments* args,
v8::Local<v8::Value> buffer,
const mate::Dictionary& options);
static mate::Handle<NativeImage> CreateFromBuffer(
mate::Arguments* args,
v8::Local<v8::Value> buffer);
static mate::Handle<NativeImage> CreateFromDataURL(v8::Isolate* isolate,
const GURL& url);
static mate::Handle<NativeImage> CreateFromNamedImage(
mate::Arguments* args,
const std::string& name);
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype);
#if defined(OS_WIN)
HICON GetHICON(int size);
#endif
const gfx::Image& image() const { return image_; }
protected:
NativeImage(v8::Isolate* isolate, const gfx::Image& image);
#if defined(OS_WIN)
NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path);
#endif
~NativeImage() override;
private:
v8::Local<v8::Value> ToPNG(mate::Arguments* args);
v8::Local<v8::Value> ToJPEG(v8::Isolate* isolate, int quality);
v8::Local<v8::Value> ToBitmap(mate::Arguments* args);
v8::Local<v8::Value> GetBitmap(mate::Arguments* args);
v8::Local<v8::Value> GetNativeHandle(v8::Isolate* isolate,
mate::Arguments* args);
mate::Handle<NativeImage> Resize(v8::Isolate* isolate,
const base::DictionaryValue& options);
mate::Handle<NativeImage> Crop(v8::Isolate* isolate, const gfx::Rect& rect);
std::string ToDataURL(mate::Arguments* args);
bool IsEmpty();
gfx::Size GetSize();
float GetAspectRatio();
void AddRepresentation(const mate::Dictionary& options);
// Mark the image as template image.
void SetTemplateImage(bool setAsTemplate);
// Determine if the image is a template image.
bool IsTemplateImage();
#if defined(OS_WIN)
base::FilePath hicon_path_;
std::map<int, base::win::ScopedHICON> hicons_;
#endif
gfx::Image image_;
DISALLOW_COPY_AND_ASSIGN(NativeImage);
};
} // namespace api
} // namespace atom
namespace mate {
// A custom converter that allows converting path to NativeImage.
template <>
struct Converter<mate::Handle<atom::api::NativeImage>> {
static v8::Local<v8::Value> ToV8(
v8::Isolate* isolate,
const mate::Handle<atom::api::NativeImage>& val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
mate::Handle<atom::api::NativeImage>* out);
};
} // namespace mate
#endif // ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_

View file

@ -0,0 +1,76 @@
// 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 "atom/common/api/atom_api_native_image.h"
#include <string>
#include <vector>
#import <Cocoa/Cocoa.h>
#include "base/strings/sys_string_conversions.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
namespace atom {
namespace api {
NSData* bufferFromNSImage(NSImage* image) {
CGImageRef ref = [image CGImageForProposedRect:nil context:nil hints:nil];
NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithCGImage:ref];
[rep setSize:[image size]];
return [rep representationUsingType:NSPNGFileType
properties:[[NSDictionary alloc] init]];
}
double safeShift(double in, double def) {
if (in >= 0 || in <= 1 || in == def)
return in;
return def;
}
mate::Handle<NativeImage> NativeImage::CreateFromNamedImage(
mate::Arguments* args,
const std::string& name) {
@autoreleasepool {
std::vector<double> hsl_shift;
NSImage* image = [NSImage imageNamed:base::SysUTF8ToNSString(name)];
if (!image.valid) {
return CreateEmpty(args->isolate());
}
NSData* png_data = bufferFromNSImage(image);
if (args->GetNext(&hsl_shift) && hsl_shift.size() == 3) {
gfx::Image gfx_image = gfx::Image::CreateFrom1xPNGBytes(
reinterpret_cast<const unsigned char*>((char*)[png_data bytes]),
[png_data length]);
color_utils::HSL shift = {safeShift(hsl_shift[0], -1),
safeShift(hsl_shift[1], 0.5),
safeShift(hsl_shift[2], 0.5)};
png_data = bufferFromNSImage(
gfx::Image(gfx::ImageSkiaOperations::CreateHSLShiftedImage(
gfx_image.AsImageSkia(), shift))
.AsNSImage());
}
return CreateFromPNG(args->isolate(), (char*)[png_data bytes],
[png_data length]);
}
}
void NativeImage::SetTemplateImage(bool setAsTemplate) {
[image_.AsNSImage() setTemplate:setAsTemplate];
}
bool NativeImage::IsTemplateImage() {
return [image_.AsNSImage() isTemplate];
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,147 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <string>
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/node_includes.h"
#include "atom/common/platform_util.h"
#include "atom/common/promise_util.h"
#include "native_mate/dictionary.h"
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
#include "base/win/shortcut.h"
namespace mate {
template <>
struct Converter<base::win::ShortcutOperation> {
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
base::win::ShortcutOperation* out) {
std::string operation;
if (!ConvertFromV8(isolate, val, &operation))
return false;
if (operation.empty() || operation == "create")
*out = base::win::SHORTCUT_CREATE_ALWAYS;
else if (operation == "update")
*out = base::win::SHORTCUT_UPDATE_EXISTING;
else if (operation == "replace")
*out = base::win::SHORTCUT_REPLACE_EXISTING;
else
return false;
return true;
}
};
} // namespace mate
#endif
namespace {
void OnOpenExternalFinished(atom::util::Promise promise,
const std::string& error) {
if (error.empty())
promise.Resolve();
else
promise.RejectWithErrorMessage(error.c_str());
}
v8::Local<v8::Promise> OpenExternal(const GURL& url, mate::Arguments* args) {
atom::util::Promise promise(args->isolate());
v8::Local<v8::Promise> handle = promise.GetHandle();
platform_util::OpenExternalOptions options;
if (args->Length() >= 2) {
mate::Dictionary obj;
if (args->GetNext(&obj)) {
obj.Get("activate", &options.activate);
obj.Get("workingDirectory", &options.working_dir);
}
}
platform_util::OpenExternal(
url, options,
base::BindOnce(&OnOpenExternalFinished, std::move(promise)));
return handle;
}
#if defined(OS_WIN)
bool WriteShortcutLink(const base::FilePath& shortcut_path,
mate::Arguments* args) {
base::win::ShortcutOperation operation = base::win::SHORTCUT_CREATE_ALWAYS;
args->GetNext(&operation);
mate::Dictionary options = mate::Dictionary::CreateEmpty(args->isolate());
if (!args->GetNext(&options)) {
args->ThrowError();
return false;
}
base::win::ShortcutProperties properties;
base::FilePath path;
base::string16 str;
int index;
if (options.Get("target", &path))
properties.set_target(path);
if (options.Get("cwd", &path))
properties.set_working_dir(path);
if (options.Get("args", &str))
properties.set_arguments(str);
if (options.Get("description", &str))
properties.set_description(str);
if (options.Get("icon", &path) && options.Get("iconIndex", &index))
properties.set_icon(path, index);
if (options.Get("appUserModelId", &str))
properties.set_app_id(str);
base::win::ScopedCOMInitializer com_initializer;
return base::win::CreateOrUpdateShortcutLink(shortcut_path, properties,
operation);
}
v8::Local<v8::Value> ReadShortcutLink(mate::Arguments* args,
const base::FilePath& path) {
using base::win::ShortcutProperties;
mate::Dictionary options = mate::Dictionary::CreateEmpty(args->isolate());
base::win::ScopedCOMInitializer com_initializer;
base::win::ShortcutProperties properties;
if (!base::win::ResolveShortcutProperties(
path, ShortcutProperties::PROPERTIES_ALL, &properties)) {
args->ThrowError("Failed to read shortcut link");
return v8::Null(args->isolate());
}
options.Set("target", properties.target);
options.Set("cwd", properties.working_dir);
options.Set("args", properties.arguments);
options.Set("description", properties.description);
options.Set("icon", properties.icon);
options.Set("iconIndex", properties.icon_index);
options.Set("appUserModelId", properties.app_id);
return options.GetHandle();
}
#endif
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("showItemInFolder", &platform_util::ShowItemInFolder);
dict.SetMethod("openItem", &platform_util::OpenItem);
dict.SetMethod("openExternal", &OpenExternal);
dict.SetMethod("moveItemToTrash", &platform_util::MoveItemToTrash);
dict.SetMethod("beep", &platform_util::Beep);
#if defined(OS_WIN)
dict.SetMethod("writeShortcutLink", &WriteShortcutLink);
dict.SetMethod("readShortcutLink", &ReadShortcutLink);
#endif
}
} // namespace
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_shell, Initialize)

View file

@ -0,0 +1,134 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <string>
#include <utility>
#include "atom/common/api/atom_api_key_weak_map.h"
#include "atom/common/api/remote_callback_freer.h"
#include "atom/common/api/remote_object_freer.h"
#include "atom/common/native_mate_converters/content_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/node_includes.h"
#include "base/hash/hash.h"
#include "native_mate/dictionary.h"
#include "url/origin.h"
#include "v8/include/v8-profiler.h"
namespace std {
// The hash function used by DoubleIDWeakMap.
template <typename Type1, typename Type2>
struct hash<std::pair<Type1, Type2>> {
std::size_t operator()(std::pair<Type1, Type2> value) const {
return base::HashInts(base::Hash(value.first), value.second);
}
};
} // namespace std
namespace mate {
template <typename Type1, typename Type2>
struct Converter<std::pair<Type1, Type2>> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
std::pair<Type1, Type2>* out) {
if (!val->IsArray())
return false;
v8::Local<v8::Array> array(v8::Local<v8::Array>::Cast(val));
if (array->Length() != 2)
return false;
auto context = isolate->GetCurrentContext();
return Converter<Type1>::FromV8(
isolate, array->Get(context, 0).ToLocalChecked(), &out->first) &&
Converter<Type2>::FromV8(
isolate, array->Get(context, 1).ToLocalChecked(), &out->second);
}
};
} // namespace mate
namespace {
v8::Local<v8::Value> GetHiddenValue(v8::Isolate* isolate,
v8::Local<v8::Object> object,
v8::Local<v8::String> key) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Private> privateKey = v8::Private::ForApi(isolate, key);
v8::Local<v8::Value> value;
v8::Maybe<bool> result = object->HasPrivate(context, privateKey);
if (!(result.IsJust() && result.FromJust()))
return v8::Local<v8::Value>();
if (object->GetPrivate(context, privateKey).ToLocal(&value))
return value;
return v8::Local<v8::Value>();
}
void SetHiddenValue(v8::Isolate* isolate,
v8::Local<v8::Object> object,
v8::Local<v8::String> key,
v8::Local<v8::Value> value) {
if (value.IsEmpty())
return;
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Private> privateKey = v8::Private::ForApi(isolate, key);
object->SetPrivate(context, privateKey, value);
}
void DeleteHiddenValue(v8::Isolate* isolate,
v8::Local<v8::Object> object,
v8::Local<v8::String> key) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Private> privateKey = v8::Private::ForApi(isolate, key);
// Actually deleting the value would make force the object into
// dictionary mode which is unnecessarily slow. Instead, we replace
// the hidden value with "undefined".
object->SetPrivate(context, privateKey, v8::Undefined(isolate));
}
int32_t GetObjectHash(v8::Local<v8::Object> object) {
return object->GetIdentityHash();
}
void TakeHeapSnapshot(v8::Isolate* isolate) {
isolate->GetHeapProfiler()->TakeHeapSnapshot();
}
void RequestGarbageCollectionForTesting(v8::Isolate* isolate) {
isolate->RequestGarbageCollectionForTesting(
v8::Isolate::GarbageCollectionType::kFullGarbageCollection);
}
bool IsSameOrigin(const GURL& l, const GURL& r) {
return url::Origin::Create(l).IsSameOriginWith(url::Origin::Create(r));
}
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("getHiddenValue", &GetHiddenValue);
dict.SetMethod("setHiddenValue", &SetHiddenValue);
dict.SetMethod("deleteHiddenValue", &DeleteHiddenValue);
dict.SetMethod("getObjectHash", &GetObjectHash);
dict.SetMethod("takeHeapSnapshot", &TakeHeapSnapshot);
dict.SetMethod("setRemoteCallbackFreer", &atom::RemoteCallbackFreer::BindTo);
dict.SetMethod("setRemoteObjectFreer", &atom::RemoteObjectFreer::BindTo);
dict.SetMethod("addRemoteObjectRef", &atom::RemoteObjectFreer::AddRef);
dict.SetMethod("createIDWeakMap", &atom::api::KeyWeakMap<int32_t>::Create);
dict.SetMethod(
"createDoubleIDWeakMap",
&atom::api::KeyWeakMap<std::pair<std::string, int32_t>>::Create);
dict.SetMethod("requestGarbageCollectionForTesting",
&RequestGarbageCollectionForTesting);
dict.SetMethod("isSameOrigin", &IsSameOrigin);
}
} // namespace
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_v8_util, Initialize)

View file

@ -0,0 +1,34 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_CONSTRUCTOR_H_
#define ATOM_COMMON_API_CONSTRUCTOR_H_
#include "native_mate/constructor.h"
namespace mate {
// Create a FunctionTemplate that can be "new"ed in JavaScript.
// It is user's responsibility to ensure this function is called for one type
// only ONCE in the program's whole lifetime, otherwise we would have memory
// leak.
template <typename T, typename Sig>
v8::Local<v8::Function> CreateConstructor(
v8::Isolate* isolate,
const base::RepeatingCallback<Sig>& func) {
#ifndef NDEBUG
static bool called = false;
CHECK(!called) << "CreateConstructor can only be called for one type once";
called = true;
#endif
v8::Local<v8::FunctionTemplate> templ = CreateFunctionTemplate(
isolate, base::BindRepeating(&mate::internal::InvokeNew<Sig>, func));
templ->InstanceTemplate()->SetInternalFieldCount(1);
T::BuildPrototype(isolate, templ);
return templ->GetFunction(isolate->GetCurrentContext()).ToLocalChecked();
}
} // namespace mate
#endif // ATOM_COMMON_API_CONSTRUCTOR_H_

View file

@ -0,0 +1,364 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/api/electron_bindings.h"
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include "atom/browser/browser.h"
#include "atom/common/api/locker.h"
#include "atom/common/application_info.h"
#include "atom/common/heap_snapshot.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/node_includes.h"
#include "atom/common/promise_util.h"
#include "base/logging.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/process/process_metrics_iocounters.h"
#include "base/system/sys_info.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/common/chrome_version.h"
#include "electron/electron_version.h"
#include "native_mate/dictionary.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "third_party/blink/renderer/platform/heap/process_heap.h" // nogncheck
namespace atom {
namespace {
// Dummy class type that used for crashing the program.
struct DummyClass {
bool crash;
};
// Called when there is a fatal error in V8, we just crash the process here so
// we can get the stack trace.
void FatalErrorCallback(const char* location, const char* message) {
LOG(ERROR) << "Fatal error in V8: " << location << " " << message;
ElectronBindings::Crash();
}
} // namespace
ElectronBindings::ElectronBindings(uv_loop_t* loop) {
uv_async_init(loop, &call_next_tick_async_, OnCallNextTick);
call_next_tick_async_.data = this;
metrics_ = base::ProcessMetrics::CreateCurrentProcessMetrics();
}
ElectronBindings::~ElectronBindings() {
uv_close(reinterpret_cast<uv_handle_t*>(&call_next_tick_async_), nullptr);
}
// static
void ElectronBindings::BindProcess(v8::Isolate* isolate,
mate::Dictionary* process,
base::ProcessMetrics* metrics) {
// These bindings are shared between sandboxed & unsandboxed renderers
process->SetMethod("crash", &Crash);
process->SetMethod("hang", &Hang);
process->SetMethod("log", &Log);
process->SetMethod("getCreationTime", &GetCreationTime);
process->SetMethod("getHeapStatistics", &GetHeapStatistics);
process->SetMethod("getBlinkMemoryInfo", &GetBlinkMemoryInfo);
process->SetMethod("getProcessMemoryInfo", &GetProcessMemoryInfo);
process->SetMethod("getSystemMemoryInfo", &GetSystemMemoryInfo);
process->SetMethod("getSystemVersion",
&base::SysInfo::OperatingSystemVersion);
process->SetMethod("getIOCounters", &GetIOCounters);
process->SetMethod("getCPUUsage",
base::BindRepeating(&ElectronBindings::GetCPUUsage,
base::Unretained(metrics)));
#if defined(MAS_BUILD)
process->SetReadOnly("mas", true);
#endif
#if defined(OS_WIN)
if (IsRunningInDesktopBridge())
process->SetReadOnly("windowsStore", true);
#endif
}
void ElectronBindings::BindTo(v8::Isolate* isolate,
v8::Local<v8::Object> process) {
isolate->SetFatalErrorHandler(FatalErrorCallback);
mate::Dictionary dict(isolate, process);
BindProcess(isolate, &dict, metrics_.get());
dict.SetMethod("takeHeapSnapshot", &TakeHeapSnapshot);
#if defined(OS_POSIX)
dict.SetMethod("setFdLimit", &base::IncreaseFdLimitTo);
#endif
dict.SetMethod("activateUvLoop",
base::BindRepeating(&ElectronBindings::ActivateUVLoop,
base::Unretained(this)));
mate::Dictionary versions;
if (dict.Get("versions", &versions)) {
versions.SetReadOnly(ELECTRON_PROJECT_NAME, ELECTRON_VERSION_STRING);
versions.SetReadOnly("chrome", CHROME_VERSION_STRING);
}
}
void ElectronBindings::EnvironmentDestroyed(node::Environment* env) {
auto it =
std::find(pending_next_ticks_.begin(), pending_next_ticks_.end(), env);
if (it != pending_next_ticks_.end())
pending_next_ticks_.erase(it);
}
void ElectronBindings::ActivateUVLoop(v8::Isolate* isolate) {
node::Environment* env = node::Environment::GetCurrent(isolate);
if (std::find(pending_next_ticks_.begin(), pending_next_ticks_.end(), env) !=
pending_next_ticks_.end())
return;
pending_next_ticks_.push_back(env);
uv_async_send(&call_next_tick_async_);
}
// static
void ElectronBindings::OnCallNextTick(uv_async_t* handle) {
ElectronBindings* self = static_cast<ElectronBindings*>(handle->data);
for (std::list<node::Environment*>::const_iterator it =
self->pending_next_ticks_.begin();
it != self->pending_next_ticks_.end(); ++it) {
node::Environment* env = *it;
mate::Locker locker(env->isolate());
v8::Context::Scope context_scope(env->context());
node::InternalCallbackScope scope(
env, v8::Local<v8::Object>(), {0, 0},
node::InternalCallbackScope::kAllowEmptyResource);
}
self->pending_next_ticks_.clear();
}
// static
void ElectronBindings::Log(const base::string16& message) {
std::cout << message << std::flush;
}
// static
void ElectronBindings::Crash() {
static_cast<DummyClass*>(nullptr)->crash = true;
}
// static
void ElectronBindings::Hang() {
for (;;)
base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
}
// static
v8::Local<v8::Value> ElectronBindings::GetHeapStatistics(v8::Isolate* isolate) {
v8::HeapStatistics v8_heap_stats;
isolate->GetHeapStatistics(&v8_heap_stats);
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("totalHeapSize",
static_cast<double>(v8_heap_stats.total_heap_size() >> 10));
dict.Set(
"totalHeapSizeExecutable",
static_cast<double>(v8_heap_stats.total_heap_size_executable() >> 10));
dict.Set("totalPhysicalSize",
static_cast<double>(v8_heap_stats.total_physical_size() >> 10));
dict.Set("totalAvailableSize",
static_cast<double>(v8_heap_stats.total_available_size() >> 10));
dict.Set("usedHeapSize",
static_cast<double>(v8_heap_stats.used_heap_size() >> 10));
dict.Set("heapSizeLimit",
static_cast<double>(v8_heap_stats.heap_size_limit() >> 10));
dict.Set("mallocedMemory",
static_cast<double>(v8_heap_stats.malloced_memory() >> 10));
dict.Set("peakMallocedMemory",
static_cast<double>(v8_heap_stats.peak_malloced_memory() >> 10));
dict.Set("doesZapGarbage",
static_cast<bool>(v8_heap_stats.does_zap_garbage()));
return dict.GetHandle();
}
// static
v8::Local<v8::Value> ElectronBindings::GetCreationTime(v8::Isolate* isolate) {
auto timeValue = base::Process::Current().CreationTime();
if (timeValue.is_null()) {
return v8::Null(isolate);
}
double jsTime = timeValue.ToJsTime();
return v8::Number::New(isolate, jsTime);
}
// static
v8::Local<v8::Value> ElectronBindings::GetSystemMemoryInfo(
v8::Isolate* isolate,
mate::Arguments* args) {
base::SystemMemoryInfoKB mem_info;
if (!base::GetSystemMemoryInfo(&mem_info)) {
args->ThrowError("Unable to retrieve system memory information");
return v8::Undefined(isolate);
}
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("total", mem_info.total);
// See Chromium's "base/process/process_metrics.h" for an explanation.
int free =
#if defined(OS_WIN)
mem_info.avail_phys;
#else
mem_info.free;
#endif
dict.Set("free", free);
// NB: These return bogus values on macOS
#if !defined(OS_MACOSX)
dict.Set("swapTotal", mem_info.swap_total);
dict.Set("swapFree", mem_info.swap_free);
#endif
return dict.GetHandle();
}
// static
v8::Local<v8::Promise> ElectronBindings::GetProcessMemoryInfo(
v8::Isolate* isolate) {
util::Promise promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
if (mate::Locker::IsBrowserProcess() && !Browser::Get()->is_ready()) {
promise.RejectWithErrorMessage(
"Memory Info is available only after app ready");
return handle;
}
v8::Global<v8::Context> context(isolate, isolate->GetCurrentContext());
memory_instrumentation::MemoryInstrumentation::GetInstance()
->RequestGlobalDumpForPid(
base::GetCurrentProcId(), std::vector<std::string>(),
base::BindOnce(&ElectronBindings::DidReceiveMemoryDump,
std::move(context), std::move(promise)));
return handle;
}
// static
v8::Local<v8::Value> ElectronBindings::GetBlinkMemoryInfo(
v8::Isolate* isolate) {
auto allocated = blink::ProcessHeap::TotalAllocatedObjectSize();
auto marked = blink::ProcessHeap::TotalMarkedObjectSize();
auto total = blink::ProcessHeap::TotalAllocatedSpace();
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("allocated", static_cast<double>(allocated >> 10));
dict.Set("marked", static_cast<double>(marked >> 10));
dict.Set("total", static_cast<double>(total >> 10));
return dict.GetHandle();
}
// static
void ElectronBindings::DidReceiveMemoryDump(
v8::Global<v8::Context> context,
util::Promise promise,
bool success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> global_dump) {
v8::Isolate* isolate = promise.isolate();
mate::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
v8::MicrotasksScope script_scope(isolate,
v8::MicrotasksScope::kRunMicrotasks);
v8::Context::Scope context_scope(
v8::Local<v8::Context>::New(isolate, context));
if (!success) {
promise.RejectWithErrorMessage("Failed to create memory dump");
return;
}
bool resolved = false;
for (const memory_instrumentation::GlobalMemoryDump::ProcessDump& dump :
global_dump->process_dumps()) {
if (base::GetCurrentProcId() == dump.pid()) {
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
const auto& osdump = dump.os_dump();
#if defined(OS_LINUX) || defined(OS_WIN)
dict.Set("residentSet", osdump.resident_set_kb);
#endif
dict.Set("private", osdump.private_footprint_kb);
dict.Set("shared", osdump.shared_footprint_kb);
promise.Resolve(dict.GetHandle());
resolved = true;
break;
}
}
if (!resolved) {
promise.RejectWithErrorMessage(
R"(Failed to find current process memory details in memory dump)");
}
}
// static
v8::Local<v8::Value> ElectronBindings::GetCPUUsage(
base::ProcessMetrics* metrics,
v8::Isolate* isolate) {
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
int processor_count = base::SysInfo::NumberOfProcessors();
dict.Set("percentCPUUsage",
metrics->GetPlatformIndependentCPUUsage() / processor_count);
// NB: This will throw NOTIMPLEMENTED() on Windows
// For backwards compatibility, we'll return 0
#if !defined(OS_WIN)
dict.Set("idleWakeupsPerSecond", metrics->GetIdleWakeupsPerSecond());
#else
dict.Set("idleWakeupsPerSecond", 0);
#endif
return dict.GetHandle();
}
// static
v8::Local<v8::Value> ElectronBindings::GetIOCounters(v8::Isolate* isolate) {
auto metrics = base::ProcessMetrics::CreateCurrentProcessMetrics();
base::IoCounters io_counters;
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
if (metrics->GetIOCounters(&io_counters)) {
dict.Set("readOperationCount", io_counters.ReadOperationCount);
dict.Set("writeOperationCount", io_counters.WriteOperationCount);
dict.Set("otherOperationCount", io_counters.OtherOperationCount);
dict.Set("readTransferCount", io_counters.ReadTransferCount);
dict.Set("writeTransferCount", io_counters.WriteTransferCount);
dict.Set("otherTransferCount", io_counters.OtherTransferCount);
}
return dict.GetHandle();
}
// static
bool ElectronBindings::TakeHeapSnapshot(v8::Isolate* isolate,
const base::FilePath& file_path) {
base::ThreadRestrictions::ScopedAllowIO allow_io;
base::File file(file_path,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
return atom::TakeHeapSnapshot(isolate, &file);
}
} // namespace atom

View file

@ -0,0 +1,87 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_ELECTRON_BINDINGS_H_
#define ATOM_COMMON_API_ELECTRON_BINDINGS_H_
#include <list>
#include <memory>
#include "atom/common/promise_util.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/process/process_metrics.h"
#include "base/strings/string16.h"
#include "native_mate/arguments.h"
#include "uv.h" // NOLINT(build/include)
#include "v8/include/v8.h"
namespace mate {
class Dictionary;
}
namespace memory_instrumentation {
class GlobalMemoryDump;
}
namespace node {
class Environment;
}
namespace atom {
class ElectronBindings {
public:
explicit ElectronBindings(uv_loop_t* loop);
virtual ~ElectronBindings();
// Add process.electronBinding function, which behaves like process.binding
// but load native code from Electron instead.
void BindTo(v8::Isolate* isolate, v8::Local<v8::Object> process);
// Should be called when a node::Environment has been destroyed.
void EnvironmentDestroyed(node::Environment* env);
static void BindProcess(v8::Isolate* isolate,
mate::Dictionary* process,
base::ProcessMetrics* metrics);
static void Log(const base::string16& message);
static void Crash();
private:
static void Hang();
static v8::Local<v8::Value> GetHeapStatistics(v8::Isolate* isolate);
static v8::Local<v8::Value> GetCreationTime(v8::Isolate* isolate);
static v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate,
mate::Arguments* args);
static v8::Local<v8::Promise> GetProcessMemoryInfo(v8::Isolate* isolate);
static v8::Local<v8::Value> GetBlinkMemoryInfo(v8::Isolate* isolate);
static v8::Local<v8::Value> GetCPUUsage(base::ProcessMetrics* metrics,
v8::Isolate* isolate);
static v8::Local<v8::Value> GetIOCounters(v8::Isolate* isolate);
static bool TakeHeapSnapshot(v8::Isolate* isolate,
const base::FilePath& file_path);
void ActivateUVLoop(v8::Isolate* isolate);
static void OnCallNextTick(uv_async_t* handle);
static void DidReceiveMemoryDump(
v8::Global<v8::Context> context,
util::Promise promise,
bool success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump);
uv_async_t call_next_tick_async_;
std::list<node::Environment*> pending_next_ticks_;
std::unique_ptr<base::ProcessMetrics> metrics_;
DISALLOW_COPY_AND_ASSIGN(ElectronBindings);
};
} // namespace atom
#endif // ATOM_COMMON_API_ELECTRON_BINDINGS_H_

View file

@ -0,0 +1,38 @@
// 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 "atom/common/api/event_emitter_caller.h"
#include "atom/common/api/locker.h"
#include "atom/common/node_includes.h"
namespace mate {
namespace internal {
v8::Local<v8::Value> CallMethodWithArgs(v8::Isolate* isolate,
v8::Local<v8::Object> obj,
const char* method,
ValueVector* args) {
// Perform microtask checkpoint after running JavaScript.
v8::MicrotasksScope script_scope(isolate,
v8::MicrotasksScope::kRunMicrotasks);
// Use node::MakeCallback to call the callback, and it will also run pending
// tasks in Node.js.
v8::MaybeLocal<v8::Value> ret = node::MakeCallback(
isolate, obj, method, args->size(), &args->front(), {0, 0});
// If the JS function throws an exception (doesn't return a value) the result
// of MakeCallback will be empty and therefore ToLocal will be false, in this
// case we need to return "false" as that indicates that the event emitter did
// not handle the event
v8::Local<v8::Value> localRet;
if (ret.ToLocal(&localRet)) {
return localRet;
}
return v8::Boolean::New(isolate, false);
}
} // namespace internal
} // namespace mate

View file

@ -0,0 +1,69 @@
// 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 ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_
#define ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_
#include <utility>
#include <vector>
#include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/converter.h"
namespace mate {
namespace internal {
using ValueVector = std::vector<v8::Local<v8::Value>>;
v8::Local<v8::Value> CallMethodWithArgs(v8::Isolate* isolate,
v8::Local<v8::Object> obj,
const char* method,
ValueVector* args);
} // namespace internal
// obj.emit.apply(obj, name, args...);
// The caller is responsible of allocating a HandleScope.
template <typename StringType>
v8::Local<v8::Value> EmitEvent(v8::Isolate* isolate,
v8::Local<v8::Object> obj,
const StringType& name,
const internal::ValueVector& args) {
internal::ValueVector concatenated_args = {StringToV8(isolate, name)};
concatenated_args.reserve(1 + args.size());
concatenated_args.insert(concatenated_args.end(), args.begin(), args.end());
return internal::CallMethodWithArgs(isolate, obj, "emit", &concatenated_args);
}
// obj.emit(name, args...);
// The caller is responsible of allocating a HandleScope.
template <typename StringType, typename... Args>
v8::Local<v8::Value> EmitEvent(v8::Isolate* isolate,
v8::Local<v8::Object> obj,
const StringType& name,
Args&&... args) {
internal::ValueVector converted_args = {
StringToV8(isolate, name),
ConvertToV8(isolate, std::forward<Args>(args))...,
};
return internal::CallMethodWithArgs(isolate, obj, "emit", &converted_args);
}
// obj.custom_emit(args...)
template <typename... Args>
v8::Local<v8::Value> CustomEmit(v8::Isolate* isolate,
v8::Local<v8::Object> object,
const char* custom_emit,
Args&&... args) {
internal::ValueVector converted_args = {
ConvertToV8(isolate, std::forward<Args>(args))...,
};
return internal::CallMethodWithArgs(isolate, object, custom_emit,
&converted_args);
}
} // namespace mate
#endif // ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_

View file

@ -0,0 +1,71 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/node_includes.h"
#include "electron/buildflags/buildflags.h"
#include "native_mate/dictionary.h"
#include "printing/buildflags/buildflags.h"
namespace {
bool IsDesktopCapturerEnabled() {
return BUILDFLAG(ENABLE_DESKTOP_CAPTURER);
}
bool IsOffscreenRenderingEnabled() {
return BUILDFLAG(ENABLE_OSR);
}
bool IsPDFViewerEnabled() {
return BUILDFLAG(ENABLE_PDF_VIEWER);
}
bool IsRunAsNodeEnabled() {
return BUILDFLAG(ENABLE_RUN_AS_NODE);
}
bool IsFakeLocationProviderEnabled() {
return BUILDFLAG(OVERRIDE_LOCATION_PROVIDER);
}
bool IsViewApiEnabled() {
return BUILDFLAG(ENABLE_VIEW_API);
}
bool IsTtsEnabled() {
return BUILDFLAG(ENABLE_TTS);
}
bool IsPrintingEnabled() {
return BUILDFLAG(ENABLE_PRINTING);
}
bool IsComponentBuild() {
#if defined(COMPONENT_BUILD)
return true;
#else
return false;
#endif
}
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("isDesktopCapturerEnabled", &IsDesktopCapturerEnabled);
dict.SetMethod("isOffscreenRenderingEnabled", &IsOffscreenRenderingEnabled);
dict.SetMethod("isPDFViewerEnabled", &IsPDFViewerEnabled);
dict.SetMethod("isRunAsNodeEnabled", &IsRunAsNodeEnabled);
dict.SetMethod("isFakeLocationProviderEnabled",
&IsFakeLocationProviderEnabled);
dict.SetMethod("isViewApiEnabled", &IsViewApiEnabled);
dict.SetMethod("isTtsEnabled", &IsTtsEnabled);
dict.SetMethod("isPrintingEnabled", &IsPrintingEnabled);
dict.SetMethod("isComponentBuild", &IsComponentBuild);
}
} // namespace
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_features, Initialize)

View file

@ -0,0 +1,16 @@
// Copyright 2014 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.chromium file.
#include "atom/common/api/locker.h"
namespace mate {
Locker::Locker(v8::Isolate* isolate) {
if (IsBrowserProcess())
locker_.reset(new v8::Locker(isolate));
}
Locker::~Locker() {}
} // namespace mate

36
shell/common/api/locker.h Normal file
View file

@ -0,0 +1,36 @@
// Copyright 2014 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.chromium file.
#ifndef ATOM_COMMON_API_LOCKER_H_
#define ATOM_COMMON_API_LOCKER_H_
#include <memory>
#include "base/macros.h"
#include "v8/include/v8.h"
namespace mate {
// Only lock when lockers are used in current thread.
class Locker {
public:
explicit Locker(v8::Isolate* isolate);
~Locker();
// Returns whether current process is browser process, currently we detect it
// by checking whether current has used V8 Lock, but it might be a bad idea.
static inline bool IsBrowserProcess() { return v8::Locker::IsActive(); }
private:
void* operator new(size_t size);
void operator delete(void*, size_t);
std::unique_ptr<v8::Locker> locker_;
DISALLOW_COPY_AND_ASSIGN(Locker);
};
} // namespace mate
#endif // ATOM_COMMON_API_LOCKER_H_

View file

@ -0,0 +1,41 @@
// Copyright (c) 2013 GitHub, Inc.
// Copyright (c) 2012 Intel Corp. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/api/object_life_monitor.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
namespace atom {
ObjectLifeMonitor::ObjectLifeMonitor(v8::Isolate* isolate,
v8::Local<v8::Object> target)
: target_(isolate, target), weak_ptr_factory_(this) {
target_.SetWeak(this, OnObjectGC, v8::WeakCallbackType::kParameter);
}
ObjectLifeMonitor::~ObjectLifeMonitor() {
if (target_.IsEmpty())
return;
target_.ClearWeak();
target_.Reset();
}
// static
void ObjectLifeMonitor::OnObjectGC(
const v8::WeakCallbackInfo<ObjectLifeMonitor>& data) {
ObjectLifeMonitor* self = data.GetParameter();
self->target_.Reset();
self->RunDestructor();
data.SetSecondPassCallback(Free);
}
// static
void ObjectLifeMonitor::Free(
const v8::WeakCallbackInfo<ObjectLifeMonitor>& data) {
delete data.GetParameter();
}
} // namespace atom

View file

@ -0,0 +1,34 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_OBJECT_LIFE_MONITOR_H_
#define ATOM_COMMON_API_OBJECT_LIFE_MONITOR_H_
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "v8/include/v8.h"
namespace atom {
class ObjectLifeMonitor {
protected:
ObjectLifeMonitor(v8::Isolate* isolate, v8::Local<v8::Object> target);
virtual ~ObjectLifeMonitor();
virtual void RunDestructor() = 0;
private:
static void OnObjectGC(const v8::WeakCallbackInfo<ObjectLifeMonitor>& data);
static void Free(const v8::WeakCallbackInfo<ObjectLifeMonitor>& data);
v8::Global<v8::Object> target_;
base::WeakPtrFactory<ObjectLifeMonitor> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ObjectLifeMonitor);
};
} // namespace atom
#endif // ATOM_COMMON_API_OBJECT_LIFE_MONITOR_H_

View file

@ -0,0 +1,59 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/api/remote_callback_freer.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "electron/atom/common/api/api.mojom.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
namespace atom {
// static
void RemoteCallbackFreer::BindTo(v8::Isolate* isolate,
v8::Local<v8::Object> target,
const std::string& context_id,
int object_id,
content::WebContents* web_contents) {
new RemoteCallbackFreer(isolate, target, context_id, object_id, web_contents);
}
RemoteCallbackFreer::RemoteCallbackFreer(v8::Isolate* isolate,
v8::Local<v8::Object> target,
const std::string& context_id,
int object_id,
content::WebContents* web_contents)
: ObjectLifeMonitor(isolate, target),
content::WebContentsObserver(web_contents),
context_id_(context_id),
object_id_(object_id) {}
RemoteCallbackFreer::~RemoteCallbackFreer() {}
void RemoteCallbackFreer::RunDestructor() {
auto* channel = "ELECTRON_RENDERER_RELEASE_CALLBACK";
base::ListValue args;
int32_t sender_id = 0;
args.AppendString(context_id_);
args.AppendInteger(object_id_);
auto* frame_host = web_contents()->GetMainFrame();
if (frame_host) {
mojom::ElectronRendererAssociatedPtr electron_ptr;
frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
mojo::MakeRequest(&electron_ptr));
electron_ptr->Message(true /* internal */, false /* send_to_all */, channel,
args.Clone(), sender_id);
}
Observe(nullptr);
}
void RemoteCallbackFreer::RenderViewDeleted(content::RenderViewHost*) {
delete this;
}
} // namespace atom

View file

@ -0,0 +1,46 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_
#define ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_
#include <string>
#include "atom/common/api/object_life_monitor.h"
#include "content/public/browser/web_contents_observer.h"
namespace atom {
class RemoteCallbackFreer : public ObjectLifeMonitor,
public content::WebContentsObserver {
public:
static void BindTo(v8::Isolate* isolate,
v8::Local<v8::Object> target,
const std::string& context_id,
int object_id,
content::WebContents* web_conents);
protected:
RemoteCallbackFreer(v8::Isolate* isolate,
v8::Local<v8::Object> target,
const std::string& context_id,
int object_id,
content::WebContents* web_conents);
~RemoteCallbackFreer() override;
void RunDestructor() override;
// content::WebContentsObserver:
void RenderViewDeleted(content::RenderViewHost*) override;
private:
std::string context_id_;
int object_id_;
DISALLOW_COPY_AND_ASSIGN(RemoteCallbackFreer);
};
} // namespace atom
#endif // ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_

View file

@ -0,0 +1,85 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/api/remote_object_freer.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/renderer/render_frame.h"
#include "electron/atom/common/api/api.mojom.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/web/web_local_frame.h"
using blink::WebLocalFrame;
namespace atom {
namespace {
content::RenderFrame* GetCurrentRenderFrame() {
WebLocalFrame* frame = WebLocalFrame::FrameForCurrentContext();
if (!frame)
return nullptr;
return content::RenderFrame::FromWebFrame(frame);
}
} // namespace
// static
void RemoteObjectFreer::BindTo(v8::Isolate* isolate,
v8::Local<v8::Object> target,
const std::string& context_id,
int object_id) {
new RemoteObjectFreer(isolate, target, context_id, object_id);
}
// static
void RemoteObjectFreer::AddRef(const std::string& context_id, int object_id) {
ref_mapper_[context_id][object_id]++;
}
// static
std::map<std::string, std::map<int, int>> RemoteObjectFreer::ref_mapper_;
RemoteObjectFreer::RemoteObjectFreer(v8::Isolate* isolate,
v8::Local<v8::Object> target,
const std::string& context_id,
int object_id)
: ObjectLifeMonitor(isolate, target),
context_id_(context_id),
object_id_(object_id),
routing_id_(MSG_ROUTING_NONE) {
content::RenderFrame* render_frame = GetCurrentRenderFrame();
if (render_frame) {
routing_id_ = render_frame->GetRoutingID();
}
}
RemoteObjectFreer::~RemoteObjectFreer() {}
void RemoteObjectFreer::RunDestructor() {
content::RenderFrame* render_frame =
content::RenderFrame::FromRoutingID(routing_id_);
if (!render_frame)
return;
auto* channel = "ELECTRON_BROWSER_DEREFERENCE";
base::ListValue args;
args.AppendString(context_id_);
args.AppendInteger(object_id_);
args.AppendInteger(ref_mapper_[context_id_][object_id_]);
// Reset our local ref count in case we are in a GC race condition and will
// get more references in an inbound IPC message
ref_mapper_[context_id_].erase(object_id_);
if (ref_mapper_[context_id_].empty())
ref_mapper_.erase(context_id_);
mojom::ElectronBrowserAssociatedPtr electron_ptr;
render_frame->GetRemoteAssociatedInterfaces()->GetInterface(
mojo::MakeRequest(&electron_ptr));
electron_ptr->Message(true, channel, args.Clone());
}
} // namespace atom

View file

@ -0,0 +1,45 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_
#define ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_
#include <map>
#include <string>
#include "atom/common/api/object_life_monitor.h"
namespace atom {
class RemoteObjectFreer : public ObjectLifeMonitor {
public:
static void BindTo(v8::Isolate* isolate,
v8::Local<v8::Object> target,
const std::string& context_id,
int object_id);
static void AddRef(const std::string& context_id, int object_id);
protected:
RemoteObjectFreer(v8::Isolate* isolate,
v8::Local<v8::Object> target,
const std::string& context_id,
int object_id);
~RemoteObjectFreer() override;
void RunDestructor() override;
// { context_id => { object_id => ref_count }}
static std::map<std::string, std::map<int, int>> ref_mapper_;
private:
std::string context_id_;
int object_id_;
int routing_id_;
DISALLOW_COPY_AND_ASSIGN(RemoteObjectFreer);
};
} // namespace atom
#endif // ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_