refactor: rename the atom directory to shell
This commit is contained in:
parent
4575a4aae3
commit
d7f07e8a80
631 changed files with 0 additions and 0 deletions
12
shell/common/api/BUILD.gn
Normal file
12
shell/common/api/BUILD.gn
Normal 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",
|
||||
]
|
||||
}
|
78
shell/common/api/api.mojom
Normal file
78
shell/common/api/api.mojom
Normal 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();
|
||||
};
|
141
shell/common/api/atom_api_asar.cc
Normal file
141
shell/common/api/atom_api_asar.cc
Normal 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)
|
229
shell/common/api/atom_api_clipboard.cc
Normal file
229
shell/common/api/atom_api_clipboard.cc
Normal 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)
|
64
shell/common/api/atom_api_clipboard.h
Normal file
64
shell/common/api/atom_api_clipboard.h
Normal 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_
|
24
shell/common/api/atom_api_clipboard_mac.mm
Normal file
24
shell/common/api/atom_api_clipboard_mac.mm
Normal 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
|
61
shell/common/api/atom_api_command_line.cc
Normal file
61
shell/common/api/atom_api_command_line.cc
Normal 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)
|
65
shell/common/api/atom_api_crash_reporter.cc
Normal file
65
shell/common/api/atom_api_crash_reporter.cc
Normal 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)
|
63
shell/common/api/atom_api_key_weak_map.h
Normal file
63
shell/common/api/atom_api_key_weak_map.h
Normal 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_
|
713
shell/common/api/atom_api_native_image.cc
Normal file
713
shell/common/api/atom_api_native_image.cc
Normal 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)
|
133
shell/common/api/atom_api_native_image.h
Normal file
133
shell/common/api/atom_api_native_image.h
Normal 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_
|
76
shell/common/api/atom_api_native_image_mac.mm
Normal file
76
shell/common/api/atom_api_native_image_mac.mm
Normal 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
|
147
shell/common/api/atom_api_shell.cc
Normal file
147
shell/common/api/atom_api_shell.cc
Normal 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)
|
134
shell/common/api/atom_api_v8_util.cc
Normal file
134
shell/common/api/atom_api_v8_util.cc
Normal 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)
|
34
shell/common/api/constructor.h
Normal file
34
shell/common/api/constructor.h
Normal 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_
|
364
shell/common/api/electron_bindings.cc
Normal file
364
shell/common/api/electron_bindings.cc
Normal 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
|
87
shell/common/api/electron_bindings.h
Normal file
87
shell/common/api/electron_bindings.h
Normal 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_
|
38
shell/common/api/event_emitter_caller.cc
Normal file
38
shell/common/api/event_emitter_caller.cc
Normal 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
|
69
shell/common/api/event_emitter_caller.h
Normal file
69
shell/common/api/event_emitter_caller.h
Normal 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_
|
71
shell/common/api/features.cc
Normal file
71
shell/common/api/features.cc
Normal 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)
|
16
shell/common/api/locker.cc
Normal file
16
shell/common/api/locker.cc
Normal 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
36
shell/common/api/locker.h
Normal 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_
|
41
shell/common/api/object_life_monitor.cc
Normal file
41
shell/common/api/object_life_monitor.cc
Normal 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
|
34
shell/common/api/object_life_monitor.h
Normal file
34
shell/common/api/object_life_monitor.h
Normal 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_
|
59
shell/common/api/remote_callback_freer.cc
Normal file
59
shell/common/api/remote_callback_freer.cc
Normal 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
|
46
shell/common/api/remote_callback_freer.h
Normal file
46
shell/common/api/remote_callback_freer.h
Normal 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_
|
85
shell/common/api/remote_object_freer.cc
Normal file
85
shell/common/api/remote_object_freer.cc
Normal 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
|
45
shell/common/api/remote_object_freer.h
Normal file
45
shell/common/api/remote_object_freer.h
Normal 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_
|
Loading…
Add table
Add a link
Reference in a new issue