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_
|
56
shell/common/application_info.cc
Normal file
56
shell/common/application_info.cc
Normal file
|
@ -0,0 +1,56 @@
|
|||
// 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/application_info.h"
|
||||
|
||||
#include "atom/browser/browser.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "chrome/common/chrome_version.h"
|
||||
#include "content/public/common/user_agent.h"
|
||||
#include "electron/electron_version.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
base::NoDestructor<std::string> g_overridden_application_name;
|
||||
base::NoDestructor<std::string> g_overridden_application_version;
|
||||
|
||||
} // namespace
|
||||
|
||||
// name
|
||||
void OverrideApplicationName(const std::string& name) {
|
||||
*g_overridden_application_name = name;
|
||||
}
|
||||
std::string GetOverriddenApplicationName() {
|
||||
return *g_overridden_application_name;
|
||||
}
|
||||
|
||||
// version
|
||||
void OverrideApplicationVersion(const std::string& version) {
|
||||
*g_overridden_application_version = version;
|
||||
}
|
||||
std::string GetOverriddenApplicationVersion() {
|
||||
return *g_overridden_application_version;
|
||||
}
|
||||
|
||||
std::string GetApplicationUserAgent() {
|
||||
// Construct user agent string.
|
||||
Browser* browser = Browser::Get();
|
||||
std::string name, user_agent;
|
||||
if (!base::RemoveChars(browser->GetName(), " ", &name))
|
||||
name = browser->GetName();
|
||||
if (name == ELECTRON_PRODUCT_NAME) {
|
||||
user_agent = "Chrome/" CHROME_VERSION_STRING " " ELECTRON_PRODUCT_NAME
|
||||
"/" ELECTRON_VERSION_STRING;
|
||||
} else {
|
||||
user_agent = base::StringPrintf(
|
||||
"%s/%s Chrome/%s " ELECTRON_PRODUCT_NAME "/" ELECTRON_VERSION_STRING,
|
||||
name.c_str(), browser->GetVersion().c_str(), CHROME_VERSION_STRING);
|
||||
}
|
||||
return content::BuildUserAgentFromProduct(user_agent);
|
||||
}
|
||||
|
||||
} // namespace atom
|
37
shell/common/application_info.h
Normal file
37
shell/common/application_info.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
// 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_APPLICATION_INFO_H_
|
||||
#define ATOM_COMMON_APPLICATION_INFO_H_
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "atom/browser/win/scoped_hstring.h"
|
||||
#include "base/strings/string16.h"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace atom {
|
||||
|
||||
void OverrideApplicationName(const std::string& name);
|
||||
std::string GetOverriddenApplicationName();
|
||||
|
||||
void OverrideApplicationVersion(const std::string& version);
|
||||
std::string GetOverriddenApplicationVersion();
|
||||
|
||||
std::string GetApplicationName();
|
||||
std::string GetApplicationVersion();
|
||||
// Returns the user agent of Electron.
|
||||
std::string GetApplicationUserAgent();
|
||||
|
||||
#if defined(OS_WIN)
|
||||
PCWSTR GetRawAppUserModelID();
|
||||
bool GetAppUserModelID(ScopedHString* app_id);
|
||||
void SetAppUserModelID(const base::string16& name);
|
||||
bool IsRunningInDesktopBridge();
|
||||
#endif
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_APPLICATION_INFO_H_
|
79
shell/common/application_info_linux.cc
Normal file
79
shell/common/application_info_linux.cc
Normal file
|
@ -0,0 +1,79 @@
|
|||
// 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/application_info.h"
|
||||
|
||||
#include <gio/gdesktopappinfo.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/platform_util.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/logging.h"
|
||||
#include "chrome/browser/ui/libgtkui/gtk_util.h"
|
||||
#include "electron/electron_version.h"
|
||||
|
||||
namespace {
|
||||
|
||||
GDesktopAppInfo* get_desktop_app_info() {
|
||||
GDesktopAppInfo* ret = nullptr;
|
||||
|
||||
std::string desktop_id;
|
||||
if (platform_util::GetDesktopName(&desktop_id))
|
||||
ret = g_desktop_app_info_new(desktop_id.c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace atom {
|
||||
|
||||
std::string GetApplicationName() {
|
||||
// attempt #1: the string set in app.setName()
|
||||
std::string ret = GetOverriddenApplicationName();
|
||||
|
||||
// attempt #2: the 'Name' entry from .desktop file's [Desktop] section
|
||||
if (ret.empty()) {
|
||||
GDesktopAppInfo* info = get_desktop_app_info();
|
||||
if (info != nullptr) {
|
||||
char* str = g_desktop_app_info_get_string(info, "Name");
|
||||
g_clear_object(&info);
|
||||
if (str != nullptr)
|
||||
ret = str;
|
||||
g_clear_pointer(&str, g_free);
|
||||
}
|
||||
}
|
||||
|
||||
// attempt #3: Electron's name
|
||||
if (ret.empty()) {
|
||||
ret = ELECTRON_PRODUCT_NAME;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string GetApplicationVersion() {
|
||||
std::string ret;
|
||||
|
||||
// ensure ELECTRON_PRODUCT_NAME and GetApplicationVersion match up
|
||||
if (GetApplicationName() == ELECTRON_PRODUCT_NAME)
|
||||
ret = ELECTRON_VERSION_STRING;
|
||||
|
||||
// try to use the string set in app.setVersion()
|
||||
if (ret.empty())
|
||||
ret = GetOverriddenApplicationVersion();
|
||||
|
||||
// no known version number; return some safe fallback
|
||||
if (ret.empty()) {
|
||||
LOG(WARNING) << "No version found. Was app.setVersion() called?";
|
||||
ret = "0.0";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace atom
|
36
shell/common/application_info_mac.mm
Normal file
36
shell/common/application_info_mac.mm
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "atom/common/application_info.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#import "atom/common/mac/main_application_bundle.h"
|
||||
#import "base/mac/foundation_util.h"
|
||||
#import "base/strings/sys_string_conversions.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string ApplicationInfoDictionaryValue(NSString* key) {
|
||||
return base::SysNSStringToUTF8(
|
||||
[MainApplicationBundle().infoDictionary objectForKey:key]);
|
||||
}
|
||||
|
||||
std::string ApplicationInfoDictionaryValue(CFStringRef key) {
|
||||
return ApplicationInfoDictionaryValue(base::mac::CFToNSCast(key));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string GetApplicationName() {
|
||||
return ApplicationInfoDictionaryValue(kCFBundleNameKey);
|
||||
}
|
||||
|
||||
std::string GetApplicationVersion() {
|
||||
return ApplicationInfoDictionaryValue(@"CFBundleShortVersionString");
|
||||
}
|
||||
|
||||
} // namespace atom
|
113
shell/common/application_info_win.cc
Normal file
113
shell/common/application_info_win.cc
Normal file
|
@ -0,0 +1,113 @@
|
|||
// 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/application_info.h"
|
||||
|
||||
#include <windows.h> // windows.h must be included first
|
||||
|
||||
#include <VersionHelpers.h>
|
||||
#include <appmodel.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "atom/browser/win/scoped_hstring.h"
|
||||
#include "base/file_version_info.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
base::string16 g_app_user_model_id;
|
||||
}
|
||||
|
||||
const wchar_t kAppUserModelIDFormat[] = L"electron.app.$1";
|
||||
|
||||
std::string GetApplicationName() {
|
||||
auto* module = GetModuleHandle(nullptr);
|
||||
std::unique_ptr<FileVersionInfo> info(
|
||||
FileVersionInfo::CreateFileVersionInfoForModule(module));
|
||||
return base::UTF16ToUTF8(info->product_name());
|
||||
}
|
||||
|
||||
std::string GetApplicationVersion() {
|
||||
auto* module = GetModuleHandle(nullptr);
|
||||
std::unique_ptr<FileVersionInfo> info(
|
||||
FileVersionInfo::CreateFileVersionInfoForModule(module));
|
||||
return base::UTF16ToUTF8(info->product_version());
|
||||
}
|
||||
|
||||
void SetAppUserModelID(const base::string16& name) {
|
||||
g_app_user_model_id = name;
|
||||
SetCurrentProcessExplicitAppUserModelID(g_app_user_model_id.c_str());
|
||||
}
|
||||
|
||||
PCWSTR GetRawAppUserModelID() {
|
||||
if (g_app_user_model_id.empty()) {
|
||||
PWSTR current_app_id;
|
||||
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(¤t_app_id))) {
|
||||
g_app_user_model_id = current_app_id;
|
||||
} else {
|
||||
std::string name = GetApplicationName();
|
||||
base::string16 generated_app_id = base::ReplaceStringPlaceholders(
|
||||
kAppUserModelIDFormat, base::UTF8ToUTF16(name), nullptr);
|
||||
SetAppUserModelID(generated_app_id);
|
||||
}
|
||||
CoTaskMemFree(current_app_id);
|
||||
}
|
||||
|
||||
return g_app_user_model_id.c_str();
|
||||
}
|
||||
|
||||
bool GetAppUserModelID(ScopedHString* app_id) {
|
||||
app_id->Reset(GetRawAppUserModelID());
|
||||
return app_id->success();
|
||||
}
|
||||
|
||||
bool IsRunningInDesktopBridgeImpl() {
|
||||
if (IsWindows8OrGreater()) {
|
||||
// GetPackageFamilyName is not available on Windows 7
|
||||
using GetPackageFamilyNameFuncPtr = decltype(&GetPackageFamilyName);
|
||||
|
||||
static bool initialize_get_package_family_name = true;
|
||||
static GetPackageFamilyNameFuncPtr get_package_family_namePtr = NULL;
|
||||
|
||||
if (initialize_get_package_family_name) {
|
||||
initialize_get_package_family_name = false;
|
||||
HMODULE kernel32_base = GetModuleHandle(L"Kernel32.dll");
|
||||
if (!kernel32_base) {
|
||||
NOTREACHED() << " " << __FUNCTION__ << "(): Can't open Kernel32.dll";
|
||||
return false;
|
||||
}
|
||||
|
||||
get_package_family_namePtr =
|
||||
reinterpret_cast<GetPackageFamilyNameFuncPtr>(
|
||||
GetProcAddress(kernel32_base, "GetPackageFamilyName"));
|
||||
|
||||
if (!get_package_family_namePtr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 length;
|
||||
wchar_t packageFamilyName[PACKAGE_FAMILY_NAME_MAX_LENGTH + 1];
|
||||
HANDLE proc = GetCurrentProcess();
|
||||
LONG result =
|
||||
(*get_package_family_namePtr)(proc, &length, packageFamilyName);
|
||||
|
||||
return result == ERROR_SUCCESS;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsRunningInDesktopBridge() {
|
||||
static bool result = IsRunningInDesktopBridgeImpl();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace atom
|
315
shell/common/asar/archive.cc
Normal file
315
shell/common/asar/archive.cc
Normal file
|
@ -0,0 +1,315 @@
|
|||
// 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 "atom/common/asar/archive.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/asar/scoped_temporary_file.h"
|
||||
#include "base/files/file.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/json/json_reader.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/pickle.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "base/values.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
namespace asar {
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(OS_WIN)
|
||||
const char kSeparators[] = "\\/";
|
||||
#else
|
||||
const char kSeparators[] = "/";
|
||||
#endif
|
||||
|
||||
bool GetNodeFromPath(std::string path,
|
||||
const base::DictionaryValue* root,
|
||||
const base::DictionaryValue** out);
|
||||
|
||||
// Gets the "files" from "dir".
|
||||
bool GetFilesNode(const base::DictionaryValue* root,
|
||||
const base::DictionaryValue* dir,
|
||||
const base::DictionaryValue** out) {
|
||||
// Test for symbol linked directory.
|
||||
std::string link;
|
||||
if (dir->GetStringWithoutPathExpansion("link", &link)) {
|
||||
const base::DictionaryValue* linked_node = nullptr;
|
||||
if (!GetNodeFromPath(link, root, &linked_node))
|
||||
return false;
|
||||
dir = linked_node;
|
||||
}
|
||||
|
||||
return dir->GetDictionaryWithoutPathExpansion("files", out);
|
||||
}
|
||||
|
||||
// Gets sub-file "name" from "dir".
|
||||
bool GetChildNode(const base::DictionaryValue* root,
|
||||
const std::string& name,
|
||||
const base::DictionaryValue* dir,
|
||||
const base::DictionaryValue** out) {
|
||||
if (name == "") {
|
||||
*out = root;
|
||||
return true;
|
||||
}
|
||||
|
||||
const base::DictionaryValue* files = nullptr;
|
||||
return GetFilesNode(root, dir, &files) &&
|
||||
files->GetDictionaryWithoutPathExpansion(name, out);
|
||||
}
|
||||
|
||||
// Gets the node of "path" from "root".
|
||||
bool GetNodeFromPath(std::string path,
|
||||
const base::DictionaryValue* root,
|
||||
const base::DictionaryValue** out) {
|
||||
if (path == "") {
|
||||
*out = root;
|
||||
return true;
|
||||
}
|
||||
|
||||
const base::DictionaryValue* dir = root;
|
||||
for (size_t delimiter_position = path.find_first_of(kSeparators);
|
||||
delimiter_position != std::string::npos;
|
||||
delimiter_position = path.find_first_of(kSeparators)) {
|
||||
const base::DictionaryValue* child = nullptr;
|
||||
if (!GetChildNode(root, path.substr(0, delimiter_position), dir, &child))
|
||||
return false;
|
||||
|
||||
dir = child;
|
||||
path.erase(0, delimiter_position + 1);
|
||||
}
|
||||
|
||||
return GetChildNode(root, path, dir, out);
|
||||
}
|
||||
|
||||
bool FillFileInfoWithNode(Archive::FileInfo* info,
|
||||
uint32_t header_size,
|
||||
const base::DictionaryValue* node) {
|
||||
int size;
|
||||
if (!node->GetInteger("size", &size))
|
||||
return false;
|
||||
info->size = static_cast<uint32_t>(size);
|
||||
|
||||
if (node->GetBoolean("unpacked", &info->unpacked) && info->unpacked)
|
||||
return true;
|
||||
|
||||
std::string offset;
|
||||
if (!node->GetString("offset", &offset))
|
||||
return false;
|
||||
if (!base::StringToUint64(offset, &info->offset))
|
||||
return false;
|
||||
info->offset += header_size;
|
||||
|
||||
node->GetBoolean("executable", &info->executable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Archive::Archive(const base::FilePath& path)
|
||||
: path_(path), file_(base::File::FILE_OK) {
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
file_.Initialize(path_, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
||||
#if defined(OS_WIN)
|
||||
fd_ = _open_osfhandle(reinterpret_cast<intptr_t>(file_.GetPlatformFile()), 0);
|
||||
#elif defined(OS_POSIX)
|
||||
fd_ = file_.GetPlatformFile();
|
||||
#endif
|
||||
}
|
||||
|
||||
Archive::~Archive() {
|
||||
#if defined(OS_WIN)
|
||||
if (fd_ != -1) {
|
||||
_close(fd_);
|
||||
// Don't close the handle since we already closed the fd.
|
||||
file_.TakePlatformFile();
|
||||
}
|
||||
#endif
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
file_.Close();
|
||||
}
|
||||
|
||||
bool Archive::Init() {
|
||||
if (!file_.IsValid()) {
|
||||
if (file_.error_details() != base::File::FILE_ERROR_NOT_FOUND) {
|
||||
LOG(WARNING) << "Opening " << path_.value() << ": "
|
||||
<< base::File::ErrorToString(file_.error_details());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<char> buf;
|
||||
int len;
|
||||
|
||||
buf.resize(8);
|
||||
{
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
len = file_.ReadAtCurrentPos(buf.data(), buf.size());
|
||||
}
|
||||
if (len != static_cast<int>(buf.size())) {
|
||||
PLOG(ERROR) << "Failed to read header size from " << path_.value();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t size;
|
||||
if (!base::PickleIterator(base::Pickle(buf.data(), buf.size()))
|
||||
.ReadUInt32(&size)) {
|
||||
LOG(ERROR) << "Failed to parse header size from " << path_.value();
|
||||
return false;
|
||||
}
|
||||
|
||||
buf.resize(size);
|
||||
{
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
len = file_.ReadAtCurrentPos(buf.data(), buf.size());
|
||||
}
|
||||
if (len != static_cast<int>(buf.size())) {
|
||||
PLOG(ERROR) << "Failed to read header from " << path_.value();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string header;
|
||||
if (!base::PickleIterator(base::Pickle(buf.data(), buf.size()))
|
||||
.ReadString(&header)) {
|
||||
LOG(ERROR) << "Failed to parse header from " << path_.value();
|
||||
return false;
|
||||
}
|
||||
|
||||
base::Optional<base::Value> value = base::JSONReader::Read(header);
|
||||
if (!value || !value->is_dict()) {
|
||||
LOG(ERROR) << "Failed to parse header";
|
||||
return false;
|
||||
}
|
||||
|
||||
header_size_ = 8 + size;
|
||||
header_ = base::DictionaryValue::From(
|
||||
std::make_unique<base::Value>(value->Clone()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) {
|
||||
if (!header_)
|
||||
return false;
|
||||
|
||||
const base::DictionaryValue* node;
|
||||
if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node))
|
||||
return false;
|
||||
|
||||
std::string link;
|
||||
if (node->GetString("link", &link))
|
||||
return GetFileInfo(base::FilePath::FromUTF8Unsafe(link), info);
|
||||
|
||||
return FillFileInfoWithNode(info, header_size_, node);
|
||||
}
|
||||
|
||||
bool Archive::Stat(const base::FilePath& path, Stats* stats) {
|
||||
if (!header_)
|
||||
return false;
|
||||
|
||||
const base::DictionaryValue* node;
|
||||
if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node))
|
||||
return false;
|
||||
|
||||
if (node->FindKey("link")) {
|
||||
stats->is_file = false;
|
||||
stats->is_link = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node->FindKey("files")) {
|
||||
stats->is_file = false;
|
||||
stats->is_directory = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return FillFileInfoWithNode(stats, header_size_, node);
|
||||
}
|
||||
|
||||
bool Archive::Readdir(const base::FilePath& path,
|
||||
std::vector<base::FilePath>* list) {
|
||||
if (!header_)
|
||||
return false;
|
||||
|
||||
const base::DictionaryValue* node;
|
||||
if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node))
|
||||
return false;
|
||||
|
||||
const base::DictionaryValue* files;
|
||||
if (!GetFilesNode(header_.get(), node, &files))
|
||||
return false;
|
||||
|
||||
base::DictionaryValue::Iterator iter(*files);
|
||||
while (!iter.IsAtEnd()) {
|
||||
list->push_back(base::FilePath::FromUTF8Unsafe(iter.key()));
|
||||
iter.Advance();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Archive::Realpath(const base::FilePath& path, base::FilePath* realpath) {
|
||||
if (!header_)
|
||||
return false;
|
||||
|
||||
const base::DictionaryValue* node;
|
||||
if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node))
|
||||
return false;
|
||||
|
||||
std::string link;
|
||||
if (node->GetString("link", &link)) {
|
||||
*realpath = base::FilePath::FromUTF8Unsafe(link);
|
||||
return true;
|
||||
}
|
||||
|
||||
*realpath = path;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
|
||||
auto it = external_files_.find(path.value());
|
||||
if (it != external_files_.end()) {
|
||||
*out = it->second->path();
|
||||
return true;
|
||||
}
|
||||
|
||||
FileInfo info;
|
||||
if (!GetFileInfo(path, &info))
|
||||
return false;
|
||||
|
||||
if (info.unpacked) {
|
||||
*out = path_.AddExtension(FILE_PATH_LITERAL("unpacked")).Append(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto temp_file = std::make_unique<ScopedTemporaryFile>();
|
||||
base::FilePath::StringType ext = path.Extension();
|
||||
if (!temp_file->InitFromFile(&file_, ext, info.offset, info.size))
|
||||
return false;
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
if (info.executable) {
|
||||
// chmod a+x temp_file;
|
||||
base::SetPosixFilePermissions(temp_file->path(), 0755);
|
||||
}
|
||||
#endif
|
||||
|
||||
*out = temp_file->path();
|
||||
external_files_[path.value()] = std::move(temp_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
int Archive::GetFD() const {
|
||||
return fd_;
|
||||
}
|
||||
|
||||
} // namespace asar
|
87
shell/common/asar/archive.h
Normal file
87
shell/common/asar/archive.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_ASAR_ARCHIVE_H_
|
||||
#define ATOM_COMMON_ASAR_ARCHIVE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "base/files/file.h"
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
}
|
||||
|
||||
namespace asar {
|
||||
|
||||
class ScopedTemporaryFile;
|
||||
|
||||
// This class represents an asar package, and provides methods to read
|
||||
// information from it.
|
||||
class Archive {
|
||||
public:
|
||||
struct FileInfo {
|
||||
FileInfo() : unpacked(false), executable(false), size(0), offset(0) {}
|
||||
bool unpacked;
|
||||
bool executable;
|
||||
uint32_t size;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct Stats : public FileInfo {
|
||||
Stats() : is_file(true), is_directory(false), is_link(false) {}
|
||||
bool is_file;
|
||||
bool is_directory;
|
||||
bool is_link;
|
||||
};
|
||||
|
||||
explicit Archive(const base::FilePath& path);
|
||||
virtual ~Archive();
|
||||
|
||||
// Read and parse the header.
|
||||
bool Init();
|
||||
|
||||
// Get the info of a file.
|
||||
bool GetFileInfo(const base::FilePath& path, FileInfo* info);
|
||||
|
||||
// Fs.stat(path).
|
||||
bool Stat(const base::FilePath& path, Stats* stats);
|
||||
|
||||
// Fs.readdir(path).
|
||||
bool Readdir(const base::FilePath& path, std::vector<base::FilePath>* files);
|
||||
|
||||
// Fs.realpath(path).
|
||||
bool Realpath(const base::FilePath& path, base::FilePath* realpath);
|
||||
|
||||
// Copy the file into a temporary file, and return the new path.
|
||||
// For unpacked file, this method will return its real path.
|
||||
bool CopyFileOut(const base::FilePath& path, base::FilePath* out);
|
||||
|
||||
// Returns the file's fd.
|
||||
int GetFD() const;
|
||||
|
||||
base::FilePath path() const { return path_; }
|
||||
base::DictionaryValue* header() const { return header_.get(); }
|
||||
|
||||
private:
|
||||
base::FilePath path_;
|
||||
base::File file_;
|
||||
int fd_ = -1;
|
||||
uint32_t header_size_ = 0;
|
||||
std::unique_ptr<base::DictionaryValue> header_;
|
||||
|
||||
// Cached external temporary files.
|
||||
std::unordered_map<base::FilePath::StringType,
|
||||
std::unique_ptr<ScopedTemporaryFile>>
|
||||
external_files_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Archive);
|
||||
};
|
||||
|
||||
} // namespace asar
|
||||
|
||||
#endif // ATOM_COMMON_ASAR_ARCHIVE_H_
|
100
shell/common/asar/asar_util.cc
Normal file
100
shell/common/asar/asar_util.cc
Normal file
|
@ -0,0 +1,100 @@
|
|||
// 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/asar/asar_util.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/asar/archive.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/lazy_instance.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/threading/thread_local.h"
|
||||
|
||||
namespace asar {
|
||||
|
||||
namespace {
|
||||
|
||||
// The global instance of ArchiveMap, will be destroyed on exit.
|
||||
typedef std::map<base::FilePath, std::shared_ptr<Archive>> ArchiveMap;
|
||||
base::LazyInstance<base::ThreadLocalPointer<ArchiveMap>>::Leaky
|
||||
g_archive_map_tls = LAZY_INSTANCE_INITIALIZER;
|
||||
|
||||
const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar");
|
||||
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path) {
|
||||
if (!g_archive_map_tls.Pointer()->Get())
|
||||
g_archive_map_tls.Pointer()->Set(new ArchiveMap);
|
||||
ArchiveMap& archive_map = *g_archive_map_tls.Pointer()->Get();
|
||||
if (!ContainsKey(archive_map, path)) {
|
||||
std::shared_ptr<Archive> archive(new Archive(path));
|
||||
if (!archive->Init())
|
||||
return nullptr;
|
||||
archive_map[path] = archive;
|
||||
}
|
||||
return archive_map[path];
|
||||
}
|
||||
|
||||
void ClearArchives() {
|
||||
if (g_archive_map_tls.Pointer()->Get())
|
||||
delete g_archive_map_tls.Pointer()->Get();
|
||||
}
|
||||
|
||||
bool GetAsarArchivePath(const base::FilePath& full_path,
|
||||
base::FilePath* asar_path,
|
||||
base::FilePath* relative_path) {
|
||||
base::FilePath iter = full_path;
|
||||
while (true) {
|
||||
base::FilePath dirname = iter.DirName();
|
||||
if (iter.MatchesExtension(kAsarExtension))
|
||||
break;
|
||||
else if (iter == dirname)
|
||||
return false;
|
||||
iter = dirname;
|
||||
}
|
||||
|
||||
base::FilePath tail;
|
||||
if (!iter.AppendRelativePath(full_path, &tail))
|
||||
return false;
|
||||
|
||||
*asar_path = iter;
|
||||
*relative_path = tail;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFileToString(const base::FilePath& path, std::string* contents) {
|
||||
base::FilePath asar_path, relative_path;
|
||||
if (!GetAsarArchivePath(path, &asar_path, &relative_path))
|
||||
return base::ReadFileToString(path, contents);
|
||||
|
||||
std::shared_ptr<Archive> archive = GetOrCreateAsarArchive(asar_path);
|
||||
if (!archive)
|
||||
return false;
|
||||
|
||||
Archive::FileInfo info;
|
||||
if (!archive->GetFileInfo(relative_path, &info))
|
||||
return false;
|
||||
|
||||
if (info.unpacked) {
|
||||
base::FilePath real_path;
|
||||
// For unpacked file it will return the real path instead of doing the copy.
|
||||
archive->CopyFileOut(relative_path, &real_path);
|
||||
return base::ReadFileToString(real_path, contents);
|
||||
}
|
||||
|
||||
base::File src(asar_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
||||
if (!src.IsValid())
|
||||
return false;
|
||||
|
||||
contents->resize(info.size);
|
||||
return static_cast<int>(info.size) ==
|
||||
src.Read(info.offset, const_cast<char*>(contents->data()),
|
||||
contents->size());
|
||||
}
|
||||
|
||||
} // namespace asar
|
35
shell/common/asar/asar_util.h
Normal file
35
shell/common/asar/asar_util.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
// 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_ASAR_ASAR_UTIL_H_
|
||||
#define ATOM_COMMON_ASAR_ASAR_UTIL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace asar {
|
||||
|
||||
class Archive;
|
||||
|
||||
// Gets or creates a new Archive from the path.
|
||||
std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path);
|
||||
|
||||
// Destroy cached Archive objects.
|
||||
void ClearArchives();
|
||||
|
||||
// Separates the path to Archive out.
|
||||
bool GetAsarArchivePath(const base::FilePath& full_path,
|
||||
base::FilePath* asar_path,
|
||||
base::FilePath* relative_path);
|
||||
|
||||
// Same with base::ReadFileToString but supports asar Archive.
|
||||
bool ReadFileToString(const base::FilePath& path, std::string* contents);
|
||||
|
||||
} // namespace asar
|
||||
|
||||
#endif // ATOM_COMMON_ASAR_ASAR_UTIL_H_
|
74
shell/common/asar/scoped_temporary_file.cc
Normal file
74
shell/common/asar/scoped_temporary_file.cc
Normal file
|
@ -0,0 +1,74 @@
|
|||
// 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 "atom/common/asar/scoped_temporary_file.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
|
||||
namespace asar {
|
||||
|
||||
ScopedTemporaryFile::ScopedTemporaryFile() {}
|
||||
|
||||
ScopedTemporaryFile::~ScopedTemporaryFile() {
|
||||
if (!path_.empty()) {
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
// On Windows it is very likely the file is already in use (because it is
|
||||
// mostly used for Node native modules), so deleting it now will halt the
|
||||
// program.
|
||||
#if defined(OS_WIN)
|
||||
base::DeleteFileAfterReboot(path_);
|
||||
#else
|
||||
base::DeleteFile(path_, false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool ScopedTemporaryFile::Init(const base::FilePath::StringType& ext) {
|
||||
if (!path_.empty())
|
||||
return true;
|
||||
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
if (!base::CreateTemporaryFile(&path_))
|
||||
return false;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Keep the original extension.
|
||||
if (!ext.empty()) {
|
||||
base::FilePath new_path = path_.AddExtension(ext);
|
||||
if (!base::Move(path_, new_path))
|
||||
return false;
|
||||
path_ = new_path;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScopedTemporaryFile::InitFromFile(base::File* src,
|
||||
const base::FilePath::StringType& ext,
|
||||
uint64_t offset,
|
||||
uint64_t size) {
|
||||
if (!src->IsValid())
|
||||
return false;
|
||||
|
||||
if (!Init(ext))
|
||||
return false;
|
||||
|
||||
std::vector<char> buf(size);
|
||||
int len = src->Read(offset, buf.data(), buf.size());
|
||||
if (len != static_cast<int>(size))
|
||||
return false;
|
||||
|
||||
base::File dest(path_, base::File::FLAG_OPEN | base::File::FLAG_WRITE);
|
||||
if (!dest.IsValid())
|
||||
return false;
|
||||
|
||||
return dest.WriteAtCurrentPos(buf.data(), buf.size()) ==
|
||||
static_cast<int>(size);
|
||||
}
|
||||
|
||||
} // namespace asar
|
44
shell/common/asar/scoped_temporary_file.h
Normal file
44
shell/common/asar/scoped_temporary_file.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_ASAR_SCOPED_TEMPORARY_FILE_H_
|
||||
#define ATOM_COMMON_ASAR_SCOPED_TEMPORARY_FILE_H_
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
namespace base {
|
||||
class File;
|
||||
}
|
||||
|
||||
namespace asar {
|
||||
|
||||
// An object representing a temporary file that should be cleaned up when this
|
||||
// object goes out of scope. Note that since deletion occurs during the
|
||||
// destructor, no further error handling is possible if the directory fails to
|
||||
// be deleted. As a result, deletion is not guaranteed by this class.
|
||||
class ScopedTemporaryFile {
|
||||
public:
|
||||
ScopedTemporaryFile();
|
||||
virtual ~ScopedTemporaryFile();
|
||||
|
||||
// Init an empty temporary file with a certain extension.
|
||||
bool Init(const base::FilePath::StringType& ext);
|
||||
|
||||
// Init an temporary file and fill it with content of |path|.
|
||||
bool InitFromFile(base::File* src,
|
||||
const base::FilePath::StringType& ext,
|
||||
uint64_t offset,
|
||||
uint64_t size);
|
||||
|
||||
base::FilePath path() const { return path_; }
|
||||
|
||||
private:
|
||||
base::FilePath path_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedTemporaryFile);
|
||||
};
|
||||
|
||||
} // namespace asar
|
||||
|
||||
#endif // ATOM_COMMON_ASAR_SCOPED_TEMPORARY_FILE_H_
|
36
shell/common/atom_command_line.cc
Normal file
36
shell/common/atom_command_line.cc
Normal file
|
@ -0,0 +1,36 @@
|
|||
// 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/atom_command_line.h"
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "uv.h" // NOLINT(build/include)
|
||||
|
||||
namespace atom {
|
||||
|
||||
// static
|
||||
base::CommandLine::StringVector AtomCommandLine::argv_;
|
||||
|
||||
// static
|
||||
void AtomCommandLine::Init(int argc, base::CommandLine::CharType** argv) {
|
||||
DCHECK(argv_.empty());
|
||||
|
||||
// NOTE: uv_setup_args does nothing on Windows, so we don't need to call it.
|
||||
// Otherwise we'd have to convert the arguments from UTF16.
|
||||
#if !defined(OS_WIN)
|
||||
// Hack around with the argv pointer. Used for process.title = "blah"
|
||||
argv = uv_setup_args(argc, argv);
|
||||
#endif
|
||||
|
||||
argv_.assign(argv, argv + argc);
|
||||
}
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// static
|
||||
void AtomCommandLine::InitializeFromCommandLine() {
|
||||
argv_ = base::CommandLine::ForCurrentProcess()->argv();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace atom
|
38
shell/common/atom_command_line.h
Normal file
38
shell/common/atom_command_line.h
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.
|
||||
|
||||
#ifndef ATOM_COMMON_ATOM_COMMAND_LINE_H_
|
||||
#define ATOM_COMMON_ATOM_COMMAND_LINE_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Singleton to remember the original "argc" and "argv".
|
||||
class AtomCommandLine {
|
||||
public:
|
||||
static const base::CommandLine::StringVector& argv() { return argv_; }
|
||||
|
||||
static void Init(int argc, base::CommandLine::CharType** argv);
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// On Linux the command line has to be read from base::CommandLine since
|
||||
// it is using zygote.
|
||||
static void InitializeFromCommandLine();
|
||||
#endif
|
||||
|
||||
private:
|
||||
static base::CommandLine::StringVector argv_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AtomCommandLine);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_ATOM_COMMAND_LINE_H_
|
47
shell/common/atom_constants.cc
Normal file
47
shell/common/atom_constants.cc
Normal file
|
@ -0,0 +1,47 @@
|
|||
// 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/atom_constants.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
const char kBrowserForward[] = "browser-forward";
|
||||
const char kBrowserBackward[] = "browser-backward";
|
||||
|
||||
const char kCORSHeader[] = "Access-Control-Allow-Origin: *";
|
||||
|
||||
const char kSHA1Certificate[] = "SHA-1 Certificate";
|
||||
const char kSHA1MajorDescription[] =
|
||||
"The certificate for this site expires in 2017 or later, "
|
||||
"and the certificate chain contains a certificate signed using SHA-1.";
|
||||
const char kSHA1MinorDescription[] =
|
||||
"The certificate for this site expires in 2016, "
|
||||
"and the certificate chain contains a certificate signed using SHA-1.";
|
||||
const char kCertificateError[] = "Certificate Error";
|
||||
const char kValidCertificate[] = "Valid Certificate";
|
||||
const char kValidCertificateDescription[] =
|
||||
"The connection to this site is using a valid, trusted server certificate.";
|
||||
const char kSecureProtocol[] = "Secure TLS connection";
|
||||
const char kSecureProtocolDescription[] =
|
||||
"The connection to this site is using a strong protocol version "
|
||||
"and cipher suite.";
|
||||
|
||||
#if defined(OS_WIN)
|
||||
const char kCrashpadPipeName[] = "ELECTRON_CRASHPAD_PIPE_NAME";
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_RUN_AS_NODE)
|
||||
const char kRunAsNode[] = "ELECTRON_RUN_AS_NODE";
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
const char kPdfPluginMimeType[] = "application/x-google-chrome-pdf";
|
||||
const char kPdfPluginPath[] = "chrome://pdf-viewer/";
|
||||
const char kPdfPluginSrc[] = "src";
|
||||
|
||||
const char kPdfViewerUIOrigin[] = "chrome://pdf-viewer/";
|
||||
const char kPdfViewerUIHost[] = "pdf-viewer";
|
||||
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
|
||||
} // namespace atom
|
52
shell/common/atom_constants.h
Normal file
52
shell/common/atom_constants.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
// 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_ATOM_CONSTANTS_H_
|
||||
#define ATOM_COMMON_ATOM_CONSTANTS_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// The app-command in NativeWindow.
|
||||
extern const char kBrowserForward[];
|
||||
extern const char kBrowserBackward[];
|
||||
|
||||
// Header to ignore CORS.
|
||||
extern const char kCORSHeader[];
|
||||
|
||||
// Strings describing Chrome security policy for DevTools security panel.
|
||||
extern const char kSHA1Certificate[];
|
||||
extern const char kSHA1MajorDescription[];
|
||||
extern const char kSHA1MinorDescription[];
|
||||
extern const char kCertificateError[];
|
||||
extern const char kValidCertificate[];
|
||||
extern const char kValidCertificateDescription[];
|
||||
extern const char kSecureProtocol[];
|
||||
extern const char kSecureProtocolDescription[];
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Crashpad pipe name.
|
||||
extern const char kCrashpadPipeName[];
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_RUN_AS_NODE)
|
||||
extern const char kRunAsNode[];
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
// The MIME type used for the PDF plugin.
|
||||
extern const char kPdfPluginMimeType[];
|
||||
extern const char kPdfPluginPath[];
|
||||
extern const char kPdfPluginSrc[];
|
||||
|
||||
// Constants for PDF viewer webui.
|
||||
extern const char kPdfViewerUIOrigin[];
|
||||
extern const char kPdfViewerUIHost[];
|
||||
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_ATOM_CONSTANTS_H_
|
54
shell/common/color_util.cc
Normal file
54
shell/common/color_util.cc
Normal file
|
@ -0,0 +1,54 @@
|
|||
// 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/color_util.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
SkColor ParseHexColor(const std::string& color_string) {
|
||||
// Check the string for incorrect formatting.
|
||||
if (color_string.empty() || color_string[0] != '#')
|
||||
return SK_ColorWHITE;
|
||||
|
||||
// Prepend FF if alpha channel is not specified.
|
||||
std::string source = color_string.substr(1);
|
||||
if (source.size() == 3)
|
||||
source.insert(0, "F");
|
||||
else if (source.size() == 6)
|
||||
source.insert(0, "FF");
|
||||
|
||||
// Convert the string from #FFF format to #FFFFFF format.
|
||||
std::string formatted_color;
|
||||
if (source.size() == 4) {
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
formatted_color += source[i];
|
||||
formatted_color += source[i];
|
||||
}
|
||||
} else if (source.size() == 8) {
|
||||
formatted_color = source;
|
||||
} else {
|
||||
return SK_ColorWHITE;
|
||||
}
|
||||
|
||||
// Convert the string to an integer and make sure it is in the correct value
|
||||
// range.
|
||||
std::vector<uint8_t> bytes;
|
||||
if (!base::HexStringToBytes(formatted_color, &bytes))
|
||||
return SK_ColorWHITE;
|
||||
|
||||
return SkColorSetARGB(bytes[0], bytes[1], bytes[2], bytes[3]);
|
||||
}
|
||||
|
||||
std::string ToRGBHex(SkColor color) {
|
||||
return base::StringPrintf("#%02X%02X%02X", SkColorGetR(color),
|
||||
SkColorGetG(color), SkColorGetB(color));
|
||||
}
|
||||
|
||||
} // namespace atom
|
22
shell/common/color_util.h
Normal file
22
shell/common/color_util.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
// 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_COLOR_UTIL_H_
|
||||
#define ATOM_COMMON_COLOR_UTIL_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "third_party/skia/include/core/SkColor.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Parse hex color like "#FFF" or "#EFEFEF"
|
||||
SkColor ParseHexColor(const std::string& name);
|
||||
|
||||
// Convert color to RGB hex value like "#ABCDEF"
|
||||
std::string ToRGBHex(SkColor color);
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_COLOR_UTIL_H_
|
153
shell/common/crash_reporter/crash_reporter.cc
Normal file
153
shell/common/crash_reporter/crash_reporter.cc
Normal file
|
@ -0,0 +1,153 @@
|
|||
// 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/crash_reporter/crash_reporter.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/map_converter.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "electron/electron_version.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
const char kCrashpadProcess[] = "crash-handler";
|
||||
const char kCrashesDirectoryKey[] = "crashes-directory";
|
||||
|
||||
CrashReporter::CrashReporter() {
|
||||
#if BUILDFLAG(ENABLE_RUN_AS_NODE)
|
||||
bool run_as_node = base::Environment::Create()->HasVar(atom::kRunAsNode);
|
||||
#else
|
||||
bool run_as_node = false;
|
||||
#endif
|
||||
|
||||
if (run_as_node) {
|
||||
process_type_ = "node";
|
||||
} else {
|
||||
auto* cmd = base::CommandLine::ForCurrentProcess();
|
||||
process_type_ = cmd->GetSwitchValueASCII(switches::kProcessType);
|
||||
}
|
||||
// process_type_ will be empty for browser process
|
||||
}
|
||||
|
||||
CrashReporter::~CrashReporter() {}
|
||||
|
||||
bool CrashReporter::IsInitialized() {
|
||||
return is_initialized_;
|
||||
}
|
||||
|
||||
void CrashReporter::Start(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool upload_to_server,
|
||||
bool skip_system_crash_handler,
|
||||
const StringMap& extra_parameters) {
|
||||
is_initialized_ = true;
|
||||
SetUploadParameters(extra_parameters);
|
||||
|
||||
Init(product_name, company_name, submit_url, crashes_dir, upload_to_server,
|
||||
skip_system_crash_handler);
|
||||
}
|
||||
|
||||
void CrashReporter::SetUploadParameters(const StringMap& parameters) {
|
||||
upload_parameters_ = parameters;
|
||||
upload_parameters_["process_type"] =
|
||||
process_type_.empty() ? "browser" : process_type_;
|
||||
upload_parameters_["prod"] = ELECTRON_PRODUCT_NAME;
|
||||
upload_parameters_["ver"] = ELECTRON_VERSION_STRING;
|
||||
|
||||
// Setting platform dependent parameters.
|
||||
SetUploadParameters();
|
||||
}
|
||||
|
||||
void CrashReporter::SetUploadToServer(const bool upload_to_server) {}
|
||||
|
||||
bool CrashReporter::GetUploadToServer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<CrashReporter::UploadReportResult>
|
||||
CrashReporter::GetUploadedReports(const base::FilePath& crashes_dir) {
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
std::string file_content;
|
||||
std::vector<CrashReporter::UploadReportResult> result;
|
||||
base::FilePath uploads_path =
|
||||
crashes_dir.Append(FILE_PATH_LITERAL("uploads.log"));
|
||||
if (base::ReadFileToString(uploads_path, &file_content)) {
|
||||
std::vector<std::string> reports = base::SplitString(
|
||||
file_content, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
for (const std::string& report : reports) {
|
||||
std::vector<std::string> report_item = base::SplitString(
|
||||
report, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
int report_time = 0;
|
||||
if (report_item.size() >= 2 &&
|
||||
base::StringToInt(report_item[0], &report_time)) {
|
||||
result.push_back(
|
||||
CrashReporter::UploadReportResult(report_time, report_item[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CrashReporter::Init(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler) {}
|
||||
|
||||
void CrashReporter::SetUploadParameters() {}
|
||||
|
||||
void CrashReporter::AddExtraParameter(const std::string& key,
|
||||
const std::string& value) {}
|
||||
|
||||
void CrashReporter::RemoveExtraParameter(const std::string& key) {}
|
||||
|
||||
std::map<std::string, std::string> CrashReporter::GetParameters() const {
|
||||
return upload_parameters_;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && defined(MAS_BUILD)
|
||||
// static
|
||||
CrashReporter* CrashReporter::GetInstance() {
|
||||
static CrashReporter crash_reporter;
|
||||
return &crash_reporter;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CrashReporter::StartInstance(const mate::Dictionary& options) {
|
||||
auto* reporter = GetInstance();
|
||||
if (!reporter)
|
||||
return;
|
||||
|
||||
std::string product_name;
|
||||
options.Get("productName", &product_name);
|
||||
std::string company_name;
|
||||
options.Get("companyName", &company_name);
|
||||
std::string submit_url;
|
||||
options.Get("submitURL", &submit_url);
|
||||
base::FilePath crashes_dir;
|
||||
options.Get("crashesDirectory", &crashes_dir);
|
||||
StringMap extra_parameters;
|
||||
options.Get("extra", &extra_parameters);
|
||||
|
||||
extra_parameters["_productName"] = product_name;
|
||||
extra_parameters["_companyName"] = company_name;
|
||||
|
||||
reporter->Start(product_name, company_name, submit_url, crashes_dir, true,
|
||||
false, extra_parameters);
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
73
shell/common/crash_reporter/crash_reporter.h
Normal file
73
shell/common/crash_reporter/crash_reporter.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
// 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_CRASH_REPORTER_CRASH_REPORTER_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/macros.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
extern const char kCrashpadProcess[];
|
||||
extern const char kCrashesDirectoryKey[];
|
||||
|
||||
class CrashReporter {
|
||||
public:
|
||||
typedef std::map<std::string, std::string> StringMap;
|
||||
typedef std::pair<int, std::string> UploadReportResult; // upload-date, id
|
||||
|
||||
static CrashReporter* GetInstance();
|
||||
static void StartInstance(const mate::Dictionary& options);
|
||||
|
||||
bool IsInitialized();
|
||||
void Start(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool upload_to_server,
|
||||
bool skip_system_crash_handler,
|
||||
const StringMap& extra_parameters);
|
||||
|
||||
virtual std::vector<CrashReporter::UploadReportResult> GetUploadedReports(
|
||||
const base::FilePath& crashes_dir);
|
||||
|
||||
virtual void SetUploadToServer(bool upload_to_server);
|
||||
virtual bool GetUploadToServer();
|
||||
virtual void AddExtraParameter(const std::string& key,
|
||||
const std::string& value);
|
||||
virtual void RemoveExtraParameter(const std::string& key);
|
||||
virtual std::map<std::string, std::string> GetParameters() const;
|
||||
|
||||
protected:
|
||||
CrashReporter();
|
||||
virtual ~CrashReporter();
|
||||
|
||||
virtual void Init(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool upload_to_server,
|
||||
bool skip_system_crash_handler);
|
||||
virtual void SetUploadParameters();
|
||||
|
||||
StringMap upload_parameters_;
|
||||
std::string process_type_;
|
||||
|
||||
private:
|
||||
bool is_initialized_ = false;
|
||||
void SetUploadParameters(const StringMap& parameters);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashReporter);
|
||||
};
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_H_
|
118
shell/common/crash_reporter/crash_reporter_crashpad.cc
Normal file
118
shell/common/crash_reporter/crash_reporter_crashpad.cc
Normal file
|
@ -0,0 +1,118 @@
|
|||
// 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/crash_reporter/crash_reporter_crashpad.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "third_party/crashpad/crashpad/client/settings.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
CrashReporterCrashpad::CrashReporterCrashpad() {}
|
||||
|
||||
CrashReporterCrashpad::~CrashReporterCrashpad() {}
|
||||
|
||||
bool CrashReporterCrashpad::GetUploadToServer() {
|
||||
bool enabled = true;
|
||||
if (database_) {
|
||||
database_->GetSettings()->GetUploadsEnabled(&enabled);
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void CrashReporterCrashpad::SetUploadToServer(const bool upload_to_server) {
|
||||
if (database_) {
|
||||
database_->GetSettings()->SetUploadsEnabled(upload_to_server);
|
||||
}
|
||||
}
|
||||
|
||||
void CrashReporterCrashpad::SetCrashKeyValue(const base::StringPiece& key,
|
||||
const base::StringPiece& value) {
|
||||
simple_string_dictionary_->SetKeyValue(key.data(), value.data());
|
||||
}
|
||||
|
||||
void CrashReporterCrashpad::SetInitialCrashKeyValues() {
|
||||
for (const auto& upload_parameter : upload_parameters_)
|
||||
SetCrashKeyValue(upload_parameter.first, upload_parameter.second);
|
||||
}
|
||||
|
||||
void CrashReporterCrashpad::AddExtraParameter(const std::string& key,
|
||||
const std::string& value) {
|
||||
if (simple_string_dictionary_) {
|
||||
SetCrashKeyValue(key, value);
|
||||
} else {
|
||||
upload_parameters_[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void CrashReporterCrashpad::RemoveExtraParameter(const std::string& key) {
|
||||
if (simple_string_dictionary_)
|
||||
simple_string_dictionary_->RemoveKey(key.data());
|
||||
else
|
||||
upload_parameters_.erase(key);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> CrashReporterCrashpad::GetParameters()
|
||||
const {
|
||||
if (simple_string_dictionary_) {
|
||||
std::map<std::string, std::string> ret;
|
||||
crashpad::SimpleStringDictionary::Iterator iter(*simple_string_dictionary_);
|
||||
for (;;) {
|
||||
auto* const entry = iter.Next();
|
||||
if (!entry)
|
||||
break;
|
||||
ret[entry->key] = entry->value;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return upload_parameters_;
|
||||
}
|
||||
|
||||
std::vector<CrashReporter::UploadReportResult>
|
||||
CrashReporterCrashpad::GetUploadedReports(const base::FilePath& crashes_dir) {
|
||||
std::vector<CrashReporter::UploadReportResult> uploaded_reports;
|
||||
|
||||
{
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
if (!base::PathExists(crashes_dir)) {
|
||||
return uploaded_reports;
|
||||
}
|
||||
}
|
||||
// Load crashpad database.
|
||||
std::unique_ptr<crashpad::CrashReportDatabase> database =
|
||||
crashpad::CrashReportDatabase::Initialize(crashes_dir);
|
||||
DCHECK(database);
|
||||
|
||||
std::vector<crashpad::CrashReportDatabase::Report> completed_reports;
|
||||
crashpad::CrashReportDatabase::OperationStatus status =
|
||||
database->GetCompletedReports(&completed_reports);
|
||||
if (status != crashpad::CrashReportDatabase::kNoError) {
|
||||
return uploaded_reports;
|
||||
}
|
||||
|
||||
for (const crashpad::CrashReportDatabase::Report& completed_report :
|
||||
completed_reports) {
|
||||
if (completed_report.uploaded) {
|
||||
uploaded_reports.push_back(
|
||||
UploadReportResult(static_cast<int>(completed_report.creation_time),
|
||||
completed_report.id));
|
||||
}
|
||||
}
|
||||
|
||||
auto sort_by_time = [](const UploadReportResult& a,
|
||||
const UploadReportResult& b) {
|
||||
return a.first >= b.first;
|
||||
};
|
||||
std::sort(uploaded_reports.begin(), uploaded_reports.end(), sort_by_time);
|
||||
return uploaded_reports;
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
50
shell/common/crash_reporter/crash_reporter_crashpad.h
Normal file
50
shell/common/crash_reporter/crash_reporter_crashpad.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
// 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_CRASH_REPORTER_CRASH_REPORTER_CRASHPAD_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_CRASHPAD_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/crash_reporter/crash_reporter.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "third_party/crashpad/crashpad/client/crash_report_database.h"
|
||||
#include "third_party/crashpad/crashpad/client/simple_string_dictionary.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
class CrashReporterCrashpad : public CrashReporter {
|
||||
public:
|
||||
void SetUploadToServer(bool upload_to_server) override;
|
||||
bool GetUploadToServer() override;
|
||||
void AddExtraParameter(const std::string& key,
|
||||
const std::string& value) override;
|
||||
void RemoveExtraParameter(const std::string& key) override;
|
||||
std::map<std::string, std::string> GetParameters() const override;
|
||||
|
||||
protected:
|
||||
CrashReporterCrashpad();
|
||||
~CrashReporterCrashpad() override;
|
||||
|
||||
void SetUploadsEnabled(bool enable_uploads);
|
||||
void SetCrashKeyValue(const base::StringPiece& key,
|
||||
const base::StringPiece& value);
|
||||
void SetInitialCrashKeyValues();
|
||||
|
||||
std::vector<UploadReportResult> GetUploadedReports(
|
||||
const base::FilePath& crashes_dir) override;
|
||||
|
||||
std::unique_ptr<crashpad::SimpleStringDictionary> simple_string_dictionary_;
|
||||
std::unique_ptr<crashpad::CrashReportDatabase> database_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashReporterCrashpad);
|
||||
};
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_CRASHPAD_H_
|
140
shell/common/crash_reporter/crash_reporter_linux.cc
Normal file
140
shell/common/crash_reporter/crash_reporter_linux.cc
Normal file
|
@ -0,0 +1,140 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Copyright (c) 2013 The Chromium Authors. 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/crash_reporter/crash_reporter_linux.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/debug/crash_logging.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/linux_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "base/process/memory.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "breakpad/src/client/linux/handler/exception_handler.h"
|
||||
#include "breakpad/src/common/linux/linux_libc_support.h"
|
||||
|
||||
using google_breakpad::ExceptionHandler;
|
||||
using google_breakpad::MinidumpDescriptor;
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
namespace {
|
||||
|
||||
// Define a preferred limit on minidump sizes, because Crash Server currently
|
||||
// throws away any larger than 1.2MB (1.2 * 1024 * 1024). A value of -1 means
|
||||
// no limit.
|
||||
static const off_t kMaxMinidumpFileSize = 1258291;
|
||||
|
||||
} // namespace
|
||||
|
||||
CrashReporterLinux::CrashReporterLinux() : pid_(getpid()) {
|
||||
// Set the base process start time value.
|
||||
struct timeval tv;
|
||||
if (!gettimeofday(&tv, NULL)) {
|
||||
uint64_t ret = tv.tv_sec;
|
||||
ret *= 1000;
|
||||
ret += tv.tv_usec / 1000;
|
||||
process_start_time_ = ret;
|
||||
}
|
||||
|
||||
// Make base::g_linux_distro work.
|
||||
base::SetLinuxDistro(base::GetLinuxDistro());
|
||||
}
|
||||
|
||||
CrashReporterLinux::~CrashReporterLinux() {}
|
||||
|
||||
void CrashReporterLinux::Init(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool upload_to_server,
|
||||
bool skip_system_crash_handler) {
|
||||
EnableCrashDumping(crashes_dir);
|
||||
|
||||
upload_url_ = submit_url;
|
||||
upload_to_server_ = upload_to_server;
|
||||
|
||||
crash_keys_.reset(new CrashKeyStorage());
|
||||
for (StringMap::const_iterator iter = upload_parameters_.begin();
|
||||
iter != upload_parameters_.end(); ++iter)
|
||||
crash_keys_->SetKeyValue(iter->first.c_str(), iter->second.c_str());
|
||||
}
|
||||
|
||||
void CrashReporterLinux::SetUploadParameters() {
|
||||
upload_parameters_["platform"] = "linux";
|
||||
}
|
||||
|
||||
void CrashReporterLinux::SetUploadToServer(const bool upload_to_server) {
|
||||
upload_to_server_ = upload_to_server;
|
||||
}
|
||||
|
||||
bool CrashReporterLinux::GetUploadToServer() {
|
||||
return upload_to_server_;
|
||||
}
|
||||
|
||||
void CrashReporterLinux::EnableCrashDumping(const base::FilePath& crashes_dir) {
|
||||
{
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
base::CreateDirectory(crashes_dir);
|
||||
}
|
||||
std::string log_file = crashes_dir.Append("uploads.log").value();
|
||||
strncpy(g_crash_log_path, log_file.c_str(), sizeof(g_crash_log_path));
|
||||
|
||||
MinidumpDescriptor minidump_descriptor(crashes_dir.value());
|
||||
minidump_descriptor.set_size_limit(kMaxMinidumpFileSize);
|
||||
|
||||
breakpad_.reset(new ExceptionHandler(minidump_descriptor, NULL, CrashDone,
|
||||
this,
|
||||
true, // Install handlers.
|
||||
-1));
|
||||
}
|
||||
|
||||
bool CrashReporterLinux::CrashDone(const MinidumpDescriptor& minidump,
|
||||
void* context,
|
||||
const bool succeeded) {
|
||||
CrashReporterLinux* self = static_cast<CrashReporterLinux*>(context);
|
||||
|
||||
// WARNING: this code runs in a compromised context. It may not call into
|
||||
// libc nor allocate memory normally.
|
||||
if (!succeeded) {
|
||||
const char msg[] = "Failed to generate minidump.";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
DCHECK(!minidump.IsFD());
|
||||
|
||||
BreakpadInfo info = {0};
|
||||
info.filename = minidump.path();
|
||||
info.fd = minidump.fd();
|
||||
info.distro = base::g_linux_distro;
|
||||
info.distro_length = my_strlen(base::g_linux_distro);
|
||||
info.upload = self->upload_to_server_;
|
||||
info.process_start_time = self->process_start_time_;
|
||||
info.oom_size = base::g_oom_size;
|
||||
info.pid = self->pid_;
|
||||
info.upload_url = self->upload_url_.c_str();
|
||||
info.crash_keys = self->crash_keys_.get();
|
||||
HandleCrashDump(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporterLinux* CrashReporterLinux::GetInstance() {
|
||||
return base::Singleton<CrashReporterLinux>::get();
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporter* CrashReporter::GetInstance() {
|
||||
return CrashReporterLinux::GetInstance();
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
65
shell/common/crash_reporter/crash_reporter_linux.h
Normal file
65
shell/common/crash_reporter/crash_reporter_linux.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_LINUX_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_LINUX_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/crash_reporter/crash_reporter.h"
|
||||
#include "atom/common/crash_reporter/linux/crash_dump_handler.h"
|
||||
#include "base/compiler_specific.h"
|
||||
|
||||
namespace base {
|
||||
template <typename T>
|
||||
struct DefaultSingletonTraits;
|
||||
}
|
||||
|
||||
namespace google_breakpad {
|
||||
class ExceptionHandler;
|
||||
class MinidumpDescriptor;
|
||||
} // namespace google_breakpad
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
class CrashReporterLinux : public CrashReporter {
|
||||
public:
|
||||
static CrashReporterLinux* GetInstance();
|
||||
|
||||
void Init(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool upload_to_server,
|
||||
bool skip_system_crash_handler) override;
|
||||
void SetUploadToServer(bool upload_to_server) override;
|
||||
void SetUploadParameters() override;
|
||||
bool GetUploadToServer() override;
|
||||
|
||||
private:
|
||||
friend struct base::DefaultSingletonTraits<CrashReporterLinux>;
|
||||
|
||||
CrashReporterLinux();
|
||||
~CrashReporterLinux() override;
|
||||
|
||||
void EnableCrashDumping(const base::FilePath& crashes_dir);
|
||||
|
||||
static bool CrashDone(const google_breakpad::MinidumpDescriptor& minidump,
|
||||
void* context,
|
||||
const bool succeeded);
|
||||
|
||||
std::unique_ptr<google_breakpad::ExceptionHandler> breakpad_;
|
||||
std::unique_ptr<CrashKeyStorage> crash_keys_;
|
||||
|
||||
uint64_t process_start_time_ = 0;
|
||||
pid_t pid_ = 0;
|
||||
std::string upload_url_;
|
||||
bool upload_to_server_ = true;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashReporterLinux);
|
||||
};
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_LINUX_H_
|
43
shell/common/crash_reporter/crash_reporter_mac.h
Normal file
43
shell/common/crash_reporter/crash_reporter_mac.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// 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_CRASH_REPORTER_CRASH_REPORTER_MAC_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/crash_reporter/crash_reporter_crashpad.h"
|
||||
|
||||
namespace base {
|
||||
template <typename T>
|
||||
struct DefaultSingletonTraits;
|
||||
}
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
class CrashReporterMac : public CrashReporterCrashpad {
|
||||
public:
|
||||
static CrashReporterMac* GetInstance();
|
||||
|
||||
void Init(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool upload_to_server,
|
||||
bool skip_system_crash_handler) override;
|
||||
void SetUploadParameters() override;
|
||||
|
||||
private:
|
||||
friend struct base::DefaultSingletonTraits<CrashReporterMac>;
|
||||
|
||||
CrashReporterMac();
|
||||
~CrashReporterMac() override;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashReporterMac);
|
||||
};
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_
|
84
shell/common/crash_reporter/crash_reporter_mac.mm
Normal file
84
shell/common/crash_reporter/crash_reporter_mac.mm
Normal file
|
@ -0,0 +1,84 @@
|
|||
// 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/crash_reporter/crash_reporter_mac.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/mac/bundle_locations.h"
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
|
||||
#include "third_party/crashpad/crashpad/client/crashpad_info.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
CrashReporterMac::CrashReporterMac() {}
|
||||
|
||||
CrashReporterMac::~CrashReporterMac() {}
|
||||
|
||||
void CrashReporterMac::Init(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool upload_to_server,
|
||||
bool skip_system_crash_handler) {
|
||||
// check whether crashpad has been initialized.
|
||||
// Only need to initialize once.
|
||||
if (simple_string_dictionary_)
|
||||
return;
|
||||
|
||||
if (process_type_.empty()) { // browser process
|
||||
@autoreleasepool {
|
||||
base::FilePath framework_bundle_path = base::mac::FrameworkBundlePath();
|
||||
base::FilePath handler_path =
|
||||
framework_bundle_path.Append("Resources").Append("crashpad_handler");
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--no-rate-limit",
|
||||
"--no-upload-gzip", // not all servers accept gzip
|
||||
};
|
||||
|
||||
crashpad::CrashpadClient crashpad_client;
|
||||
crashpad_client.StartHandler(handler_path, crashes_dir, crashes_dir,
|
||||
submit_url, StringMap(), args, true, false);
|
||||
} // @autoreleasepool
|
||||
}
|
||||
|
||||
crashpad::CrashpadInfo* crashpad_info =
|
||||
crashpad::CrashpadInfo::GetCrashpadInfo();
|
||||
if (skip_system_crash_handler) {
|
||||
crashpad_info->set_system_crash_reporter_forwarding(
|
||||
crashpad::TriState::kDisabled);
|
||||
}
|
||||
|
||||
simple_string_dictionary_.reset(new crashpad::SimpleStringDictionary());
|
||||
crashpad_info->set_simple_annotations(simple_string_dictionary_.get());
|
||||
|
||||
SetInitialCrashKeyValues();
|
||||
if (process_type_.empty()) { // browser process
|
||||
database_ = crashpad::CrashReportDatabase::Initialize(crashes_dir);
|
||||
SetUploadToServer(upload_to_server);
|
||||
}
|
||||
}
|
||||
|
||||
void CrashReporterMac::SetUploadParameters() {
|
||||
upload_parameters_["platform"] = "darwin";
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporterMac* CrashReporterMac::GetInstance() {
|
||||
return base::Singleton<CrashReporterMac>::get();
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporter* CrashReporter::GetInstance() {
|
||||
return CrashReporterMac::GetInstance();
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
141
shell/common/crash_reporter/crash_reporter_win.cc
Normal file
141
shell/common/crash_reporter/crash_reporter_win.cc
Normal file
|
@ -0,0 +1,141 @@
|
|||
// 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/crash_reporter/crash_reporter_win.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/ui/inspectable_web_contents_impl.h"
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "electron/atom/common/api/api.mojom.h"
|
||||
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
|
||||
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
|
||||
#include "third_party/crashpad/crashpad/client/crashpad_info.h"
|
||||
|
||||
#if defined(_WIN64)
|
||||
#include "gin/public/debug.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(_WIN64)
|
||||
int CrashForException(EXCEPTION_POINTERS* info) {
|
||||
auto* reporter = crash_reporter::CrashReporterWin::GetInstance();
|
||||
if (reporter->IsInitialized())
|
||||
reporter->GetCrashpadClient().DumpAndCrash(info);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
CrashReporterWin::CrashReporterWin() {}
|
||||
|
||||
CrashReporterWin::~CrashReporterWin() {}
|
||||
|
||||
#if defined(_WIN64)
|
||||
void CrashReporterWin::SetUnhandledExceptionFilter() {
|
||||
gin::Debug::SetUnhandledExceptionCallback(&CrashForException);
|
||||
}
|
||||
#endif
|
||||
|
||||
void CrashReporterWin::Init(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool upload_to_server,
|
||||
bool skip_system_crash_handler) {
|
||||
// check whether crashpad has been initialized.
|
||||
// Only need to initialize once.
|
||||
if (simple_string_dictionary_)
|
||||
return;
|
||||
if (process_type_.empty()) { // browser process
|
||||
base::FilePath handler_path;
|
||||
base::PathService::Get(base::FILE_EXE, &handler_path);
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--no-rate-limit",
|
||||
"--no-upload-gzip", // not all servers accept gzip
|
||||
};
|
||||
args.push_back(base::StringPrintf("--type=%s", kCrashpadProcess));
|
||||
args.push_back(
|
||||
base::StringPrintf("--%s=%s", kCrashesDirectoryKey,
|
||||
base::UTF16ToUTF8(crashes_dir.value()).c_str()));
|
||||
crashpad_client_.StartHandler(handler_path, crashes_dir, crashes_dir,
|
||||
submit_url, StringMap(), args, true, false);
|
||||
UpdatePipeName();
|
||||
} else {
|
||||
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
||||
std::string pipe_name_utf8;
|
||||
if (env->GetVar(atom::kCrashpadPipeName, &pipe_name_utf8)) {
|
||||
base::string16 pipe_name = base::UTF8ToUTF16(pipe_name_utf8);
|
||||
if (!crashpad_client_.SetHandlerIPCPipe(pipe_name))
|
||||
LOG(ERROR) << "Failed to set handler IPC pipe name: " << pipe_name;
|
||||
} else {
|
||||
LOG(ERROR) << "Unable to get pipe name for crashpad";
|
||||
}
|
||||
}
|
||||
crashpad::CrashpadInfo* crashpad_info =
|
||||
crashpad::CrashpadInfo::GetCrashpadInfo();
|
||||
if (skip_system_crash_handler) {
|
||||
crashpad_info->set_system_crash_reporter_forwarding(
|
||||
crashpad::TriState::kDisabled);
|
||||
}
|
||||
simple_string_dictionary_.reset(new crashpad::SimpleStringDictionary());
|
||||
crashpad_info->set_simple_annotations(simple_string_dictionary_.get());
|
||||
|
||||
SetInitialCrashKeyValues();
|
||||
if (process_type_.empty()) { // browser process
|
||||
database_ = crashpad::CrashReportDatabase::Initialize(crashes_dir);
|
||||
SetUploadToServer(upload_to_server);
|
||||
}
|
||||
}
|
||||
|
||||
void CrashReporterWin::SetUploadParameters() {
|
||||
upload_parameters_["platform"] = "win32";
|
||||
}
|
||||
|
||||
crashpad::CrashpadClient& CrashReporterWin::GetCrashpadClient() {
|
||||
return crashpad_client_;
|
||||
}
|
||||
|
||||
void CrashReporterWin::UpdatePipeName() {
|
||||
std::string pipe_name =
|
||||
base::UTF16ToUTF8(crashpad_client_.GetHandlerIPCPipe());
|
||||
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
||||
env->SetVar(atom::kCrashpadPipeName, pipe_name);
|
||||
|
||||
// Notify all WebContents of the pipe name.
|
||||
const auto& pages = atom::InspectableWebContentsImpl::GetAll();
|
||||
for (auto* page : pages) {
|
||||
auto* frame_host = page->GetWebContents()->GetMainFrame();
|
||||
if (!frame_host)
|
||||
continue;
|
||||
|
||||
atom::mojom::ElectronRendererAssociatedPtr electron_ptr;
|
||||
frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
|
||||
mojo::MakeRequest(&electron_ptr));
|
||||
electron_ptr->UpdateCrashpadPipeName(pipe_name);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporterWin* CrashReporterWin::GetInstance() {
|
||||
return base::Singleton<CrashReporterWin>::get();
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporter* CrashReporter::GetInstance() {
|
||||
return CrashReporterWin::GetInstance();
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
52
shell/common/crash_reporter/crash_reporter_win.h
Normal file
52
shell/common/crash_reporter/crash_reporter_win.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
// 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_CRASH_REPORTER_CRASH_REPORTER_WIN_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_WIN_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/crash_reporter/crash_reporter_crashpad.h"
|
||||
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
|
||||
|
||||
namespace base {
|
||||
template <typename T>
|
||||
struct DefaultSingletonTraits;
|
||||
}
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
class CrashReporterWin : public CrashReporterCrashpad {
|
||||
public:
|
||||
static CrashReporterWin* GetInstance();
|
||||
#if defined(_WIN64)
|
||||
static void SetUnhandledExceptionFilter();
|
||||
#endif
|
||||
|
||||
void Init(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
const base::FilePath& crashes_dir,
|
||||
bool upload_to_server,
|
||||
bool skip_system_crash_handler) override;
|
||||
void SetUploadParameters() override;
|
||||
|
||||
crashpad::CrashpadClient& GetCrashpadClient();
|
||||
|
||||
private:
|
||||
friend struct base::DefaultSingletonTraits<CrashReporterWin>;
|
||||
CrashReporterWin();
|
||||
~CrashReporterWin() override;
|
||||
|
||||
void UpdatePipeName();
|
||||
|
||||
crashpad::CrashpadClient crashpad_client_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashReporterWin);
|
||||
};
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_WIN_H_
|
753
shell/common/crash_reporter/linux/crash_dump_handler.cc
Normal file
753
shell/common/crash_reporter/linux/crash_dump_handler.cc
Normal file
|
@ -0,0 +1,753 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// For linux_syscall_support.h. This makes it safe to call embedded system
|
||||
// calls when in seccomp mode.
|
||||
|
||||
#include "atom/common/crash_reporter/linux/crash_dump_handler.h"
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "breakpad/src/client/linux/minidump_writer/directory_reader.h"
|
||||
#include "breakpad/src/common/linux/linux_libc_support.h"
|
||||
#include "breakpad/src/common/memory_allocator.h"
|
||||
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
// Some versions of gcc are prone to warn about unused return values. In cases
|
||||
// where we either a) know the call cannot fail, or b) there is nothing we
|
||||
// can do when a call fails, we mark the return code as ignored. This avoids
|
||||
// spurious compiler warnings.
|
||||
#define IGNORE_RET(x) \
|
||||
do { \
|
||||
if (x) \
|
||||
; \
|
||||
} while (0)
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
namespace {
|
||||
|
||||
// String buffer size to use to convert a uint64_t to string.
|
||||
const size_t kUint64StringSize = 21;
|
||||
|
||||
// Writes the value |v| as 16 hex characters to the memory pointed at by
|
||||
// |output|.
|
||||
void write_uint64_hex(char* output, uint64_t v) {
|
||||
static const char hextable[] = "0123456789abcdef";
|
||||
|
||||
for (int i = 15; i >= 0; --i) {
|
||||
output[i] = hextable[v & 15];
|
||||
v >>= 4;
|
||||
}
|
||||
}
|
||||
|
||||
// uint64_t version of my_int_len() from
|
||||
// breakpad/src/common/linux/linux_libc_support.h. Return the length of the
|
||||
// given, non-negative integer when expressed in base 10.
|
||||
unsigned my_uint64_len(uint64_t i) {
|
||||
if (!i)
|
||||
return 1;
|
||||
|
||||
unsigned len = 0;
|
||||
while (i) {
|
||||
len++;
|
||||
i /= 10;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// uint64_t version of my_uitos() from
|
||||
// breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative
|
||||
// integer to a string (not null-terminated).
|
||||
void my_uint64tos(char* output, uint64_t i, unsigned i_len) {
|
||||
for (unsigned index = i_len; index; --index, i /= 10)
|
||||
output[index - 1] = '0' + (i % 10);
|
||||
}
|
||||
|
||||
// Converts a struct timeval to milliseconds.
|
||||
uint64_t kernel_timeval_to_ms(struct kernel_timeval* tv) {
|
||||
uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
|
||||
ret *= 1000;
|
||||
ret += tv->tv_usec / 1000;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool my_isxdigit(char c) {
|
||||
return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
|
||||
}
|
||||
|
||||
size_t LengthWithoutTrailingSpaces(const char* str, size_t len) {
|
||||
while (len > 0 && str[len - 1] == ' ') {
|
||||
len--;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// MIME substrings.
|
||||
const char g_rn[] = "\r\n";
|
||||
const char g_form_data_msg[] = "Content-Disposition: form-data; name=\"";
|
||||
const char g_quote_msg[] = "\"";
|
||||
const char g_dashdash_msg[] = "--";
|
||||
const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\"";
|
||||
const char g_content_type_msg[] = "Content-Type: application/octet-stream";
|
||||
|
||||
// MimeWriter manages an iovec for writing MIMEs to a file.
|
||||
class MimeWriter {
|
||||
public:
|
||||
static const int kIovCapacity = 30;
|
||||
static const size_t kMaxCrashChunkSize = 64;
|
||||
|
||||
MimeWriter(int fd, const char* const mime_boundary);
|
||||
~MimeWriter();
|
||||
|
||||
// Append boundary.
|
||||
virtual void AddBoundary();
|
||||
|
||||
// Append end of file boundary.
|
||||
virtual void AddEnd();
|
||||
|
||||
// Append key/value pair with specified sizes.
|
||||
virtual void AddPairData(const char* msg_type,
|
||||
size_t msg_type_size,
|
||||
const char* msg_data,
|
||||
size_t msg_data_size);
|
||||
|
||||
// Append key/value pair.
|
||||
void AddPairString(const char* msg_type, const char* msg_data) {
|
||||
AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data));
|
||||
}
|
||||
|
||||
// Append key/value pair, splitting value into chunks no larger than
|
||||
// |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|.
|
||||
// The msg_type string will have a counter suffix to distinguish each chunk.
|
||||
virtual void AddPairDataInChunks(const char* msg_type,
|
||||
size_t msg_type_size,
|
||||
const char* msg_data,
|
||||
size_t msg_data_size,
|
||||
size_t chunk_size,
|
||||
bool strip_trailing_spaces);
|
||||
|
||||
// Add binary file contents to be uploaded with the specified filename.
|
||||
virtual void AddFileContents(const char* filename_msg,
|
||||
uint8_t* file_data,
|
||||
size_t file_size);
|
||||
|
||||
// Flush any pending iovecs to the output file.
|
||||
void Flush() {
|
||||
IGNORE_RET(sys_writev(fd_, iov_, iov_index_));
|
||||
iov_index_ = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
void AddItem(const void* base, size_t size);
|
||||
// Minor performance trade-off for easier-to-maintain code.
|
||||
void AddString(const char* str) { AddItem(str, my_strlen(str)); }
|
||||
void AddItemWithoutTrailingSpaces(const void* base, size_t size);
|
||||
|
||||
struct kernel_iovec iov_[kIovCapacity];
|
||||
int iov_index_ = 0;
|
||||
|
||||
// Output file descriptor.
|
||||
int fd_ = -1;
|
||||
|
||||
const char* const mime_boundary_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MimeWriter);
|
||||
};
|
||||
|
||||
MimeWriter::MimeWriter(int fd, const char* const mime_boundary)
|
||||
: fd_(fd), mime_boundary_(mime_boundary) {}
|
||||
|
||||
MimeWriter::~MimeWriter() {}
|
||||
|
||||
void MimeWriter::AddBoundary() {
|
||||
AddString(mime_boundary_);
|
||||
AddString(g_rn);
|
||||
}
|
||||
|
||||
void MimeWriter::AddEnd() {
|
||||
AddString(mime_boundary_);
|
||||
AddString(g_dashdash_msg);
|
||||
AddString(g_rn);
|
||||
}
|
||||
|
||||
void MimeWriter::AddPairData(const char* msg_type,
|
||||
size_t msg_type_size,
|
||||
const char* msg_data,
|
||||
size_t msg_data_size) {
|
||||
AddString(g_form_data_msg);
|
||||
AddItem(msg_type, msg_type_size);
|
||||
AddString(g_quote_msg);
|
||||
AddString(g_rn);
|
||||
AddString(g_rn);
|
||||
AddItem(msg_data, msg_data_size);
|
||||
AddString(g_rn);
|
||||
}
|
||||
|
||||
void MimeWriter::AddPairDataInChunks(const char* msg_type,
|
||||
size_t msg_type_size,
|
||||
const char* msg_data,
|
||||
size_t msg_data_size,
|
||||
size_t chunk_size,
|
||||
bool strip_trailing_spaces) {
|
||||
if (chunk_size > kMaxCrashChunkSize)
|
||||
return;
|
||||
|
||||
unsigned i = 0;
|
||||
size_t done = 0, msg_length = msg_data_size;
|
||||
|
||||
while (msg_length) {
|
||||
char num[kUint64StringSize];
|
||||
const unsigned num_len = my_uint_len(++i);
|
||||
my_uitos(num, i, num_len);
|
||||
|
||||
size_t chunk_len = std::min(chunk_size, msg_length);
|
||||
|
||||
AddString(g_form_data_msg);
|
||||
AddItem(msg_type, msg_type_size);
|
||||
AddItem(num, num_len);
|
||||
AddString(g_quote_msg);
|
||||
AddString(g_rn);
|
||||
AddString(g_rn);
|
||||
if (strip_trailing_spaces) {
|
||||
AddItemWithoutTrailingSpaces(msg_data + done, chunk_len);
|
||||
} else {
|
||||
AddItem(msg_data + done, chunk_len);
|
||||
}
|
||||
AddString(g_rn);
|
||||
AddBoundary();
|
||||
Flush();
|
||||
|
||||
done += chunk_len;
|
||||
msg_length -= chunk_len;
|
||||
}
|
||||
}
|
||||
|
||||
void MimeWriter::AddFileContents(const char* filename_msg,
|
||||
uint8_t* file_data,
|
||||
size_t file_size) {
|
||||
AddString(g_form_data_msg);
|
||||
AddString(filename_msg);
|
||||
AddString(g_rn);
|
||||
AddString(g_content_type_msg);
|
||||
AddString(g_rn);
|
||||
AddString(g_rn);
|
||||
AddItem(file_data, file_size);
|
||||
AddString(g_rn);
|
||||
}
|
||||
|
||||
void MimeWriter::AddItem(const void* base, size_t size) {
|
||||
// Check if the iovec is full and needs to be flushed to output file.
|
||||
if (iov_index_ == kIovCapacity) {
|
||||
Flush();
|
||||
}
|
||||
iov_[iov_index_].iov_base = const_cast<void*>(base);
|
||||
iov_[iov_index_].iov_len = size;
|
||||
++iov_index_;
|
||||
}
|
||||
|
||||
void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) {
|
||||
AddItem(base,
|
||||
LengthWithoutTrailingSpaces(static_cast<const char*>(base), size));
|
||||
}
|
||||
|
||||
void LoadDataFromFD(google_breakpad::PageAllocator* allocator,
|
||||
int fd,
|
||||
bool close_fd,
|
||||
uint8_t** file_data,
|
||||
size_t* size) {
|
||||
struct kernel_stat st;
|
||||
if (sys_fstat(fd, &st) != 0) {
|
||||
static const char msg[] = "Cannot upload crash dump: stat failed\n";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
if (close_fd)
|
||||
IGNORE_RET(sys_close(fd));
|
||||
return;
|
||||
}
|
||||
|
||||
*file_data = reinterpret_cast<uint8_t*>(allocator->Alloc(st.st_size));
|
||||
if (!(*file_data)) {
|
||||
static const char msg[] = "Cannot upload crash dump: cannot alloc\n";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
if (close_fd)
|
||||
IGNORE_RET(sys_close(fd));
|
||||
return;
|
||||
}
|
||||
my_memset(*file_data, 0xf, st.st_size);
|
||||
|
||||
*size = st.st_size;
|
||||
int byte_read = sys_read(fd, *file_data, *size);
|
||||
if (byte_read == -1) {
|
||||
static const char msg[] = "Cannot upload crash dump: read failed\n";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
if (close_fd)
|
||||
IGNORE_RET(sys_close(fd));
|
||||
return;
|
||||
}
|
||||
|
||||
if (close_fd)
|
||||
IGNORE_RET(sys_close(fd));
|
||||
}
|
||||
|
||||
void LoadDataFromFile(google_breakpad::PageAllocator* allocator,
|
||||
const char* filename,
|
||||
int* fd,
|
||||
uint8_t** file_data,
|
||||
size_t* size) {
|
||||
// WARNING: this code runs in a compromised context. It may not call into
|
||||
// libc nor allocate memory normally.
|
||||
*fd = sys_open(filename, O_RDONLY, 0);
|
||||
*size = 0;
|
||||
|
||||
if (*fd < 0) {
|
||||
static const char msg[] = "Cannot upload crash dump: failed to open\n";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
LoadDataFromFD(allocator, *fd, true, file_data, size);
|
||||
}
|
||||
|
||||
// Spawn the appropriate upload process for the current OS:
|
||||
// - generic Linux invokes wget.
|
||||
// - ChromeOS invokes crash_reporter.
|
||||
// |dumpfile| is the path to the dump data file.
|
||||
// |mime_boundary| is only used on Linux.
|
||||
// |exe_buf| is only used on CrOS and is the crashing process' name.
|
||||
void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
|
||||
const char* dumpfile,
|
||||
const char* mime_boundary,
|
||||
const char* exe_buf,
|
||||
google_breakpad::PageAllocator* allocator) {
|
||||
// The --header argument to wget looks like:
|
||||
// --header=Content-Type: multipart/form-data; boundary=XYZ
|
||||
// where the boundary has two fewer leading '-' chars
|
||||
static const char header_msg[] =
|
||||
"--header=Content-Type: multipart/form-data; boundary=";
|
||||
char* const header = reinterpret_cast<char*>(
|
||||
allocator->Alloc(sizeof(header_msg) - 1 + strlen(mime_boundary) - 2 + 1));
|
||||
memcpy(header, header_msg, sizeof(header_msg) - 1);
|
||||
memcpy(header + sizeof(header_msg) - 1, mime_boundary + 2,
|
||||
strlen(mime_boundary) - 2);
|
||||
// We grab the NUL byte from the end of |mime_boundary|.
|
||||
|
||||
// The --post-file argument to wget looks like:
|
||||
// --post-file=/tmp/...
|
||||
static const char post_file_msg[] = "--post-file=";
|
||||
char* const post_file = reinterpret_cast<char*>(
|
||||
allocator->Alloc(sizeof(post_file_msg) - 1 + strlen(dumpfile) + 1));
|
||||
memcpy(post_file, post_file_msg, sizeof(post_file_msg) - 1);
|
||||
memcpy(post_file + sizeof(post_file_msg) - 1, dumpfile, strlen(dumpfile));
|
||||
|
||||
static const char kWgetBinary[] = "/usr/bin/wget";
|
||||
const char* args[] = {
|
||||
kWgetBinary, header, post_file, info.upload_url,
|
||||
"--timeout=60", // Set a timeout so we don't hang forever.
|
||||
"--tries=1", // Don't retry if the upload fails.
|
||||
"--quiet", // Be silent.
|
||||
"-O", // output reply to /dev/null.
|
||||
"/dev/fd/3", NULL,
|
||||
};
|
||||
static const char msg[] =
|
||||
"Cannot upload crash dump: cannot exec "
|
||||
"/usr/bin/wget\n";
|
||||
execve(args[0], const_cast<char**>(args), environ);
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
sys__exit(1);
|
||||
}
|
||||
|
||||
// Runs in the helper process to wait for the upload process running
|
||||
// ExecUploadProcessOrTerminate() to finish. Returns the number of bytes written
|
||||
// to |fd| and save the written contents to |buf|.
|
||||
// |buf| needs to be big enough to hold |bytes_to_read| + 1 characters.
|
||||
size_t WaitForCrashReportUploadProcess(int fd,
|
||||
size_t bytes_to_read,
|
||||
char* buf) {
|
||||
size_t bytes_read = 0;
|
||||
|
||||
// Upload should finish in about 10 seconds. Add a few more 500 ms
|
||||
// internals to account for process startup time.
|
||||
for (size_t wait_count = 0; wait_count < 24; ++wait_count) {
|
||||
struct kernel_pollfd poll_fd;
|
||||
poll_fd.fd = fd;
|
||||
poll_fd.events = POLLIN | POLLPRI | POLLERR;
|
||||
int ret = sys_poll(&poll_fd, 1, 500);
|
||||
if (ret < 0) {
|
||||
// Error
|
||||
break;
|
||||
} else if (ret > 0) {
|
||||
// There is data to read.
|
||||
ssize_t len = HANDLE_EINTR(
|
||||
sys_read(fd, buf + bytes_read, bytes_to_read - bytes_read));
|
||||
if (len < 0)
|
||||
break;
|
||||
bytes_read += len;
|
||||
if (bytes_read == bytes_to_read)
|
||||
break;
|
||||
}
|
||||
// |ret| == 0 -> timed out, continue waiting.
|
||||
// or |bytes_read| < |bytes_to_read| still, keep reading.
|
||||
}
|
||||
buf[bytes_to_read] = 0; // Always NUL terminate the buffer.
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
// |buf| should be |expected_len| + 1 characters in size and NULL terminated.
|
||||
bool IsValidCrashReportId(const char* buf,
|
||||
size_t bytes_read,
|
||||
size_t expected_len) {
|
||||
if (bytes_read != expected_len)
|
||||
return false;
|
||||
for (size_t i = 0; i < bytes_read; ++i) {
|
||||
if (!my_isxdigit(buf[i]) && buf[i] != '-')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// |buf| should be |expected_len| + 1 characters in size and NULL terminated.
|
||||
void HandleCrashReportId(const char* buf,
|
||||
size_t bytes_read,
|
||||
size_t expected_len) {
|
||||
if (!IsValidCrashReportId(buf, bytes_read, expected_len)) {
|
||||
static const char msg[] = "Failed to get crash dump id.";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
WriteNewline();
|
||||
|
||||
static const char id_msg[] = "Report Id: ";
|
||||
WriteLog(id_msg, sizeof(id_msg) - 1);
|
||||
WriteLog(buf, bytes_read);
|
||||
WriteNewline();
|
||||
return;
|
||||
}
|
||||
|
||||
// Write crash dump id to stderr.
|
||||
static const char msg[] = "Crash dump id: ";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
WriteLog(buf, my_strlen(buf));
|
||||
WriteNewline();
|
||||
|
||||
// Write crash dump id to crash log as: seconds_since_epoch,crash_id
|
||||
struct kernel_timeval tv;
|
||||
if (!sys_gettimeofday(&tv, NULL)) {
|
||||
uint64_t time = kernel_timeval_to_ms(&tv) / 1000;
|
||||
char time_str[kUint64StringSize];
|
||||
const unsigned time_len = my_uint64_len(time);
|
||||
my_uint64tos(time_str, time, time_len);
|
||||
|
||||
const int kLogOpenFlags = O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC;
|
||||
int log_fd = sys_open(g_crash_log_path, kLogOpenFlags, 0600);
|
||||
if (log_fd > 0) {
|
||||
sys_write(log_fd, time_str, time_len);
|
||||
sys_write(log_fd, ",", 1);
|
||||
sys_write(log_fd, buf, my_strlen(buf));
|
||||
sys_write(log_fd, "\n", 1);
|
||||
IGNORE_RET(sys_close(log_fd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
char g_crash_log_path[256];
|
||||
|
||||
void HandleCrashDump(const BreakpadInfo& info) {
|
||||
int dumpfd;
|
||||
bool keep_fd = false;
|
||||
size_t dump_size;
|
||||
uint8_t* dump_data;
|
||||
google_breakpad::PageAllocator allocator;
|
||||
const char* exe_buf = NULL;
|
||||
|
||||
if (info.fd != -1) {
|
||||
// Dump is provided with an open FD.
|
||||
keep_fd = true;
|
||||
dumpfd = info.fd;
|
||||
|
||||
// The FD is pointing to the end of the file.
|
||||
// Rewind, we'll read the data next.
|
||||
if (lseek(dumpfd, 0, SEEK_SET) == -1) {
|
||||
static const char msg[] =
|
||||
"Cannot upload crash dump: failed to "
|
||||
"reposition minidump FD\n";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
IGNORE_RET(sys_close(dumpfd));
|
||||
return;
|
||||
}
|
||||
LoadDataFromFD(&allocator, info.fd, false, &dump_data, &dump_size);
|
||||
} else {
|
||||
// Dump is provided with a path.
|
||||
keep_fd = false;
|
||||
LoadDataFromFile(&allocator, info.filename, &dumpfd, &dump_data,
|
||||
&dump_size);
|
||||
}
|
||||
|
||||
// We need to build a MIME block for uploading to the server. Since we are
|
||||
// going to fork and run wget, it needs to be written to a temp file.
|
||||
const int ufd = sys_open("/dev/urandom", O_RDONLY, 0);
|
||||
if (ufd < 0) {
|
||||
static const char msg[] =
|
||||
"Cannot upload crash dump because /dev/urandom"
|
||||
" is missing\n";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
static const char temp_file_template[] =
|
||||
"/tmp/chromium-upload-XXXXXXXXXXXXXXXX";
|
||||
char temp_file[sizeof(temp_file_template)];
|
||||
int temp_file_fd = -1;
|
||||
if (keep_fd) {
|
||||
temp_file_fd = dumpfd;
|
||||
// Rewind the destination, we are going to overwrite it.
|
||||
if (lseek(dumpfd, 0, SEEK_SET) == -1) {
|
||||
static const char msg[] =
|
||||
"Cannot upload crash dump: failed to "
|
||||
"reposition minidump FD (2)\n";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
IGNORE_RET(sys_close(dumpfd));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (info.upload) {
|
||||
memcpy(temp_file, temp_file_template, sizeof(temp_file_template));
|
||||
|
||||
for (unsigned i = 0; i < 10; ++i) {
|
||||
uint64_t t;
|
||||
sys_read(ufd, &t, sizeof(t));
|
||||
write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t);
|
||||
|
||||
temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
if (temp_file_fd >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (temp_file_fd < 0) {
|
||||
static const char msg[] =
|
||||
"Failed to create temporary file in /tmp: "
|
||||
"cannot upload crash dump\n";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
IGNORE_RET(sys_close(ufd));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
temp_file_fd = sys_open(info.filename, O_WRONLY, 0600);
|
||||
if (temp_file_fd < 0) {
|
||||
static const char msg[] = "Failed to save crash dump: failed to open\n";
|
||||
WriteLog(msg, sizeof(msg) - 1);
|
||||
IGNORE_RET(sys_close(ufd));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL.
|
||||
char mime_boundary[28 + 16 + 1];
|
||||
my_memset(mime_boundary, '-', 28);
|
||||
uint64_t boundary_rand;
|
||||
sys_read(ufd, &boundary_rand, sizeof(boundary_rand));
|
||||
write_uint64_hex(mime_boundary + 28, boundary_rand);
|
||||
mime_boundary[28 + 16] = 0;
|
||||
IGNORE_RET(sys_close(ufd));
|
||||
|
||||
// The MIME block looks like this:
|
||||
// BOUNDARY \r\n
|
||||
// Content-Disposition: form-data; name="prod" \r\n \r\n
|
||||
// Chrome_Linux \r\n
|
||||
// BOUNDARY \r\n
|
||||
// Content-Disposition: form-data; name="ver" \r\n \r\n
|
||||
// 1.2.3.4 \r\n
|
||||
// BOUNDARY \r\n
|
||||
//
|
||||
// zero or one:
|
||||
// Content-Disposition: form-data; name="ptime" \r\n \r\n
|
||||
// abcdef \r\n
|
||||
// BOUNDARY \r\n
|
||||
//
|
||||
// zero or one:
|
||||
// Content-Disposition: form-data; name="ptype" \r\n \r\n
|
||||
// abcdef \r\n
|
||||
// BOUNDARY \r\n
|
||||
//
|
||||
// zero or one:
|
||||
// Content-Disposition: form-data; name="lsb-release" \r\n \r\n
|
||||
// abcdef \r\n
|
||||
// BOUNDARY \r\n
|
||||
//
|
||||
// zero or one:
|
||||
// Content-Disposition: form-data; name="oom-size" \r\n \r\n
|
||||
// 1234567890 \r\n
|
||||
// BOUNDARY \r\n
|
||||
//
|
||||
// zero or more (up to CrashKeyStorage::num_entries = 64):
|
||||
// Content-Disposition: form-data; name=crash-key-name \r\n
|
||||
// crash-key-value \r\n
|
||||
// BOUNDARY \r\n
|
||||
//
|
||||
// Content-Disposition: form-data; name="dump"; filename="dump" \r\n
|
||||
// Content-Type: application/octet-stream \r\n \r\n
|
||||
// <dump contents>
|
||||
// \r\n BOUNDARY -- \r\n
|
||||
|
||||
MimeWriter writer(temp_file_fd, mime_boundary);
|
||||
{
|
||||
writer.AddBoundary();
|
||||
if (info.pid > 0) {
|
||||
char pid_value_buf[kUint64StringSize];
|
||||
uint64_t pid_value_len = my_uint64_len(info.pid);
|
||||
my_uint64tos(pid_value_buf, info.pid, pid_value_len);
|
||||
static const char pid_key_name[] = "pid";
|
||||
writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1, pid_value_buf,
|
||||
pid_value_len);
|
||||
writer.AddBoundary();
|
||||
}
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
if (info.process_start_time > 0) {
|
||||
struct kernel_timeval tv;
|
||||
if (!sys_gettimeofday(&tv, NULL)) {
|
||||
uint64_t time = kernel_timeval_to_ms(&tv);
|
||||
if (time > info.process_start_time) {
|
||||
time -= info.process_start_time;
|
||||
char time_str[kUint64StringSize];
|
||||
const unsigned time_len = my_uint64_len(time);
|
||||
my_uint64tos(time_str, time, time_len);
|
||||
|
||||
static const char process_time_msg[] = "ptime";
|
||||
writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1,
|
||||
time_str, time_len);
|
||||
writer.AddBoundary();
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info.distro_length) {
|
||||
static const char distro_msg[] = "lsb-release";
|
||||
writer.AddPairString(distro_msg, info.distro);
|
||||
writer.AddBoundary();
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
if (info.oom_size) {
|
||||
char oom_size_str[kUint64StringSize];
|
||||
const unsigned oom_size_len = my_uint64_len(info.oom_size);
|
||||
my_uint64tos(oom_size_str, info.oom_size, oom_size_len);
|
||||
static const char oom_size_msg[] = "oom-size";
|
||||
writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1, oom_size_str,
|
||||
oom_size_len);
|
||||
writer.AddBoundary();
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
if (info.crash_keys) {
|
||||
CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys);
|
||||
const CrashKeyStorage::Entry* entry;
|
||||
while ((entry = crash_key_iterator.Next())) {
|
||||
writer.AddPairString(entry->key, entry->value);
|
||||
writer.AddBoundary();
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
writer.AddFileContents(g_dump_msg, dump_data, dump_size);
|
||||
writer.AddEnd();
|
||||
writer.Flush();
|
||||
|
||||
IGNORE_RET(sys_close(temp_file_fd));
|
||||
|
||||
if (!info.upload)
|
||||
return;
|
||||
|
||||
const pid_t child = sys_fork();
|
||||
if (!child) {
|
||||
// Spawned helper process.
|
||||
//
|
||||
// This code is called both when a browser is crashing (in which case,
|
||||
// nothing really matters any more) and when a renderer/plugin crashes, in
|
||||
// which case we need to continue.
|
||||
//
|
||||
// Since we are a multithreaded app, if we were just to fork(), we might
|
||||
// grab file descriptors which have just been created in another thread and
|
||||
// hold them open for too long.
|
||||
//
|
||||
// Thus, we have to loop and try and close everything.
|
||||
const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0);
|
||||
if (fd < 0) {
|
||||
for (unsigned i = 3; i < 8192; ++i)
|
||||
IGNORE_RET(sys_close(i));
|
||||
} else {
|
||||
google_breakpad::DirectoryReader reader(fd);
|
||||
const char* name;
|
||||
while (reader.GetNextEntry(&name)) {
|
||||
int i;
|
||||
if (my_strtoui(&i, name) && i > 2 && i != fd)
|
||||
IGNORE_RET(sys_close(i));
|
||||
reader.PopEntry();
|
||||
}
|
||||
|
||||
IGNORE_RET(sys_close(fd));
|
||||
}
|
||||
|
||||
IGNORE_RET(sys_setsid());
|
||||
|
||||
// Leave one end of a pipe in the upload process and watch for it getting
|
||||
// closed by the upload process exiting.
|
||||
int fds[2];
|
||||
if (sys_pipe(fds) >= 0) {
|
||||
const pid_t upload_child = sys_fork();
|
||||
if (!upload_child) {
|
||||
// Upload process.
|
||||
IGNORE_RET(sys_close(fds[0]));
|
||||
IGNORE_RET(sys_dup2(fds[1], 3));
|
||||
ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf,
|
||||
&allocator);
|
||||
}
|
||||
|
||||
// Helper process.
|
||||
if (upload_child > 0) {
|
||||
IGNORE_RET(sys_close(fds[1]));
|
||||
|
||||
const size_t kCrashIdLength = 36;
|
||||
char id_buf[kCrashIdLength + 1];
|
||||
size_t bytes_read =
|
||||
WaitForCrashReportUploadProcess(fds[0], kCrashIdLength, id_buf);
|
||||
HandleCrashReportId(id_buf, bytes_read, kCrashIdLength);
|
||||
|
||||
if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) {
|
||||
// Upload process is still around, kill it.
|
||||
sys_kill(upload_child, SIGKILL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper process.
|
||||
IGNORE_RET(sys_unlink(info.filename));
|
||||
IGNORE_RET(sys_unlink(temp_file));
|
||||
sys__exit(0);
|
||||
}
|
||||
|
||||
// Main browser process.
|
||||
if (child <= 0)
|
||||
return;
|
||||
(void)HANDLE_EINTR(sys_waitpid(child, NULL, 0));
|
||||
}
|
||||
|
||||
size_t WriteLog(const char* buf, size_t nbytes) {
|
||||
return sys_write(2, buf, nbytes);
|
||||
}
|
||||
|
||||
size_t WriteNewline() {
|
||||
return WriteLog("\n", 1);
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
46
shell/common/crash_reporter/linux/crash_dump_handler.h
Normal file
46
shell/common/crash_reporter/linux/crash_dump_handler.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_CRASH_REPORTER_LINUX_CRASH_DUMP_HANDLER_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_LINUX_CRASH_DUMP_HANDLER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "breakpad/src/common/simple_string_dictionary.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
typedef google_breakpad::NonAllocatingMap<256, 256, 64> CrashKeyStorage;
|
||||
|
||||
// BreakpadInfo describes a crash report.
|
||||
// The minidump information can either be contained in a file descriptor (fd) or
|
||||
// in a file (whose path is in filename).
|
||||
struct BreakpadInfo {
|
||||
int fd; // File descriptor to the Breakpad dump data.
|
||||
const char* filename; // Path to the Breakpad dump data.
|
||||
const char* distro; // Linux distro string.
|
||||
unsigned distro_length; // Length of |distro|.
|
||||
bool upload; // Whether to upload or save crash dump.
|
||||
uint64_t process_start_time; // Uptime of the crashing process.
|
||||
size_t oom_size; // Amount of memory requested if OOM.
|
||||
uint64_t pid; // PID where applicable.
|
||||
const char* upload_url; // URL to upload the minidump.
|
||||
CrashKeyStorage* crash_keys;
|
||||
};
|
||||
|
||||
void HandleCrashDump(const BreakpadInfo& info);
|
||||
|
||||
size_t WriteLog(const char* buf, size_t nbytes);
|
||||
size_t WriteNewline();
|
||||
|
||||
// Global variable storing the path of upload log.
|
||||
extern char g_crash_log_path[256];
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_LINUX_CRASH_DUMP_HANDLER_H_
|
508
shell/common/crash_reporter/win/crash_service.cc
Normal file
508
shell/common/crash_reporter/win/crash_service.cc
Normal file
|
@ -0,0 +1,508 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. 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/crash_reporter/win/crash_service.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <sddl.h>
|
||||
#include <fstream> // NOLINT
|
||||
#include <map>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "breakpad/src/client/windows/crash_generation/client_info.h"
|
||||
#include "breakpad/src/client/windows/crash_generation/crash_generation_server.h"
|
||||
#include "breakpad/src/client/windows/sender/crash_report_sender.h"
|
||||
|
||||
namespace breakpad {
|
||||
|
||||
namespace {
|
||||
|
||||
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
|
||||
const wchar_t kClassNameFormat[] = L"$1CrashServiceWindow";
|
||||
|
||||
const wchar_t kTestPipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
|
||||
|
||||
const wchar_t kGoogleReportURL[] = L"https://clients2.google.com/cr/report";
|
||||
const wchar_t kCheckPointFile[] = L"crash_checkpoint.txt";
|
||||
|
||||
typedef std::map<std::wstring, std::wstring> CrashMap;
|
||||
|
||||
bool CustomInfoToMap(const google_breakpad::ClientInfo* client_info,
|
||||
const std::wstring& reporter_tag,
|
||||
CrashMap* map) {
|
||||
google_breakpad::CustomClientInfo info = client_info->GetCustomInfo();
|
||||
|
||||
for (uintptr_t i = 0; i < info.count; ++i) {
|
||||
(*map)[info.entries[i].name] = info.entries[i].value;
|
||||
}
|
||||
|
||||
(*map)[L"rept"] = reporter_tag;
|
||||
|
||||
return !map->empty();
|
||||
}
|
||||
|
||||
bool WriteCustomInfoToFile(const std::wstring& dump_path, const CrashMap& map) {
|
||||
std::wstring file_path(dump_path);
|
||||
size_t last_dot = file_path.rfind(L'.');
|
||||
if (last_dot == std::wstring::npos)
|
||||
return false;
|
||||
file_path.resize(last_dot);
|
||||
file_path += L".txt";
|
||||
|
||||
std::wofstream file(file_path.c_str(), std::ios_base::out |
|
||||
std::ios_base::app |
|
||||
std::ios::binary);
|
||||
if (!file.is_open())
|
||||
return false;
|
||||
|
||||
CrashMap::const_iterator pos;
|
||||
for (pos = map.begin(); pos != map.end(); ++pos) {
|
||||
std::wstring line = pos->first;
|
||||
line += L':';
|
||||
line += pos->second;
|
||||
line += L'\n';
|
||||
file.write(line.c_str(), static_cast<std::streamsize>(line.length()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteReportIDToFile(const std::wstring& dump_path,
|
||||
const std::wstring& report_id) {
|
||||
std::wstring file_path(dump_path);
|
||||
size_t last_slash = file_path.rfind(L'\\');
|
||||
if (last_slash == std::wstring::npos)
|
||||
return false;
|
||||
file_path.resize(last_slash);
|
||||
file_path += L"\\uploads.log";
|
||||
|
||||
std::wofstream file(file_path.c_str(), std::ios_base::out |
|
||||
std::ios_base::app |
|
||||
std::ios::binary);
|
||||
if (!file.is_open())
|
||||
return false;
|
||||
|
||||
int64_t seconds_since_epoch =
|
||||
(base::Time::Now() - base::Time::UnixEpoch()).InSeconds();
|
||||
std::wstring line = base::NumberToString16(seconds_since_epoch);
|
||||
line += L',';
|
||||
line += report_id;
|
||||
line += L'\n';
|
||||
file.write(line.c_str(), static_cast<std::streamsize>(line.length()));
|
||||
return true;
|
||||
}
|
||||
|
||||
// The window procedure task is to handle when a) the user logs off.
|
||||
// b) the system shuts down or c) when the user closes the window.
|
||||
LRESULT __stdcall CrashSvcWndProc(HWND hwnd,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam) {
|
||||
switch (message) {
|
||||
case WM_CLOSE:
|
||||
case WM_ENDSESSION:
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hwnd, message, wparam, lparam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This is the main and only application window.
|
||||
HWND g_top_window = NULL;
|
||||
|
||||
bool CreateTopWindow(HINSTANCE instance,
|
||||
const base::string16& application_name,
|
||||
bool visible) {
|
||||
base::string16 class_name =
|
||||
base::ReplaceStringPlaceholders(kClassNameFormat, application_name, NULL);
|
||||
|
||||
WNDCLASSEXW wcx = {0};
|
||||
wcx.cbSize = sizeof(wcx);
|
||||
wcx.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcx.lpfnWndProc = CrashSvcWndProc;
|
||||
wcx.hInstance = instance;
|
||||
wcx.lpszClassName = class_name.c_str();
|
||||
::RegisterClassExW(&wcx);
|
||||
DWORD style = visible ? WS_POPUPWINDOW | WS_VISIBLE : WS_OVERLAPPED;
|
||||
|
||||
// The window size is zero but being a popup window still shows in the
|
||||
// task bar and can be closed using the system menu or using task manager.
|
||||
HWND window = CreateWindowExW(0, wcx.lpszClassName, L"crash service", style,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL,
|
||||
instance, NULL);
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
::UpdateWindow(window);
|
||||
VLOG(1) << "window handle is " << window;
|
||||
g_top_window = window;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Simple helper class to keep the process alive until the current request
|
||||
// finishes.
|
||||
class ProcessingLock {
|
||||
public:
|
||||
ProcessingLock() { ::InterlockedIncrement(&op_count_); }
|
||||
~ProcessingLock() { ::InterlockedDecrement(&op_count_); }
|
||||
static bool IsWorking() { return (op_count_ != 0); }
|
||||
|
||||
private:
|
||||
static volatile LONG op_count_;
|
||||
};
|
||||
|
||||
volatile LONG ProcessingLock::op_count_ = 0;
|
||||
|
||||
// This structure contains the information that the worker thread needs to
|
||||
// send a crash dump to the server.
|
||||
struct DumpJobInfo {
|
||||
DWORD pid;
|
||||
CrashService* self;
|
||||
CrashMap map;
|
||||
std::wstring dump_path;
|
||||
|
||||
DumpJobInfo(DWORD process_id,
|
||||
CrashService* service,
|
||||
const CrashMap& crash_map,
|
||||
const std::wstring& path)
|
||||
: pid(process_id), self(service), map(crash_map), dump_path(path) {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Command line switches:
|
||||
const char CrashService::kMaxReports[] = "max-reports";
|
||||
const char CrashService::kNoWindow[] = "no-window";
|
||||
const char CrashService::kReporterTag[] = "reporter";
|
||||
const char CrashService::kDumpsDir[] = "dumps-dir";
|
||||
const char CrashService::kPipeName[] = "pipe-name";
|
||||
const char CrashService::kReporterURL[] = "reporter-url";
|
||||
|
||||
CrashService::CrashService() {}
|
||||
|
||||
CrashService::~CrashService() {
|
||||
base::AutoLock lock(sending_);
|
||||
delete dumper_;
|
||||
delete sender_;
|
||||
}
|
||||
|
||||
bool CrashService::Initialize(const base::string16& application_name,
|
||||
const base::FilePath& operating_dir,
|
||||
const base::FilePath& dumps_path) {
|
||||
using google_breakpad::CrashGenerationServer;
|
||||
using google_breakpad::CrashReportSender;
|
||||
|
||||
std::wstring pipe_name = kTestPipeName;
|
||||
int max_reports = -1;
|
||||
|
||||
// The checkpoint file allows CrashReportSender to enforce the maximum
|
||||
// reports per day quota. Does not seem to serve any other purpose.
|
||||
base::FilePath checkpoint_path = operating_dir.Append(kCheckPointFile);
|
||||
|
||||
base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
|
||||
|
||||
base::FilePath dumps_path_to_use = dumps_path;
|
||||
|
||||
if (cmd_line.HasSwitch(kDumpsDir)) {
|
||||
dumps_path_to_use =
|
||||
base::FilePath(cmd_line.GetSwitchValueNative(kDumpsDir));
|
||||
}
|
||||
|
||||
// We can override the send reports quota with a command line switch.
|
||||
if (cmd_line.HasSwitch(kMaxReports))
|
||||
max_reports = _wtoi(cmd_line.GetSwitchValueNative(kMaxReports).c_str());
|
||||
|
||||
// Allow the global pipe name to be overridden for better testability.
|
||||
if (cmd_line.HasSwitch(kPipeName))
|
||||
pipe_name = cmd_line.GetSwitchValueNative(kPipeName);
|
||||
|
||||
if (max_reports > 0) {
|
||||
// Create the http sender object.
|
||||
sender_ = new CrashReportSender(checkpoint_path.value());
|
||||
sender_->set_max_reports_per_day(max_reports);
|
||||
}
|
||||
|
||||
SECURITY_ATTRIBUTES security_attributes = {0};
|
||||
SECURITY_DESCRIPTOR* security_descriptor =
|
||||
reinterpret_cast<SECURITY_DESCRIPTOR*>(
|
||||
GetSecurityDescriptorForLowIntegrity());
|
||||
DCHECK(security_descriptor != NULL);
|
||||
|
||||
security_attributes.nLength = sizeof(security_attributes);
|
||||
security_attributes.lpSecurityDescriptor = security_descriptor;
|
||||
security_attributes.bInheritHandle = FALSE;
|
||||
|
||||
// Create the OOP crash generator object.
|
||||
dumper_ = new CrashGenerationServer(
|
||||
pipe_name, &security_attributes, &CrashService::OnClientConnected, this,
|
||||
&CrashService::OnClientDumpRequest, this, &CrashService::OnClientExited,
|
||||
this, NULL, NULL, true, &dumps_path_to_use.value());
|
||||
|
||||
if (!dumper_) {
|
||||
LOG(ERROR) << "could not create dumper";
|
||||
if (security_attributes.lpSecurityDescriptor)
|
||||
LocalFree(security_attributes.lpSecurityDescriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateTopWindow(::GetModuleHandleW(NULL), application_name,
|
||||
!cmd_line.HasSwitch(kNoWindow))) {
|
||||
LOG(ERROR) << "could not create window";
|
||||
if (security_attributes.lpSecurityDescriptor)
|
||||
LocalFree(security_attributes.lpSecurityDescriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
reporter_tag_ = L"crash svc";
|
||||
if (cmd_line.HasSwitch(kReporterTag))
|
||||
reporter_tag_ = cmd_line.GetSwitchValueNative(kReporterTag);
|
||||
|
||||
reporter_url_ = kGoogleReportURL;
|
||||
if (cmd_line.HasSwitch(kReporterURL))
|
||||
reporter_url_ = cmd_line.GetSwitchValueNative(kReporterURL);
|
||||
|
||||
// Log basic information.
|
||||
VLOG(1) << "pipe name is " << pipe_name << "\ndumps at "
|
||||
<< dumps_path_to_use.value();
|
||||
|
||||
if (sender_) {
|
||||
VLOG(1) << "checkpoint is " << checkpoint_path.value() << "\nserver is "
|
||||
<< reporter_url_ << "\nmaximum " << sender_->max_reports_per_day()
|
||||
<< " reports/day"
|
||||
<< "\nreporter is " << reporter_tag_;
|
||||
}
|
||||
// Start servicing clients.
|
||||
if (!dumper_->Start()) {
|
||||
LOG(ERROR) << "could not start dumper";
|
||||
if (security_attributes.lpSecurityDescriptor)
|
||||
LocalFree(security_attributes.lpSecurityDescriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (security_attributes.lpSecurityDescriptor)
|
||||
LocalFree(security_attributes.lpSecurityDescriptor);
|
||||
|
||||
// Create or open an event to signal the browser process that the crash
|
||||
// service is initialized.
|
||||
base::string16 wait_name =
|
||||
base::ReplaceStringPlaceholders(kWaitEventFormat, application_name, NULL);
|
||||
HANDLE wait_event = ::CreateEventW(NULL, TRUE, TRUE, wait_name.c_str());
|
||||
::SetEvent(wait_event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CrashService::OnClientConnected(
|
||||
void* context,
|
||||
const google_breakpad::ClientInfo* client_info) {
|
||||
ProcessingLock lock;
|
||||
VLOG(1) << "client start. pid = " << client_info->pid();
|
||||
CrashService* self = static_cast<CrashService*>(context);
|
||||
::InterlockedIncrement(&self->clients_connected_);
|
||||
}
|
||||
|
||||
void CrashService::OnClientExited(
|
||||
void* context,
|
||||
const google_breakpad::ClientInfo* client_info) {
|
||||
ProcessingLock processing_lock;
|
||||
VLOG(1) << "client end. pid = " << client_info->pid();
|
||||
CrashService* self = static_cast<CrashService*>(context);
|
||||
::InterlockedIncrement(&self->clients_terminated_);
|
||||
|
||||
if (!self->sender_)
|
||||
return;
|
||||
|
||||
// When we are instructed to send reports we need to exit if there are
|
||||
// no more clients to service. The next client that runs will start us.
|
||||
// Only chrome.exe starts crash_service with a non-zero max_reports.
|
||||
if (self->clients_connected_ > self->clients_terminated_)
|
||||
return;
|
||||
if (self->sender_->max_reports_per_day() > 0) {
|
||||
// Wait for the other thread to send crashes, if applicable. The sender
|
||||
// thread takes the sending_ lock, so the sleep is just to give it a
|
||||
// chance to start.
|
||||
::Sleep(1000);
|
||||
base::AutoLock lock(self->sending_);
|
||||
// Some people can restart chrome very fast, check again if we have
|
||||
// a new client before exiting for real.
|
||||
if (self->clients_connected_ == self->clients_terminated_) {
|
||||
VLOG(1) << "zero clients. exiting";
|
||||
::PostMessage(g_top_window, WM_CLOSE, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CrashService::OnClientDumpRequest(
|
||||
void* context,
|
||||
const google_breakpad::ClientInfo* client_info,
|
||||
const std::wstring* file_path) {
|
||||
ProcessingLock lock;
|
||||
|
||||
if (!file_path) {
|
||||
LOG(ERROR) << "dump with no file path";
|
||||
return;
|
||||
}
|
||||
if (!client_info) {
|
||||
LOG(ERROR) << "dump with no client info";
|
||||
return;
|
||||
}
|
||||
|
||||
CrashService* self = static_cast<CrashService*>(context);
|
||||
if (!self) {
|
||||
LOG(ERROR) << "dump with no context";
|
||||
return;
|
||||
}
|
||||
|
||||
CrashMap map;
|
||||
CustomInfoToMap(client_info, self->reporter_tag_, &map);
|
||||
|
||||
// Move dump file to the directory under client breakpad dump location.
|
||||
base::FilePath dump_location = base::FilePath(*file_path);
|
||||
CrashMap::const_iterator it = map.find(L"breakpad-dump-location");
|
||||
if (it != map.end()) {
|
||||
base::FilePath alternate_dump_location = base::FilePath(it->second);
|
||||
base::CreateDirectoryW(alternate_dump_location);
|
||||
alternate_dump_location =
|
||||
alternate_dump_location.Append(dump_location.BaseName());
|
||||
base::Move(dump_location, alternate_dump_location);
|
||||
dump_location = alternate_dump_location;
|
||||
}
|
||||
|
||||
DWORD pid = client_info->pid();
|
||||
VLOG(1) << "dump for pid = " << pid << " is " << dump_location.value();
|
||||
|
||||
if (!WriteCustomInfoToFile(dump_location.value(), map)) {
|
||||
LOG(ERROR) << "could not write custom info file";
|
||||
}
|
||||
|
||||
if (!self->sender_ || map.find(L"skip_upload") != map.end())
|
||||
return;
|
||||
|
||||
// Send the crash dump using a worker thread. This operation has retry
|
||||
// logic in case there is no internet connection at the time.
|
||||
DumpJobInfo* dump_job =
|
||||
new DumpJobInfo(pid, self, map, dump_location.value());
|
||||
if (!::QueueUserWorkItem(&CrashService::AsyncSendDump, dump_job,
|
||||
WT_EXECUTELONGFUNCTION)) {
|
||||
LOG(ERROR) << "could not queue job";
|
||||
}
|
||||
}
|
||||
|
||||
// We are going to try sending the report several times. If we can't send,
|
||||
// we sleep from one minute to several hours depending on the retry round.
|
||||
DWORD CrashService::AsyncSendDump(void* context) {
|
||||
if (!context)
|
||||
return 0;
|
||||
|
||||
DumpJobInfo* info = static_cast<DumpJobInfo*>(context);
|
||||
|
||||
std::wstring report_id = L"<unsent>";
|
||||
|
||||
const DWORD kOneMinute = 60 * 1000;
|
||||
const DWORD kOneHour = 60 * kOneMinute;
|
||||
|
||||
const DWORD kSleepSchedule[] = {24 * kOneHour, 8 * kOneHour, 4 * kOneHour,
|
||||
kOneHour, 15 * kOneMinute, 0};
|
||||
|
||||
int retry_round = base::size(kSleepSchedule) - 1;
|
||||
|
||||
do {
|
||||
::Sleep(kSleepSchedule[retry_round]);
|
||||
{
|
||||
// Take the server lock while sending. This also prevent early
|
||||
// termination of the service object.
|
||||
base::AutoLock lock(info->self->sending_);
|
||||
VLOG(1) << "trying to send report for pid = " << info->pid;
|
||||
std::map<std::wstring, std::wstring> file_map;
|
||||
file_map[L"upload_file_minidump"] = info->dump_path;
|
||||
google_breakpad::ReportResult send_result =
|
||||
info->self->sender_->SendCrashReport(info->self->reporter_url_,
|
||||
info->map, file_map, &report_id);
|
||||
switch (send_result) {
|
||||
case google_breakpad::RESULT_FAILED:
|
||||
report_id = L"<network issue>";
|
||||
break;
|
||||
case google_breakpad::RESULT_REJECTED:
|
||||
report_id = L"<rejected>";
|
||||
++info->self->requests_handled_;
|
||||
retry_round = 0;
|
||||
break;
|
||||
case google_breakpad::RESULT_SUCCEEDED:
|
||||
++info->self->requests_sent_;
|
||||
++info->self->requests_handled_;
|
||||
retry_round = 0;
|
||||
WriteReportIDToFile(info->dump_path, report_id);
|
||||
break;
|
||||
case google_breakpad::RESULT_THROTTLED:
|
||||
report_id = L"<throttled>";
|
||||
break;
|
||||
default:
|
||||
report_id = L"<unknown>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VLOG(1) << "dump for pid =" << info->pid << " crash2 id =" << report_id;
|
||||
--retry_round;
|
||||
} while (retry_round >= 0);
|
||||
|
||||
if (!::DeleteFileW(info->dump_path.c_str()))
|
||||
LOG(WARNING) << "could not delete " << info->dump_path;
|
||||
|
||||
delete info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CrashService::ProcessingLoop() {
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
VLOG(1) << "session ending..";
|
||||
while (ProcessingLock::IsWorking()) {
|
||||
::Sleep(50);
|
||||
}
|
||||
|
||||
VLOG(1) << "clients connected :" << clients_connected_
|
||||
<< "\nclients terminated :" << clients_terminated_
|
||||
<< "\ndumps serviced :" << requests_handled_
|
||||
<< "\ndumps reported :" << requests_sent_;
|
||||
|
||||
return static_cast<int>(msg.wParam);
|
||||
}
|
||||
|
||||
PSECURITY_DESCRIPTOR CrashService::GetSecurityDescriptorForLowIntegrity() {
|
||||
// Build the SDDL string for the label.
|
||||
std::wstring sddl = L"S:(ML;;NW;;;S-1-16-4096)";
|
||||
|
||||
PSECURITY_DESCRIPTOR sec_desc = NULL;
|
||||
|
||||
PACL sacl = NULL;
|
||||
BOOL sacl_present = FALSE;
|
||||
BOOL sacl_defaulted = FALSE;
|
||||
|
||||
if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
||||
sddl.c_str(), SDDL_REVISION, &sec_desc, NULL)) {
|
||||
if (::GetSecurityDescriptorSacl(sec_desc, &sacl_present, &sacl,
|
||||
&sacl_defaulted)) {
|
||||
return sec_desc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace breakpad
|
130
shell/common/crash_reporter/win/crash_service.h
Normal file
130
shell/common/crash_reporter/win/crash_service.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class CrashReportSender;
|
||||
class CrashGenerationServer;
|
||||
class ClientInfo;
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
namespace breakpad {
|
||||
|
||||
// This class implements an out-of-process crash server. It uses breakpad's
|
||||
// CrashGenerationServer and CrashReportSender to generate and then send the
|
||||
// crash dumps. Internally, it uses OS specific pipe to allow applications to
|
||||
// register for crash dumps and later on when a registered application crashes
|
||||
// it will signal an event that causes this code to wake up and perform a
|
||||
// crash dump on the signaling process. The dump is then stored on disk and
|
||||
// possibly sent to the crash2 servers.
|
||||
class CrashService {
|
||||
public:
|
||||
CrashService();
|
||||
~CrashService();
|
||||
|
||||
// Starts servicing crash dumps. Returns false if it failed. Do not use
|
||||
// other members in that case. |operating_dir| is where the CrashService
|
||||
// should store breakpad's checkpoint file. |dumps_path| is the directory
|
||||
// where the crash dumps should be stored.
|
||||
bool Initialize(const base::string16& application_name,
|
||||
const base::FilePath& operating_dir,
|
||||
const base::FilePath& dumps_path);
|
||||
|
||||
// Command line switches:
|
||||
//
|
||||
// --max-reports=<number>
|
||||
// Allows to override the maximum number for reports per day. Normally
|
||||
// the crash dumps are never sent so if you want to send any you must
|
||||
// specify a positive number here.
|
||||
static const char kMaxReports[];
|
||||
// --no-window
|
||||
// Does not create a visible window on the desktop. The window does not have
|
||||
// any other functionality other than allowing the crash service to be
|
||||
// gracefully closed.
|
||||
static const char kNoWindow[];
|
||||
// --reporter=<string>
|
||||
// Allows to specify a custom string that appears on the detail crash report
|
||||
// page in the crash server. This should be a 25 chars or less string.
|
||||
// The default tag if not specified is 'crash svc'.
|
||||
static const char kReporterTag[];
|
||||
// --dumps-dir=<directory-path>
|
||||
// Override the directory to which crash dump files will be written.
|
||||
static const char kDumpsDir[];
|
||||
// --pipe-name=<string>
|
||||
// Override the name of the Windows named pipe on which we will
|
||||
// listen for crash dump request messages.
|
||||
static const char kPipeName[];
|
||||
// --reporter-url=<string>
|
||||
// Override the URL to which crash reports will be sent to.
|
||||
static const char kReporterURL[];
|
||||
|
||||
// Returns number of crash dumps handled.
|
||||
int requests_handled() const { return requests_handled_; }
|
||||
// Returns number of crash clients registered.
|
||||
int clients_connected() const { return clients_connected_; }
|
||||
// Returns number of crash clients terminated.
|
||||
int clients_terminated() const { return clients_terminated_; }
|
||||
|
||||
// Starts the processing loop. This function does not return unless the
|
||||
// user is logging off or the user closes the crash service window. The
|
||||
// return value is a good number to pass in ExitProcess().
|
||||
int ProcessingLoop();
|
||||
|
||||
private:
|
||||
static void OnClientConnected(void* context,
|
||||
const google_breakpad::ClientInfo* client_info);
|
||||
|
||||
static void OnClientDumpRequest(
|
||||
void* context,
|
||||
const google_breakpad::ClientInfo* client_info,
|
||||
const std::wstring* file_path);
|
||||
|
||||
static void OnClientExited(void* context,
|
||||
const google_breakpad::ClientInfo* client_info);
|
||||
|
||||
// This routine sends the crash dump to the server. It takes the sending_
|
||||
// lock when it is performing the send.
|
||||
static DWORD __stdcall AsyncSendDump(void* context);
|
||||
|
||||
// Returns the security descriptor which access to low integrity processes
|
||||
// The caller is supposed to free the security descriptor by calling
|
||||
// LocalFree.
|
||||
PSECURITY_DESCRIPTOR GetSecurityDescriptorForLowIntegrity();
|
||||
|
||||
google_breakpad::CrashGenerationServer* dumper_ = nullptr;
|
||||
google_breakpad::CrashReportSender* sender_ = nullptr;
|
||||
|
||||
// the extra tag sent to the server with each dump.
|
||||
std::wstring reporter_tag_;
|
||||
|
||||
// receiver URL of crash reports.
|
||||
std::wstring reporter_url_;
|
||||
|
||||
// clients serviced statistics:
|
||||
int requests_handled_ = 0;
|
||||
int requests_sent_ = 0;
|
||||
volatile LONG clients_connected_ = 0;
|
||||
volatile LONG clients_terminated_ = 0;
|
||||
base::Lock sending_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashService);
|
||||
};
|
||||
|
||||
} // namespace breakpad
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_H_
|
81
shell/common/crash_reporter/win/crash_service_main.cc
Normal file
81
shell/common/crash_reporter/win/crash_service_main.cc
Normal file
|
@ -0,0 +1,81 @@
|
|||
// 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/crash_reporter/win/crash_service_main.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/crash_reporter/crash_reporter.h"
|
||||
#include "atom/common/crash_reporter/win/crash_service.h"
|
||||
#include "base/at_exit.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "third_party/crashpad/crashpad/handler/handler_main.h"
|
||||
|
||||
namespace crash_service {
|
||||
|
||||
namespace {
|
||||
|
||||
const wchar_t kStandardLogFile[] = L"operation_log.txt";
|
||||
|
||||
void InvalidParameterHandler(const wchar_t*,
|
||||
const wchar_t*,
|
||||
const wchar_t*,
|
||||
unsigned int,
|
||||
uintptr_t) {
|
||||
// noop.
|
||||
}
|
||||
|
||||
bool CreateCrashServiceDirectory(const base::FilePath& temp_dir) {
|
||||
if (!base::PathExists(temp_dir)) {
|
||||
if (!base::CreateDirectory(temp_dir))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoveArgs(std::vector<char*>* args) {
|
||||
args->erase(
|
||||
std::remove_if(args->begin(), args->end(), [](const std::string& str) {
|
||||
return base::StartsWith(str, "--type", base::CompareCase::SENSITIVE) ||
|
||||
base::StartsWith(
|
||||
str,
|
||||
std::string("--") + crash_reporter::kCrashesDirectoryKey,
|
||||
base::CompareCase::INSENSITIVE_ASCII);
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace.
|
||||
|
||||
int Main(std::vector<char*>* args) {
|
||||
// Ignore invalid parameter errors.
|
||||
_set_invalid_parameter_handler(InvalidParameterHandler);
|
||||
|
||||
// Initialize all Chromium things.
|
||||
base::AtExitManager exit_manager;
|
||||
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
|
||||
// We use/create a directory under the user's temp folder, for logging.
|
||||
base::FilePath operating_dir(
|
||||
cmd_line->GetSwitchValueNative(crash_reporter::kCrashesDirectoryKey));
|
||||
CreateCrashServiceDirectory(operating_dir);
|
||||
base::FilePath log_file = operating_dir.Append(kStandardLogFile);
|
||||
|
||||
// Logging to stderr (to help with debugging failures on the
|
||||
// buildbots) and to a file.
|
||||
logging::LoggingSettings settings;
|
||||
settings.logging_dest = logging::LOG_TO_ALL;
|
||||
settings.log_file = log_file.value().c_str();
|
||||
logging::InitLogging(settings);
|
||||
// Logging with pid, tid and timestamp.
|
||||
logging::SetLogItems(true, true, true, false);
|
||||
|
||||
// Crashpad cannot handle unknown arguments, so we need to remove it
|
||||
RemoveArgs(args);
|
||||
return crashpad::HandlerMain(args->size(), args->data(), nullptr);
|
||||
}
|
||||
|
||||
} // namespace crash_service
|
17
shell/common/crash_reporter/win/crash_service_main.h
Normal file
17
shell/common/crash_reporter/win/crash_service_main.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
// 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_CRASH_REPORTER_WIN_CRASH_SERVICE_MAIN_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_MAIN_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace crash_service {
|
||||
|
||||
// Program entry, should be called by main();
|
||||
int Main(std::vector<char*>* args);
|
||||
|
||||
} // namespace crash_service
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_MAIN_H_
|
27
shell/common/deprecate_util.cc
Normal file
27
shell/common/deprecate_util.cc
Normal file
|
@ -0,0 +1,27 @@
|
|||
// 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/deprecate_util.h"
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "base/callback.h"
|
||||
#include "native_mate/converter.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
void EmitDeprecationWarning(node::Environment* env,
|
||||
const std::string& warning_msg,
|
||||
const std::string& warning_type) {
|
||||
mate::Dictionary process(env->isolate(), env->process_object());
|
||||
|
||||
base::RepeatingCallback<void(base::StringPiece, base::StringPiece,
|
||||
base::StringPiece)>
|
||||
emit_warning;
|
||||
process.Get("emitWarning", &emit_warning);
|
||||
|
||||
emit_warning.Run(warning_msg, warning_type, "");
|
||||
}
|
||||
|
||||
} // namespace atom
|
20
shell/common/deprecate_util.h
Normal file
20
shell/common/deprecate_util.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) 2019 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_DEPRECATE_UTIL_H_
|
||||
#define ATOM_COMMON_DEPRECATE_UTIL_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
void EmitDeprecationWarning(node::Environment* env,
|
||||
const std::string& warning_msg,
|
||||
const std::string& warning_type);
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_DEPRECATE_UTIL_H_
|
29
shell/common/gin_util.h
Normal file
29
shell/common/gin_util.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2018 Slack Technologies, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_GIN_UTIL_H_
|
||||
#define ATOM_COMMON_GIN_UTIL_H_
|
||||
|
||||
#include "gin/converter.h"
|
||||
#include "gin/function_template.h"
|
||||
|
||||
namespace gin_util {
|
||||
|
||||
template <typename T>
|
||||
bool SetMethod(v8::Local<v8::Object> recv,
|
||||
const base::StringPiece& key,
|
||||
const T& callback) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
return recv
|
||||
->Set(context, gin::StringToV8(isolate, key),
|
||||
gin::CreateFunctionTemplate(isolate, callback)
|
||||
->GetFunction(context)
|
||||
.ToLocalChecked())
|
||||
.ToChecked();
|
||||
}
|
||||
|
||||
} // namespace gin_util
|
||||
|
||||
#endif // ATOM_COMMON_GIN_UTIL_H_
|
56
shell/common/heap_snapshot.cc
Normal file
56
shell/common/heap_snapshot.cc
Normal file
|
@ -0,0 +1,56 @@
|
|||
// 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/heap_snapshot.h"
|
||||
|
||||
#include "v8/include/v8-profiler.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class HeapSnapshotOutputStream : public v8::OutputStream {
|
||||
public:
|
||||
explicit HeapSnapshotOutputStream(base::File* file) : file_(file) {
|
||||
DCHECK(file_);
|
||||
}
|
||||
|
||||
bool IsComplete() const { return is_complete_; }
|
||||
|
||||
// v8::OutputStream
|
||||
int GetChunkSize() override { return 65536; }
|
||||
void EndOfStream() override { is_complete_ = true; }
|
||||
|
||||
v8::OutputStream::WriteResult WriteAsciiChunk(char* data, int size) override {
|
||||
auto bytes_written = file_->WriteAtCurrentPos(data, size);
|
||||
return bytes_written == size ? kContinue : kAbort;
|
||||
}
|
||||
|
||||
private:
|
||||
base::File* file_ = nullptr;
|
||||
bool is_complete_ = false;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace atom {
|
||||
|
||||
bool TakeHeapSnapshot(v8::Isolate* isolate, base::File* file) {
|
||||
DCHECK(isolate);
|
||||
DCHECK(file);
|
||||
|
||||
if (!file->IsValid())
|
||||
return false;
|
||||
|
||||
auto* snapshot = isolate->GetHeapProfiler()->TakeHeapSnapshot();
|
||||
if (!snapshot)
|
||||
return false;
|
||||
|
||||
HeapSnapshotOutputStream stream(file);
|
||||
snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
|
||||
|
||||
const_cast<v8::HeapSnapshot*>(snapshot)->Delete();
|
||||
|
||||
return stream.IsComplete();
|
||||
}
|
||||
|
||||
} // namespace atom
|
17
shell/common/heap_snapshot.h
Normal file
17
shell/common/heap_snapshot.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
// 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_HEAP_SNAPSHOT_H_
|
||||
#define ATOM_COMMON_HEAP_SNAPSHOT_H_
|
||||
|
||||
#include "base/files/file.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
bool TakeHeapSnapshot(v8::Isolate* isolate, base::File* file);
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_HEAP_SNAPSHOT_H_
|
87
shell/common/key_weak_map.h
Normal file
87
shell/common/key_weak_map.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
// 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_KEY_WEAK_MAP_H_
|
||||
#define ATOM_COMMON_KEY_WEAK_MAP_H_
|
||||
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer.
|
||||
template <typename K>
|
||||
class KeyWeakMap {
|
||||
public:
|
||||
// Records the key and self, used by SetWeak.
|
||||
struct KeyObject {
|
||||
K key;
|
||||
KeyWeakMap* self;
|
||||
};
|
||||
|
||||
KeyWeakMap() {}
|
||||
virtual ~KeyWeakMap() {
|
||||
for (auto& p : map_)
|
||||
p.second.second.ClearWeak();
|
||||
}
|
||||
|
||||
// Sets the object to WeakMap with the given |key|.
|
||||
void Set(v8::Isolate* isolate, const K& key, v8::Local<v8::Object> object) {
|
||||
KeyObject key_object = {key, this};
|
||||
auto& p = map_[key] =
|
||||
std::make_pair(key_object, v8::Global<v8::Object>(isolate, object));
|
||||
p.second.SetWeak(&(p.first), OnObjectGC, v8::WeakCallbackType::kParameter);
|
||||
}
|
||||
|
||||
// Gets the object from WeakMap by its |key|.
|
||||
v8::MaybeLocal<v8::Object> Get(v8::Isolate* isolate, const K& key) {
|
||||
auto iter = map_.find(key);
|
||||
if (iter == map_.end())
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
else
|
||||
return v8::Local<v8::Object>::New(isolate, iter->second.second);
|
||||
}
|
||||
|
||||
// Whethere there is an object with |key| in this WeakMap.
|
||||
bool Has(const K& key) const { return map_.find(key) != map_.end(); }
|
||||
|
||||
// Returns all objects.
|
||||
std::vector<v8::Local<v8::Object>> Values(v8::Isolate* isolate) const {
|
||||
std::vector<v8::Local<v8::Object>> keys;
|
||||
keys.reserve(map_.size());
|
||||
for (const auto& it : map_)
|
||||
keys.emplace_back(v8::Local<v8::Object>::New(isolate, it.second.second));
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Remove object with |key| in the WeakMap.
|
||||
void Remove(const K& key) {
|
||||
auto iter = map_.find(key);
|
||||
if (iter == map_.end())
|
||||
return;
|
||||
|
||||
iter->second.second.ClearWeak();
|
||||
map_.erase(iter);
|
||||
}
|
||||
|
||||
private:
|
||||
static void OnObjectGC(
|
||||
const v8::WeakCallbackInfo<typename KeyWeakMap<K>::KeyObject>& data) {
|
||||
KeyWeakMap<K>::KeyObject* key_object = data.GetParameter();
|
||||
key_object->self->Remove(key_object->key);
|
||||
}
|
||||
|
||||
// Map of stored objects.
|
||||
std::unordered_map<K, std::pair<KeyObject, v8::Global<v8::Object>>> map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(KeyWeakMap);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_KEY_WEAK_MAP_H_
|
358
shell/common/keyboard_util.cc
Normal file
358
shell/common/keyboard_util.cc
Normal file
|
@ -0,0 +1,358 @@
|
|||
// 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 <string>
|
||||
|
||||
#include "atom/common/keyboard_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "third_party/blink/public/platform/web_input_event.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Return key code represented by |str|.
|
||||
ui::KeyboardCode KeyboardCodeFromKeyIdentifier(const std::string& s,
|
||||
bool* shifted) {
|
||||
std::string str = base::ToLowerASCII(s);
|
||||
if (str == "ctrl" || str == "control") {
|
||||
return ui::VKEY_CONTROL;
|
||||
} else if (str == "super" || str == "cmd" || str == "command" ||
|
||||
str == "meta") {
|
||||
return ui::VKEY_COMMAND;
|
||||
} else if (str == "commandorcontrol" || str == "cmdorctrl") {
|
||||
#if defined(OS_MACOSX)
|
||||
return ui::VKEY_COMMAND;
|
||||
#else
|
||||
return ui::VKEY_CONTROL;
|
||||
#endif
|
||||
} else if (str == "alt" || str == "option") {
|
||||
return ui::VKEY_MENU;
|
||||
} else if (str == "shift") {
|
||||
return ui::VKEY_SHIFT;
|
||||
} else if (str == "altgr") {
|
||||
return ui::VKEY_ALTGR;
|
||||
} else if (str == "plus") {
|
||||
*shifted = true;
|
||||
return ui::VKEY_OEM_PLUS;
|
||||
} else if (str == "capslock") {
|
||||
return ui::VKEY_CAPITAL;
|
||||
} else if (str == "numlock") {
|
||||
return ui::VKEY_NUMLOCK;
|
||||
} else if (str == "scrolllock") {
|
||||
return ui::VKEY_SCROLL;
|
||||
} else if (str == "tab") {
|
||||
return ui::VKEY_TAB;
|
||||
} else if (str == "num0") {
|
||||
return ui::VKEY_NUMPAD0;
|
||||
} else if (str == "num1") {
|
||||
return ui::VKEY_NUMPAD1;
|
||||
} else if (str == "num2") {
|
||||
return ui::VKEY_NUMPAD2;
|
||||
} else if (str == "num3") {
|
||||
return ui::VKEY_NUMPAD3;
|
||||
} else if (str == "num4") {
|
||||
return ui::VKEY_NUMPAD4;
|
||||
} else if (str == "num5") {
|
||||
return ui::VKEY_NUMPAD5;
|
||||
} else if (str == "num6") {
|
||||
return ui::VKEY_NUMPAD6;
|
||||
} else if (str == "num7") {
|
||||
return ui::VKEY_NUMPAD7;
|
||||
} else if (str == "num8") {
|
||||
return ui::VKEY_NUMPAD8;
|
||||
} else if (str == "num9") {
|
||||
return ui::VKEY_NUMPAD9;
|
||||
} else if (str == "numadd") {
|
||||
return ui::VKEY_ADD;
|
||||
} else if (str == "nummult") {
|
||||
return ui::VKEY_MULTIPLY;
|
||||
} else if (str == "numdec") {
|
||||
return ui::VKEY_DECIMAL;
|
||||
} else if (str == "numsub") {
|
||||
return ui::VKEY_SUBTRACT;
|
||||
} else if (str == "numdiv") {
|
||||
return ui::VKEY_DIVIDE;
|
||||
} else if (str == "space") {
|
||||
return ui::VKEY_SPACE;
|
||||
} else if (str == "backspace") {
|
||||
return ui::VKEY_BACK;
|
||||
} else if (str == "delete") {
|
||||
return ui::VKEY_DELETE;
|
||||
} else if (str == "insert") {
|
||||
return ui::VKEY_INSERT;
|
||||
} else if (str == "enter" || str == "return") {
|
||||
return ui::VKEY_RETURN;
|
||||
} else if (str == "up") {
|
||||
return ui::VKEY_UP;
|
||||
} else if (str == "down") {
|
||||
return ui::VKEY_DOWN;
|
||||
} else if (str == "left") {
|
||||
return ui::VKEY_LEFT;
|
||||
} else if (str == "right") {
|
||||
return ui::VKEY_RIGHT;
|
||||
} else if (str == "home") {
|
||||
return ui::VKEY_HOME;
|
||||
} else if (str == "end") {
|
||||
return ui::VKEY_END;
|
||||
} else if (str == "pageup") {
|
||||
return ui::VKEY_PRIOR;
|
||||
} else if (str == "pagedown") {
|
||||
return ui::VKEY_NEXT;
|
||||
} else if (str == "esc" || str == "escape") {
|
||||
return ui::VKEY_ESCAPE;
|
||||
} else if (str == "volumemute") {
|
||||
return ui::VKEY_VOLUME_MUTE;
|
||||
} else if (str == "volumeup") {
|
||||
return ui::VKEY_VOLUME_UP;
|
||||
} else if (str == "volumedown") {
|
||||
return ui::VKEY_VOLUME_DOWN;
|
||||
} else if (str == "medianexttrack") {
|
||||
return ui::VKEY_MEDIA_NEXT_TRACK;
|
||||
} else if (str == "mediaprevioustrack") {
|
||||
return ui::VKEY_MEDIA_PREV_TRACK;
|
||||
} else if (str == "mediastop") {
|
||||
return ui::VKEY_MEDIA_STOP;
|
||||
} else if (str == "mediaplaypause") {
|
||||
return ui::VKEY_MEDIA_PLAY_PAUSE;
|
||||
} else if (str == "printscreen") {
|
||||
return ui::VKEY_SNAPSHOT;
|
||||
} else if (str.size() > 1 && str[0] == 'f') {
|
||||
// F1 - F24.
|
||||
int n;
|
||||
if (base::StringToInt(str.c_str() + 1, &n) && n > 0 && n < 25) {
|
||||
return static_cast<ui::KeyboardCode>(ui::VKEY_F1 + n - 1);
|
||||
} else {
|
||||
LOG(WARNING) << str << "is not available on keyboard";
|
||||
return ui::VKEY_UNKNOWN;
|
||||
}
|
||||
} else {
|
||||
if (str.size() > 2)
|
||||
LOG(WARNING) << "Invalid accelerator token: " << str;
|
||||
return ui::VKEY_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ui::KeyboardCode KeyboardCodeFromCharCode(base::char16 c, bool* shifted) {
|
||||
c = base::ToLowerASCII(c);
|
||||
*shifted = false;
|
||||
switch (c) {
|
||||
case 0x08:
|
||||
return ui::VKEY_BACK;
|
||||
case 0x7F:
|
||||
return ui::VKEY_DELETE;
|
||||
case 0x09:
|
||||
return ui::VKEY_TAB;
|
||||
case 0x0D:
|
||||
return ui::VKEY_RETURN;
|
||||
case 0x1B:
|
||||
return ui::VKEY_ESCAPE;
|
||||
case ' ':
|
||||
return ui::VKEY_SPACE;
|
||||
case 'a':
|
||||
return ui::VKEY_A;
|
||||
case 'b':
|
||||
return ui::VKEY_B;
|
||||
case 'c':
|
||||
return ui::VKEY_C;
|
||||
case 'd':
|
||||
return ui::VKEY_D;
|
||||
case 'e':
|
||||
return ui::VKEY_E;
|
||||
case 'f':
|
||||
return ui::VKEY_F;
|
||||
case 'g':
|
||||
return ui::VKEY_G;
|
||||
case 'h':
|
||||
return ui::VKEY_H;
|
||||
case 'i':
|
||||
return ui::VKEY_I;
|
||||
case 'j':
|
||||
return ui::VKEY_J;
|
||||
case 'k':
|
||||
return ui::VKEY_K;
|
||||
case 'l':
|
||||
return ui::VKEY_L;
|
||||
case 'm':
|
||||
return ui::VKEY_M;
|
||||
case 'n':
|
||||
return ui::VKEY_N;
|
||||
case 'o':
|
||||
return ui::VKEY_O;
|
||||
case 'p':
|
||||
return ui::VKEY_P;
|
||||
case 'q':
|
||||
return ui::VKEY_Q;
|
||||
case 'r':
|
||||
return ui::VKEY_R;
|
||||
case 's':
|
||||
return ui::VKEY_S;
|
||||
case 't':
|
||||
return ui::VKEY_T;
|
||||
case 'u':
|
||||
return ui::VKEY_U;
|
||||
case 'v':
|
||||
return ui::VKEY_V;
|
||||
case 'w':
|
||||
return ui::VKEY_W;
|
||||
case 'x':
|
||||
return ui::VKEY_X;
|
||||
case 'y':
|
||||
return ui::VKEY_Y;
|
||||
case 'z':
|
||||
return ui::VKEY_Z;
|
||||
|
||||
case ')':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '0':
|
||||
return ui::VKEY_0;
|
||||
case '!':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '1':
|
||||
return ui::VKEY_1;
|
||||
case '@':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '2':
|
||||
return ui::VKEY_2;
|
||||
case '#':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '3':
|
||||
return ui::VKEY_3;
|
||||
case '$':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '4':
|
||||
return ui::VKEY_4;
|
||||
case '%':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '5':
|
||||
return ui::VKEY_5;
|
||||
case '^':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '6':
|
||||
return ui::VKEY_6;
|
||||
case '&':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '7':
|
||||
return ui::VKEY_7;
|
||||
case '*':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '8':
|
||||
return ui::VKEY_8;
|
||||
case '(':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '9':
|
||||
return ui::VKEY_9;
|
||||
|
||||
case ':':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case ';':
|
||||
return ui::VKEY_OEM_1;
|
||||
case '+':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '=':
|
||||
return ui::VKEY_OEM_PLUS;
|
||||
case '<':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case ',':
|
||||
return ui::VKEY_OEM_COMMA;
|
||||
case '_':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '-':
|
||||
return ui::VKEY_OEM_MINUS;
|
||||
case '>':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '.':
|
||||
return ui::VKEY_OEM_PERIOD;
|
||||
case '?':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '/':
|
||||
return ui::VKEY_OEM_2;
|
||||
case '~':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '`':
|
||||
return ui::VKEY_OEM_3;
|
||||
case '{':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '[':
|
||||
return ui::VKEY_OEM_4;
|
||||
case '|':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '\\':
|
||||
return ui::VKEY_OEM_5;
|
||||
case '}':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case ']':
|
||||
return ui::VKEY_OEM_6;
|
||||
case '"':
|
||||
*shifted = true;
|
||||
FALLTHROUGH;
|
||||
case '\'':
|
||||
return ui::VKEY_OEM_7;
|
||||
|
||||
default:
|
||||
return ui::VKEY_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted) {
|
||||
if (str.size() == 1)
|
||||
return KeyboardCodeFromCharCode(str[0], shifted);
|
||||
else
|
||||
return KeyboardCodeFromKeyIdentifier(str, shifted);
|
||||
}
|
||||
|
||||
int WebEventModifiersToEventFlags(int modifiers) {
|
||||
int flags = 0;
|
||||
|
||||
if (modifiers & blink::WebInputEvent::kShiftKey)
|
||||
flags |= ui::EF_SHIFT_DOWN;
|
||||
if (modifiers & blink::WebInputEvent::kControlKey)
|
||||
flags |= ui::EF_CONTROL_DOWN;
|
||||
if (modifiers & blink::WebInputEvent::kAltKey)
|
||||
flags |= ui::EF_ALT_DOWN;
|
||||
if (modifiers & blink::WebInputEvent::kMetaKey)
|
||||
flags |= ui::EF_COMMAND_DOWN;
|
||||
if (modifiers & blink::WebInputEvent::kCapsLockOn)
|
||||
flags |= ui::EF_CAPS_LOCK_ON;
|
||||
if (modifiers & blink::WebInputEvent::kNumLockOn)
|
||||
flags |= ui::EF_NUM_LOCK_ON;
|
||||
if (modifiers & blink::WebInputEvent::kScrollLockOn)
|
||||
flags |= ui::EF_SCROLL_LOCK_ON;
|
||||
if (modifiers & blink::WebInputEvent::kLeftButtonDown)
|
||||
flags |= ui::EF_LEFT_MOUSE_BUTTON;
|
||||
if (modifiers & blink::WebInputEvent::kMiddleButtonDown)
|
||||
flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
|
||||
if (modifiers & blink::WebInputEvent::kRightButtonDown)
|
||||
flags |= ui::EF_RIGHT_MOUSE_BUTTON;
|
||||
if (modifiers & blink::WebInputEvent::kIsAutoRepeat)
|
||||
flags |= ui::EF_IS_REPEAT;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
} // namespace atom
|
28
shell/common/keyboard_util.h
Normal file
28
shell/common/keyboard_util.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
// 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_KEYBOARD_UTIL_H_
|
||||
#define ATOM_COMMON_KEYBOARD_UTIL_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/strings/string16.h"
|
||||
#include "ui/events/keycodes/keyboard_codes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Return key code of the char, and also determine whether the SHIFT key is
|
||||
// pressed.
|
||||
ui::KeyboardCode KeyboardCodeFromCharCode(base::char16 c, bool* shifted);
|
||||
|
||||
// Return key code of the |str|, and also determine whether the SHIFT key is
|
||||
// pressed.
|
||||
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted);
|
||||
|
||||
// Ported from ui/events/blink/blink_event_util.h
|
||||
int WebEventModifiersToEventFlags(int modifiers);
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_KEYBOARD_UTIL_H_
|
26
shell/common/mac/main_application_bundle.h
Normal file
26
shell/common/mac/main_application_bundle.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Copyright (c) 2013 Adam Roben <adam@roben.org>. 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_MAC_MAIN_APPLICATION_BUNDLE_H_
|
||||
#define ATOM_COMMON_MAC_MAIN_APPLICATION_BUNDLE_H_
|
||||
|
||||
@class NSBundle;
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
// The "main" application bundle is the outermost bundle for this logical
|
||||
// application. E.g., if you have MyApp.app and
|
||||
// MyApp.app/Contents/Frameworks/MyApp Helper.app, the main application bundle
|
||||
// is MyApp.app, no matter which executable is currently running.
|
||||
NSBundle* MainApplicationBundle();
|
||||
base::FilePath MainApplicationBundlePath();
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_MAC_MAIN_APPLICATION_BUNDLE_H_
|
56
shell/common/mac/main_application_bundle.mm
Normal file
56
shell/common/mac/main_application_bundle.mm
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE-CHROMIUM file.
|
||||
|
||||
#import "atom/common/mac/main_application_bundle.h"
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/mac/bundle_locations.h"
|
||||
#include "base/mac/foundation_util.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/string_util.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
bool HasMainProcessKey() {
|
||||
NSDictionary* info_dictionary = [base::mac::MainBundle() infoDictionary];
|
||||
return
|
||||
[[info_dictionary objectForKey:@"ElectronMainProcess"] boolValue] != NO;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
base::FilePath MainApplicationBundlePath() {
|
||||
// Start out with the path to the running executable.
|
||||
base::FilePath path;
|
||||
base::PathService::Get(base::FILE_EXE, &path);
|
||||
|
||||
// Up to Contents.
|
||||
if (!HasMainProcessKey() &&
|
||||
base::EndsWith(path.value(), " Helper", base::CompareCase::SENSITIVE)) {
|
||||
// The running executable is the helper. Go up five steps:
|
||||
// Contents/Frameworks/Helper.app/Contents/MacOS/Helper
|
||||
// ^ to here ^ from here
|
||||
path = path.DirName().DirName().DirName().DirName().DirName();
|
||||
} else {
|
||||
// One step up to MacOS, another to Contents.
|
||||
path = path.DirName().DirName();
|
||||
}
|
||||
DCHECK_EQ(path.BaseName().value(), "Contents");
|
||||
|
||||
// Up one more level to the .app.
|
||||
path = path.DirName();
|
||||
DCHECK_EQ(path.BaseName().Extension(), ".app");
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
NSBundle* MainApplicationBundle() {
|
||||
return [NSBundle bundleWithPath:base::mac::FilePathToNSString(
|
||||
MainApplicationBundlePath())];
|
||||
}
|
||||
|
||||
} // namespace atom
|
107
shell/common/mouse_util.cc
Normal file
107
shell/common/mouse_util.cc
Normal file
|
@ -0,0 +1,107 @@
|
|||
// 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/mouse_util.h"
|
||||
#include <string>
|
||||
|
||||
using Cursor = blink::WebCursorInfo::Type;
|
||||
|
||||
namespace atom {
|
||||
|
||||
std::string CursorTypeToString(const content::CursorInfo& info) {
|
||||
switch (info.type) {
|
||||
case Cursor::kTypePointer:
|
||||
return "default";
|
||||
case Cursor::kTypeCross:
|
||||
return "crosshair";
|
||||
case Cursor::kTypeHand:
|
||||
return "pointer";
|
||||
case Cursor::kTypeIBeam:
|
||||
return "text";
|
||||
case Cursor::kTypeWait:
|
||||
return "wait";
|
||||
case Cursor::kTypeHelp:
|
||||
return "help";
|
||||
case Cursor::kTypeEastResize:
|
||||
return "e-resize";
|
||||
case Cursor::kTypeNorthResize:
|
||||
return "n-resize";
|
||||
case Cursor::kTypeNorthEastResize:
|
||||
return "ne-resize";
|
||||
case Cursor::kTypeNorthWestResize:
|
||||
return "nw-resize";
|
||||
case Cursor::kTypeSouthResize:
|
||||
return "s-resize";
|
||||
case Cursor::kTypeSouthEastResize:
|
||||
return "se-resize";
|
||||
case Cursor::kTypeSouthWestResize:
|
||||
return "sw-resize";
|
||||
case Cursor::kTypeWestResize:
|
||||
return "w-resize";
|
||||
case Cursor::kTypeNorthSouthResize:
|
||||
return "ns-resize";
|
||||
case Cursor::kTypeEastWestResize:
|
||||
return "ew-resize";
|
||||
case Cursor::kTypeNorthEastSouthWestResize:
|
||||
return "nesw-resize";
|
||||
case Cursor::kTypeNorthWestSouthEastResize:
|
||||
return "nwse-resize";
|
||||
case Cursor::kTypeColumnResize:
|
||||
return "col-resize";
|
||||
case Cursor::kTypeRowResize:
|
||||
return "row-resize";
|
||||
case Cursor::kTypeMiddlePanning:
|
||||
return "m-panning";
|
||||
case Cursor::kTypeEastPanning:
|
||||
return "e-panning";
|
||||
case Cursor::kTypeNorthPanning:
|
||||
return "n-panning";
|
||||
case Cursor::kTypeNorthEastPanning:
|
||||
return "ne-panning";
|
||||
case Cursor::kTypeNorthWestPanning:
|
||||
return "nw-panning";
|
||||
case Cursor::kTypeSouthPanning:
|
||||
return "s-panning";
|
||||
case Cursor::kTypeSouthEastPanning:
|
||||
return "se-panning";
|
||||
case Cursor::kTypeSouthWestPanning:
|
||||
return "sw-panning";
|
||||
case Cursor::kTypeWestPanning:
|
||||
return "w-panning";
|
||||
case Cursor::kTypeMove:
|
||||
return "move";
|
||||
case Cursor::kTypeVerticalText:
|
||||
return "vertical-text";
|
||||
case Cursor::kTypeCell:
|
||||
return "cell";
|
||||
case Cursor::kTypeContextMenu:
|
||||
return "context-menu";
|
||||
case Cursor::kTypeAlias:
|
||||
return "alias";
|
||||
case Cursor::kTypeProgress:
|
||||
return "progress";
|
||||
case Cursor::kTypeNoDrop:
|
||||
return "nodrop";
|
||||
case Cursor::kTypeCopy:
|
||||
return "copy";
|
||||
case Cursor::kTypeNone:
|
||||
return "none";
|
||||
case Cursor::kTypeNotAllowed:
|
||||
return "not-allowed";
|
||||
case Cursor::kTypeZoomIn:
|
||||
return "zoom-in";
|
||||
case Cursor::kTypeZoomOut:
|
||||
return "zoom-out";
|
||||
case Cursor::kTypeGrab:
|
||||
return "grab";
|
||||
case Cursor::kTypeGrabbing:
|
||||
return "grabbing";
|
||||
case Cursor::kTypeCustom:
|
||||
return "custom";
|
||||
default:
|
||||
return "default";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
34
shell/common/mouse_util.h
Normal file
34
shell/common/mouse_util.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
// 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_MOUSE_UTIL_H_
|
||||
#define ATOM_COMMON_MOUSE_UTIL_H_
|
||||
|
||||
#include <string>
|
||||
#include "content/common/cursors/webcursor.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
|
||||
// IPC macros similar to the already existing ones in the chromium source.
|
||||
// We need these to listen to the cursor change IPC message while still
|
||||
// letting chromium handle the actual cursor change by setting handled = false.
|
||||
#define IPC_MESSAGE_HANDLER_CODE(msg_class, member_func, code) \
|
||||
IPC_MESSAGE_FORWARD_CODE(msg_class, this, \
|
||||
_IpcMessageHandlerClass::member_func, code)
|
||||
|
||||
#define IPC_MESSAGE_FORWARD_CODE(msg_class, obj, member_func, code) \
|
||||
case msg_class::ID: { \
|
||||
if (!msg_class::Dispatch(&ipc_message__, obj, this, param__, \
|
||||
&member_func)) \
|
||||
ipc_message__.set_dispatch_error(); \
|
||||
code; \
|
||||
} break;
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Returns the cursor's type as a string.
|
||||
std::string CursorTypeToString(const content::CursorInfo& info);
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_MOUSE_UTIL_H_
|
23
shell/common/native_mate_converters/accelerator_converter.cc
Normal file
23
shell/common/native_mate_converters/accelerator_converter.cc
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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 "atom/common/native_mate_converters/accelerator_converter.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
// static
|
||||
bool Converter<ui::Accelerator>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
ui::Accelerator* out) {
|
||||
std::string keycode;
|
||||
if (!ConvertFromV8(isolate, val, &keycode))
|
||||
return false;
|
||||
return accelerator_util::StringToAccelerator(keycode, out);
|
||||
}
|
||||
|
||||
} // namespace mate
|
25
shell/common/native_mate_converters/accelerator_converter.h
Normal file
25
shell/common/native_mate_converters/accelerator_converter.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_ACCELERATOR_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_ACCELERATOR_CONVERTER_H_
|
||||
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace ui {
|
||||
class Accelerator;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<ui::Accelerator> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
ui::Accelerator* out);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_ACCELERATOR_CONVERTER_H_
|
530
shell/common/native_mate_converters/blink_converter.cc
Normal file
530
shell/common/native_mate_converters/blink_converter.cc
Normal file
|
@ -0,0 +1,530 @@
|
|||
// 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/native_mate_converters/blink_converter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/keyboard_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "gin/converter.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "third_party/blink/public/platform/web_input_event.h"
|
||||
#include "third_party/blink/public/platform/web_mouse_event.h"
|
||||
#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
|
||||
#include "third_party/blink/public/web/web_device_emulation_params.h"
|
||||
#include "ui/base/clipboard/clipboard.h"
|
||||
#include "ui/events/keycodes/dom/keycode_converter.h"
|
||||
#include "ui/events/keycodes/keyboard_code_conversion.h"
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
int VectorToBitArray(const std::vector<T>& vec) {
|
||||
int bits = 0;
|
||||
for (const T& item : vec)
|
||||
bits |= item;
|
||||
return bits;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<base::char16> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
base::char16* out) {
|
||||
base::string16 code = base::UTF8ToUTF16(gin::V8ToString(isolate, val));
|
||||
if (code.length() != 1)
|
||||
return false;
|
||||
*out = code[0];
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebInputEvent::Type> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
blink::WebInputEvent::Type* out) {
|
||||
std::string type = base::ToLowerASCII(gin::V8ToString(isolate, val));
|
||||
if (type == "mousedown")
|
||||
*out = blink::WebInputEvent::kMouseDown;
|
||||
else if (type == "mouseup")
|
||||
*out = blink::WebInputEvent::kMouseUp;
|
||||
else if (type == "mousemove")
|
||||
*out = blink::WebInputEvent::kMouseMove;
|
||||
else if (type == "mouseenter")
|
||||
*out = blink::WebInputEvent::kMouseEnter;
|
||||
else if (type == "mouseleave")
|
||||
*out = blink::WebInputEvent::kMouseLeave;
|
||||
else if (type == "contextmenu")
|
||||
*out = blink::WebInputEvent::kContextMenu;
|
||||
else if (type == "mousewheel")
|
||||
*out = blink::WebInputEvent::kMouseWheel;
|
||||
else if (type == "keydown")
|
||||
*out = blink::WebInputEvent::kRawKeyDown;
|
||||
else if (type == "keyup")
|
||||
*out = blink::WebInputEvent::kKeyUp;
|
||||
else if (type == "char")
|
||||
*out = blink::WebInputEvent::kChar;
|
||||
else if (type == "touchstart")
|
||||
*out = blink::WebInputEvent::kTouchStart;
|
||||
else if (type == "touchmove")
|
||||
*out = blink::WebInputEvent::kTouchMove;
|
||||
else if (type == "touchend")
|
||||
*out = blink::WebInputEvent::kTouchEnd;
|
||||
else if (type == "touchcancel")
|
||||
*out = blink::WebInputEvent::kTouchCancel;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebMouseEvent::Button> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
blink::WebMouseEvent::Button* out) {
|
||||
std::string button = base::ToLowerASCII(gin::V8ToString(isolate, val));
|
||||
if (button == "left")
|
||||
*out = blink::WebMouseEvent::Button::kLeft;
|
||||
else if (button == "middle")
|
||||
*out = blink::WebMouseEvent::Button::kMiddle;
|
||||
else if (button == "right")
|
||||
*out = blink::WebMouseEvent::Button::kRight;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebInputEvent::Modifiers> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
blink::WebInputEvent::Modifiers* out) {
|
||||
std::string modifier = base::ToLowerASCII(gin::V8ToString(isolate, val));
|
||||
if (modifier == "shift")
|
||||
*out = blink::WebInputEvent::kShiftKey;
|
||||
else if (modifier == "control" || modifier == "ctrl")
|
||||
*out = blink::WebInputEvent::kControlKey;
|
||||
else if (modifier == "alt")
|
||||
*out = blink::WebInputEvent::kAltKey;
|
||||
else if (modifier == "meta" || modifier == "command" || modifier == "cmd")
|
||||
*out = blink::WebInputEvent::kMetaKey;
|
||||
else if (modifier == "iskeypad")
|
||||
*out = blink::WebInputEvent::kIsKeyPad;
|
||||
else if (modifier == "isautorepeat")
|
||||
*out = blink::WebInputEvent::kIsAutoRepeat;
|
||||
else if (modifier == "leftbuttondown")
|
||||
*out = blink::WebInputEvent::kLeftButtonDown;
|
||||
else if (modifier == "middlebuttondown")
|
||||
*out = blink::WebInputEvent::kMiddleButtonDown;
|
||||
else if (modifier == "rightbuttondown")
|
||||
*out = blink::WebInputEvent::kRightButtonDown;
|
||||
else if (modifier == "capslock")
|
||||
*out = blink::WebInputEvent::kCapsLockOn;
|
||||
else if (modifier == "numlock")
|
||||
*out = blink::WebInputEvent::kNumLockOn;
|
||||
else if (modifier == "left")
|
||||
*out = blink::WebInputEvent::kIsLeft;
|
||||
else if (modifier == "right")
|
||||
*out = blink::WebInputEvent::kIsRight;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
blink::WebInputEvent::Type GetWebInputEventType(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val) {
|
||||
blink::WebInputEvent::Type type = blink::WebInputEvent::kUndefined;
|
||||
mate::Dictionary dict;
|
||||
ConvertFromV8(isolate, val, &dict) && dict.Get("type", &type);
|
||||
return type;
|
||||
}
|
||||
|
||||
bool Converter<blink::WebInputEvent>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebInputEvent* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
blink::WebInputEvent::Type type;
|
||||
if (!dict.Get("type", &type))
|
||||
return false;
|
||||
out->SetType(type);
|
||||
std::vector<blink::WebInputEvent::Modifiers> modifiers;
|
||||
if (dict.Get("modifiers", &modifiers))
|
||||
out->SetModifiers(VectorToBitArray(modifiers));
|
||||
out->SetTimeStamp(base::TimeTicks::Now());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter<blink::WebKeyboardEvent>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebKeyboardEvent* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
if (!ConvertFromV8(isolate, val, static_cast<blink::WebInputEvent*>(out)))
|
||||
return false;
|
||||
|
||||
std::string str;
|
||||
if (!dict.Get("keyCode", &str))
|
||||
return false;
|
||||
|
||||
bool shifted = false;
|
||||
ui::KeyboardCode keyCode = atom::KeyboardCodeFromStr(str, &shifted);
|
||||
out->windows_key_code = keyCode;
|
||||
if (shifted)
|
||||
out->SetModifiers(out->GetModifiers() | blink::WebInputEvent::kShiftKey);
|
||||
|
||||
ui::DomCode domCode = ui::UsLayoutKeyboardCodeToDomCode(keyCode);
|
||||
out->dom_code = static_cast<int>(domCode);
|
||||
|
||||
ui::DomKey domKey;
|
||||
ui::KeyboardCode dummy_code;
|
||||
int flags = atom::WebEventModifiersToEventFlags(out->GetModifiers());
|
||||
if (ui::DomCodeToUsLayoutDomKey(domCode, flags, &domKey, &dummy_code))
|
||||
out->dom_key = static_cast<int>(domKey);
|
||||
|
||||
if ((out->GetType() == blink::WebInputEvent::kChar ||
|
||||
out->GetType() == blink::WebInputEvent::kRawKeyDown)) {
|
||||
// Make sure to not read beyond the buffer in case some bad code doesn't
|
||||
// NULL-terminate it (this is called from plugins).
|
||||
size_t text_length_cap = blink::WebKeyboardEvent::kTextLengthCap;
|
||||
base::string16 text16 = base::UTF8ToUTF16(str);
|
||||
|
||||
memset(out->text, 0, text_length_cap);
|
||||
memset(out->unmodified_text, 0, text_length_cap);
|
||||
for (size_t i = 0; i < std::min(text_length_cap, text16.size()); ++i) {
|
||||
out->text[i] = text16[i];
|
||||
out->unmodified_text[i] = text16[i];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter<content::NativeWebKeyboardEvent>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::NativeWebKeyboardEvent* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
if (!ConvertFromV8(isolate, val, static_cast<blink::WebKeyboardEvent*>(out)))
|
||||
return false;
|
||||
dict.Get("skipInBrowser", &out->skip_in_browser);
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Converter<content::NativeWebKeyboardEvent>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const content::NativeWebKeyboardEvent& in) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
|
||||
if (in.GetType() == blink::WebInputEvent::Type::kRawKeyDown)
|
||||
dict.Set("type", "keyDown");
|
||||
else if (in.GetType() == blink::WebInputEvent::Type::kKeyUp)
|
||||
dict.Set("type", "keyUp");
|
||||
dict.Set("key", ui::KeycodeConverter::DomKeyToKeyString(in.dom_key));
|
||||
dict.Set("code", ui::KeycodeConverter::DomCodeToCodeString(
|
||||
static_cast<ui::DomCode>(in.dom_code)));
|
||||
|
||||
using Modifiers = blink::WebInputEvent::Modifiers;
|
||||
dict.Set("isAutoRepeat", (in.GetModifiers() & Modifiers::kIsAutoRepeat) != 0);
|
||||
dict.Set("shift", (in.GetModifiers() & Modifiers::kShiftKey) != 0);
|
||||
dict.Set("control", (in.GetModifiers() & Modifiers::kControlKey) != 0);
|
||||
dict.Set("alt", (in.GetModifiers() & Modifiers::kAltKey) != 0);
|
||||
dict.Set("meta", (in.GetModifiers() & Modifiers::kMetaKey) != 0);
|
||||
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
bool Converter<blink::WebMouseEvent>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebMouseEvent* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
if (!ConvertFromV8(isolate, val, static_cast<blink::WebInputEvent*>(out)))
|
||||
return false;
|
||||
|
||||
float x = 0.f;
|
||||
float y = 0.f;
|
||||
if (!dict.Get("x", &x) || !dict.Get("y", &y))
|
||||
return false;
|
||||
out->SetPositionInWidget(x, y);
|
||||
|
||||
if (!dict.Get("button", &out->button))
|
||||
out->button = blink::WebMouseEvent::Button::kLeft;
|
||||
|
||||
float global_x = 0.f;
|
||||
float global_y = 0.f;
|
||||
dict.Get("globalX", &global_x);
|
||||
dict.Get("globalY", &global_y);
|
||||
out->SetPositionInScreen(global_x, global_y);
|
||||
|
||||
dict.Get("movementX", &out->movement_x);
|
||||
dict.Get("movementY", &out->movement_y);
|
||||
dict.Get("clickCount", &out->click_count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter<blink::WebMouseWheelEvent>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebMouseWheelEvent* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
if (!ConvertFromV8(isolate, val, static_cast<blink::WebMouseEvent*>(out)))
|
||||
return false;
|
||||
dict.Get("deltaX", &out->delta_x);
|
||||
dict.Get("deltaY", &out->delta_y);
|
||||
dict.Get("wheelTicksX", &out->wheel_ticks_x);
|
||||
dict.Get("wheelTicksY", &out->wheel_ticks_y);
|
||||
dict.Get("accelerationRatioX", &out->acceleration_ratio_x);
|
||||
dict.Get("accelerationRatioY", &out->acceleration_ratio_y);
|
||||
dict.Get("hasPreciseScrollingDeltas", &out->has_precise_scrolling_deltas);
|
||||
|
||||
#if defined(USE_AURA)
|
||||
// Matches the behavior of ui/events/blink/web_input_event_traits.cc:
|
||||
bool can_scroll = true;
|
||||
if (dict.Get("canScroll", &can_scroll) && !can_scroll) {
|
||||
out->has_precise_scrolling_deltas = false;
|
||||
out->SetModifiers(out->GetModifiers() & ~blink::WebInputEvent::kControlKey);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter<blink::WebFloatPoint>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebFloatPoint* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
return dict.Get("x", &out->x) && dict.Get("y", &out->y);
|
||||
}
|
||||
|
||||
template <>
|
||||
struct Converter<base::Optional<blink::WebPoint>> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::Optional<blink::WebPoint>* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
blink::WebPoint point;
|
||||
bool success = dict.Get("x", &point.x) && dict.Get("y", &point.y);
|
||||
if (!success)
|
||||
return false;
|
||||
out->emplace(point);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bool Converter<blink::WebSize>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebSize* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
return dict.Get("width", &out->width) && dict.Get("height", &out->height);
|
||||
}
|
||||
|
||||
bool Converter<blink::WebDeviceEmulationParams>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebDeviceEmulationParams* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
|
||||
std::string screen_position;
|
||||
if (dict.Get("screenPosition", &screen_position)) {
|
||||
screen_position = base::ToLowerASCII(screen_position);
|
||||
if (screen_position == "mobile")
|
||||
out->screen_position = blink::WebDeviceEmulationParams::kMobile;
|
||||
else if (screen_position == "desktop")
|
||||
out->screen_position = blink::WebDeviceEmulationParams::kDesktop;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
dict.Get("screenSize", &out->screen_size);
|
||||
dict.Get("viewPosition", &out->view_position);
|
||||
dict.Get("deviceScaleFactor", &out->device_scale_factor);
|
||||
dict.Get("viewSize", &out->view_size);
|
||||
dict.Get("scale", &out->scale);
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<blink::WebContextMenuData::MediaType>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::WebContextMenuData::MediaType& in) {
|
||||
switch (in) {
|
||||
case blink::WebContextMenuData::kMediaTypeImage:
|
||||
return mate::StringToV8(isolate, "image");
|
||||
case blink::WebContextMenuData::kMediaTypeVideo:
|
||||
return mate::StringToV8(isolate, "video");
|
||||
case blink::WebContextMenuData::kMediaTypeAudio:
|
||||
return mate::StringToV8(isolate, "audio");
|
||||
case blink::WebContextMenuData::kMediaTypeCanvas:
|
||||
return mate::StringToV8(isolate, "canvas");
|
||||
case blink::WebContextMenuData::kMediaTypeFile:
|
||||
return mate::StringToV8(isolate, "file");
|
||||
case blink::WebContextMenuData::kMediaTypePlugin:
|
||||
return mate::StringToV8(isolate, "plugin");
|
||||
default:
|
||||
return mate::StringToV8(isolate, "none");
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<blink::WebContextMenuData::InputFieldType>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::WebContextMenuData::InputFieldType& in) {
|
||||
switch (in) {
|
||||
case blink::WebContextMenuData::kInputFieldTypePlainText:
|
||||
return mate::StringToV8(isolate, "plainText");
|
||||
case blink::WebContextMenuData::kInputFieldTypePassword:
|
||||
return mate::StringToV8(isolate, "password");
|
||||
case blink::WebContextMenuData::kInputFieldTypeOther:
|
||||
return mate::StringToV8(isolate, "other");
|
||||
default:
|
||||
return mate::StringToV8(isolate, "none");
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> EditFlagsToV8(v8::Isolate* isolate, int editFlags) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("canUndo", !!(editFlags & blink::WebContextMenuData::kCanUndo));
|
||||
dict.Set("canRedo", !!(editFlags & blink::WebContextMenuData::kCanRedo));
|
||||
dict.Set("canCut", !!(editFlags & blink::WebContextMenuData::kCanCut));
|
||||
dict.Set("canCopy", !!(editFlags & blink::WebContextMenuData::kCanCopy));
|
||||
|
||||
bool pasteFlag = false;
|
||||
if (editFlags & blink::WebContextMenuData::kCanPaste) {
|
||||
std::vector<base::string16> types;
|
||||
bool ignore;
|
||||
ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
|
||||
ui::CLIPBOARD_TYPE_COPY_PASTE, &types, &ignore);
|
||||
pasteFlag = !types.empty();
|
||||
}
|
||||
dict.Set("canPaste", pasteFlag);
|
||||
|
||||
dict.Set("canDelete", !!(editFlags & blink::WebContextMenuData::kCanDelete));
|
||||
dict.Set("canSelectAll",
|
||||
!!(editFlags & blink::WebContextMenuData::kCanSelectAll));
|
||||
|
||||
return mate::ConvertToV8(isolate, dict);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> MediaFlagsToV8(v8::Isolate* isolate, int mediaFlags) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("inError",
|
||||
!!(mediaFlags & blink::WebContextMenuData::kMediaInError));
|
||||
dict.Set("isPaused",
|
||||
!!(mediaFlags & blink::WebContextMenuData::kMediaPaused));
|
||||
dict.Set("isMuted", !!(mediaFlags & blink::WebContextMenuData::kMediaMuted));
|
||||
dict.Set("hasAudio",
|
||||
!!(mediaFlags & blink::WebContextMenuData::kMediaHasAudio));
|
||||
dict.Set("isLooping",
|
||||
(mediaFlags & blink::WebContextMenuData::kMediaLoop) != 0);
|
||||
dict.Set("isControlsVisible",
|
||||
(mediaFlags & blink::WebContextMenuData::kMediaControls) != 0);
|
||||
dict.Set("canToggleControls",
|
||||
!!(mediaFlags & blink::WebContextMenuData::kMediaCanToggleControls));
|
||||
dict.Set("canRotate",
|
||||
!!(mediaFlags & blink::WebContextMenuData::kMediaCanRotate));
|
||||
return mate::ConvertToV8(isolate, dict);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Converter<blink::WebCache::ResourceTypeStat>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::WebCache::ResourceTypeStat& stat) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("count", static_cast<uint32_t>(stat.count));
|
||||
dict.Set("size", static_cast<double>(stat.size));
|
||||
dict.Set("liveSize", static_cast<double>(stat.decoded_size));
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Converter<blink::WebCache::ResourceTypeStats>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::WebCache::ResourceTypeStats& stats) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("images", stats.images);
|
||||
dict.Set("scripts", stats.scripts);
|
||||
dict.Set("cssStyleSheets", stats.css_style_sheets);
|
||||
dict.Set("xslStyleSheets", stats.xsl_style_sheets);
|
||||
dict.Set("fonts", stats.fonts);
|
||||
dict.Set("other", stats.other);
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<network::mojom::ReferrerPolicy>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const network::mojom::ReferrerPolicy& in) {
|
||||
switch (in) {
|
||||
case network::mojom::ReferrerPolicy::kDefault:
|
||||
return mate::StringToV8(isolate, "default");
|
||||
case network::mojom::ReferrerPolicy::kAlways:
|
||||
return mate::StringToV8(isolate, "unsafe-url");
|
||||
case network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade:
|
||||
return mate::StringToV8(isolate, "no-referrer-when-downgrade");
|
||||
case network::mojom::ReferrerPolicy::kNever:
|
||||
return mate::StringToV8(isolate, "no-referrer");
|
||||
case network::mojom::ReferrerPolicy::kOrigin:
|
||||
return mate::StringToV8(isolate, "origin");
|
||||
case network::mojom::ReferrerPolicy::
|
||||
kNoReferrerWhenDowngradeOriginWhenCrossOrigin:
|
||||
return mate::StringToV8(isolate, "strict-origin-when-cross-origin");
|
||||
case network::mojom::ReferrerPolicy::kSameOrigin:
|
||||
return mate::StringToV8(isolate, "same-origin");
|
||||
case network::mojom::ReferrerPolicy::kStrictOrigin:
|
||||
return mate::StringToV8(isolate, "strict-origin");
|
||||
default:
|
||||
return mate::StringToV8(isolate, "no-referrer");
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool Converter<network::mojom::ReferrerPolicy>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
network::mojom::ReferrerPolicy* out) {
|
||||
std::string policy = base::ToLowerASCII(gin::V8ToString(isolate, val));
|
||||
if (policy == "default")
|
||||
*out = network::mojom::ReferrerPolicy::kDefault;
|
||||
else if (policy == "unsafe-url")
|
||||
*out = network::mojom::ReferrerPolicy::kAlways;
|
||||
else if (policy == "no-referrer-when-downgrade")
|
||||
*out = network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade;
|
||||
else if (policy == "no-referrer")
|
||||
*out = network::mojom::ReferrerPolicy::kNever;
|
||||
else if (policy == "origin")
|
||||
*out = network::mojom::ReferrerPolicy::kOrigin;
|
||||
else if (policy == "strict-origin-when-cross-origin")
|
||||
*out = network::mojom::ReferrerPolicy::
|
||||
kNoReferrerWhenDowngradeOriginWhenCrossOrigin;
|
||||
else if (policy == "same-origin")
|
||||
*out = network::mojom::ReferrerPolicy::kSameOrigin;
|
||||
else if (policy == "strict-origin")
|
||||
*out = network::mojom::ReferrerPolicy::kStrictOrigin;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mate
|
139
shell/common/native_mate_converters/blink_converter.h
Normal file
139
shell/common/native_mate_converters/blink_converter.h
Normal file
|
@ -0,0 +1,139 @@
|
|||
// 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_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_
|
||||
|
||||
#include "native_mate/converter.h"
|
||||
#include "third_party/blink/public/platform/web_cache.h"
|
||||
#include "third_party/blink/public/platform/web_input_event.h"
|
||||
#include "third_party/blink/public/web/web_context_menu_data.h"
|
||||
|
||||
namespace blink {
|
||||
class WebMouseEvent;
|
||||
class WebMouseWheelEvent;
|
||||
class WebKeyboardEvent;
|
||||
struct WebDeviceEmulationParams;
|
||||
struct WebFloatPoint;
|
||||
struct WebPoint;
|
||||
struct WebSize;
|
||||
} // namespace blink
|
||||
|
||||
namespace content {
|
||||
struct NativeWebKeyboardEvent;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
|
||||
blink::WebInputEvent::Type GetWebInputEventType(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val);
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebInputEvent> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebInputEvent* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebKeyboardEvent> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebKeyboardEvent* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<content::NativeWebKeyboardEvent> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::NativeWebKeyboardEvent* out);
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const content::NativeWebKeyboardEvent& in);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebMouseEvent> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebMouseEvent* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebMouseWheelEvent> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebMouseWheelEvent* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebFloatPoint> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebFloatPoint* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebPoint> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebPoint* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebSize> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebSize* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebDeviceEmulationParams> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::WebDeviceEmulationParams* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebContextMenuData::MediaType> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::WebContextMenuData::MediaType& in);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebContextMenuData::InputFieldType> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::WebContextMenuData::InputFieldType& in);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebCache::ResourceTypeStat> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::WebCache::ResourceTypeStat& stat);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::WebCache::ResourceTypeStats> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::WebCache::ResourceTypeStats& stats);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<network::mojom::ReferrerPolicy> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const network::mojom::ReferrerPolicy& in);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
network::mojom::ReferrerPolicy* out);
|
||||
};
|
||||
|
||||
v8::Local<v8::Value> EditFlagsToV8(v8::Isolate* isolate, int editFlags);
|
||||
v8::Local<v8::Value> MediaFlagsToV8(v8::Isolate* isolate, int mediaFlags);
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_
|
163
shell/common/native_mate_converters/callback.cc
Normal file
163
shell/common/native_mate_converters/callback.cc
Normal file
|
@ -0,0 +1,163 @@
|
|||
// Copyright (c) 2015 GitHub, Inc. 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/native_mate_converters/callback.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
struct TranslaterHolder {
|
||||
explicit TranslaterHolder(v8::Isolate* isolate)
|
||||
: handle(isolate, v8::External::New(isolate, this)) {
|
||||
handle.SetWeak(this, &GC, v8::WeakCallbackType::kFinalizer);
|
||||
}
|
||||
~TranslaterHolder() {
|
||||
if (!handle.IsEmpty()) {
|
||||
handle.ClearWeak();
|
||||
handle.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
static void GC(const v8::WeakCallbackInfo<TranslaterHolder>& data) {
|
||||
delete data.GetParameter();
|
||||
}
|
||||
|
||||
v8::Global<v8::External> handle;
|
||||
Translater translater;
|
||||
};
|
||||
|
||||
// Cached JavaScript version of |CallTranslater|.
|
||||
v8::Persistent<v8::FunctionTemplate> g_call_translater;
|
||||
|
||||
void CallTranslater(v8::Local<v8::External> external,
|
||||
v8::Local<v8::Object> state,
|
||||
mate::Arguments* args) {
|
||||
// Whether the callback should only be called for once.
|
||||
v8::Isolate* isolate = args->isolate();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
bool one_time =
|
||||
state->Has(context, mate::StringToSymbol(isolate, "oneTime")).ToChecked();
|
||||
|
||||
// Check if the callback has already been called.
|
||||
if (one_time) {
|
||||
auto called_symbol = mate::StringToSymbol(isolate, "called");
|
||||
if (state->Has(context, called_symbol).ToChecked()) {
|
||||
args->ThrowError("callback can only be called for once");
|
||||
return;
|
||||
} else {
|
||||
state->Set(context, called_symbol, v8::Boolean::New(isolate, true))
|
||||
.ToChecked();
|
||||
}
|
||||
}
|
||||
|
||||
TranslaterHolder* holder = static_cast<TranslaterHolder*>(external->Value());
|
||||
holder->translater.Run(args);
|
||||
|
||||
// Free immediately for one-time callback.
|
||||
if (one_time)
|
||||
delete holder;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Destroy the class on UI thread when possible.
|
||||
struct DeleteOnUIThread {
|
||||
template <typename T>
|
||||
static void Destruct(const T* x) {
|
||||
if (Locker::IsBrowserProcess() &&
|
||||
!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
|
||||
BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, x);
|
||||
} else {
|
||||
delete x;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Like v8::Global, but ref-counted.
|
||||
template <typename T>
|
||||
class RefCountedGlobal
|
||||
: public base::RefCountedThreadSafe<RefCountedGlobal<T>, DeleteOnUIThread> {
|
||||
public:
|
||||
RefCountedGlobal(v8::Isolate* isolate, v8::Local<v8::Value> value)
|
||||
: handle_(isolate, v8::Local<T>::Cast(value)) {}
|
||||
|
||||
bool IsAlive() const { return !handle_.IsEmpty(); }
|
||||
|
||||
v8::Local<T> NewHandle(v8::Isolate* isolate) const {
|
||||
return v8::Local<T>::New(isolate, handle_);
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Global<T> handle_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RefCountedGlobal);
|
||||
};
|
||||
|
||||
SafeV8Function::SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value)
|
||||
: v8_function_(new RefCountedGlobal<v8::Function>(isolate, value)) {}
|
||||
|
||||
SafeV8Function::SafeV8Function(const SafeV8Function& other)
|
||||
: v8_function_(other.v8_function_) {}
|
||||
|
||||
SafeV8Function::~SafeV8Function() {}
|
||||
|
||||
bool SafeV8Function::IsAlive() const {
|
||||
return v8_function_.get() && v8_function_->IsAlive();
|
||||
}
|
||||
|
||||
v8::Local<v8::Function> SafeV8Function::NewHandle(v8::Isolate* isolate) const {
|
||||
return v8_function_->NewHandle(isolate);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> CreateFunctionFromTranslater(v8::Isolate* isolate,
|
||||
const Translater& translater,
|
||||
bool one_time) {
|
||||
// The FunctionTemplate is cached.
|
||||
if (g_call_translater.IsEmpty())
|
||||
g_call_translater.Reset(isolate,
|
||||
mate::CreateFunctionTemplate(
|
||||
isolate, base::BindRepeating(&CallTranslater)));
|
||||
|
||||
v8::Local<v8::FunctionTemplate> call_translater =
|
||||
v8::Local<v8::FunctionTemplate>::New(isolate, g_call_translater);
|
||||
auto* holder = new TranslaterHolder(isolate);
|
||||
holder->translater = translater;
|
||||
Dictionary state = mate::Dictionary::CreateEmpty(isolate);
|
||||
if (one_time)
|
||||
state.Set("oneTime", true);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
return BindFunctionWith(
|
||||
isolate, context, call_translater->GetFunction(context).ToLocalChecked(),
|
||||
holder->handle.Get(isolate), state.GetHandle());
|
||||
}
|
||||
|
||||
// func.bind(func, arg1).
|
||||
// NB(zcbenz): Using C++11 version crashes VS.
|
||||
v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
|
||||
v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Function> func,
|
||||
v8::Local<v8::Value> arg1,
|
||||
v8::Local<v8::Value> arg2) {
|
||||
v8::MaybeLocal<v8::Value> bind =
|
||||
func->Get(context, mate::StringToV8(isolate, "bind"));
|
||||
CHECK(!bind.IsEmpty());
|
||||
v8::Local<v8::Function> bind_func =
|
||||
v8::Local<v8::Function>::Cast(bind.ToLocalChecked());
|
||||
v8::Local<v8::Value> converted[] = {func, arg1, arg2};
|
||||
return bind_func->Call(context, func, base::size(converted), converted)
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mate
|
181
shell/common/native_mate_converters/callback.h
Normal file
181
shell/common/native_mate_converters/callback.h
Normal file
|
@ -0,0 +1,181 @@
|
|||
// Copyright (c) 2015 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/api/locker.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "native_mate/function_template.h"
|
||||
#include "native_mate/scoped_persistent.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
class RefCountedGlobal;
|
||||
|
||||
// Manages the V8 function with RAII.
|
||||
class SafeV8Function {
|
||||
public:
|
||||
SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value);
|
||||
SafeV8Function(const SafeV8Function& other);
|
||||
~SafeV8Function();
|
||||
|
||||
bool IsAlive() const;
|
||||
v8::Local<v8::Function> NewHandle(v8::Isolate* isolate) const;
|
||||
|
||||
private:
|
||||
scoped_refptr<RefCountedGlobal<v8::Function>> v8_function_;
|
||||
};
|
||||
|
||||
// Helper to invoke a V8 function with C++ parameters.
|
||||
template <typename Sig>
|
||||
struct V8FunctionInvoker {};
|
||||
|
||||
template <typename... ArgTypes>
|
||||
struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
|
||||
static v8::Local<v8::Value> Go(v8::Isolate* isolate,
|
||||
const SafeV8Function& function,
|
||||
ArgTypes... raw) {
|
||||
Locker locker(isolate);
|
||||
v8::EscapableHandleScope handle_scope(isolate);
|
||||
if (!function.IsAlive())
|
||||
return v8::Null(isolate);
|
||||
v8::MicrotasksScope script_scope(isolate,
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
v8::Local<v8::Function> holder = function.NewHandle(isolate);
|
||||
v8::Local<v8::Context> context = holder->CreationContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
std::vector<v8::Local<v8::Value>> args{
|
||||
ConvertToV8(isolate, std::forward<ArgTypes>(raw))...};
|
||||
v8::MaybeLocal<v8::Value> ret = holder->Call(
|
||||
context, holder, args.size(), args.empty() ? nullptr : &args.front());
|
||||
if (ret.IsEmpty())
|
||||
return v8::Undefined(isolate);
|
||||
else
|
||||
return handle_scope.Escape(ret.ToLocalChecked());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... ArgTypes>
|
||||
struct V8FunctionInvoker<void(ArgTypes...)> {
|
||||
static void Go(v8::Isolate* isolate,
|
||||
const SafeV8Function& function,
|
||||
ArgTypes... raw) {
|
||||
Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
if (!function.IsAlive())
|
||||
return;
|
||||
v8::MicrotasksScope script_scope(isolate,
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
v8::Local<v8::Function> holder = function.NewHandle(isolate);
|
||||
v8::Local<v8::Context> context = holder->CreationContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
std::vector<v8::Local<v8::Value>> args{
|
||||
ConvertToV8(isolate, std::forward<ArgTypes>(raw))...};
|
||||
holder
|
||||
->Call(context, holder, args.size(),
|
||||
args.empty() ? nullptr : &args.front())
|
||||
.IsEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
|
||||
static ReturnType Go(v8::Isolate* isolate,
|
||||
const SafeV8Function& function,
|
||||
ArgTypes... raw) {
|
||||
Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
ReturnType ret = ReturnType();
|
||||
if (!function.IsAlive())
|
||||
return ret;
|
||||
v8::MicrotasksScope script_scope(isolate,
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
v8::Local<v8::Function> holder = function.NewHandle(isolate);
|
||||
v8::Local<v8::Context> context = holder->CreationContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
std::vector<v8::Local<v8::Value>> args{
|
||||
ConvertToV8(isolate, std::forward<ArgTypes>(raw))...};
|
||||
v8::Local<v8::Value> result;
|
||||
auto maybe_result = holder->Call(context, holder, args.size(),
|
||||
args.empty() ? nullptr : &args.front());
|
||||
if (maybe_result.ToLocal(&result))
|
||||
Converter<ReturnType>::FromV8(isolate, result, &ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// Helper to pass a C++ funtion to JavaScript.
|
||||
using Translater = base::Callback<void(Arguments* args)>;
|
||||
v8::Local<v8::Value> CreateFunctionFromTranslater(v8::Isolate* isolate,
|
||||
const Translater& translater,
|
||||
bool one_time);
|
||||
v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
|
||||
v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Function> func,
|
||||
v8::Local<v8::Value> arg1,
|
||||
v8::Local<v8::Value> arg2);
|
||||
|
||||
// Calls callback with Arguments.
|
||||
template <typename Sig>
|
||||
struct NativeFunctionInvoker {};
|
||||
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
struct NativeFunctionInvoker<ReturnType(ArgTypes...)> {
|
||||
static void Go(base::Callback<ReturnType(ArgTypes...)> val, Arguments* args) {
|
||||
using Indices = typename IndicesGenerator<sizeof...(ArgTypes)>::type;
|
||||
Invoker<Indices, ArgTypes...> invoker(args, 0);
|
||||
if (invoker.IsOK())
|
||||
invoker.DispatchToCallback(val);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Sig>
|
||||
struct Converter<base::RepeatingCallback<Sig>> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const base::RepeatingCallback<Sig>& val) {
|
||||
// We don't use CreateFunctionTemplate here because it creates a new
|
||||
// FunctionTemplate everytime, which is cached by V8 and causes leaks.
|
||||
internal::Translater translater =
|
||||
base::Bind(&internal::NativeFunctionInvoker<Sig>::Go, val);
|
||||
// To avoid memory leak, we ensure that the callback can only be called
|
||||
// for once.
|
||||
return internal::CreateFunctionFromTranslater(isolate, translater, true);
|
||||
}
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::RepeatingCallback<Sig>* out) {
|
||||
if (!val->IsFunction())
|
||||
return false;
|
||||
|
||||
*out = base::BindRepeating(&internal::V8FunctionInvoker<Sig>::Go, isolate,
|
||||
internal::SafeV8Function(isolate, val));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Convert a callback to V8 without the call number limitation, this can easily
|
||||
// cause memory leaks so use it with caution.
|
||||
template <typename Sig>
|
||||
v8::Local<v8::Value> CallbackToV8(v8::Isolate* isolate,
|
||||
const base::Callback<Sig>& val) {
|
||||
internal::Translater translater =
|
||||
base::Bind(&internal::NativeFunctionInvoker<Sig>::Go, val);
|
||||
return internal::CreateFunctionFromTranslater(isolate, translater, false);
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_
|
251
shell/common/native_mate_converters/content_converter.cc
Normal file
251
shell/common/native_mate_converters/content_converter.cc
Normal file
|
@ -0,0 +1,251 @@
|
|||
// 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/native_mate_converters/content_converter.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/web_contents_permission_helper.h"
|
||||
#include "atom/common/native_mate_converters/blink_converter.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "atom/common/native_mate_converters/ui_base_types_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/context_menu_params.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void ExecuteCommand(content::WebContents* web_contents,
|
||||
int action,
|
||||
const content::CustomContextMenuContext& context) {
|
||||
web_contents->ExecuteCustomContextMenuCommand(action, context);
|
||||
}
|
||||
|
||||
// Forward declaration for nested recursive call.
|
||||
v8::Local<v8::Value> MenuToV8(v8::Isolate* isolate,
|
||||
content::WebContents* web_contents,
|
||||
const content::CustomContextMenuContext& context,
|
||||
const std::vector<content::MenuItem>& menu);
|
||||
|
||||
v8::Local<v8::Value> MenuItemToV8(
|
||||
v8::Isolate* isolate,
|
||||
content::WebContents* web_contents,
|
||||
const content::CustomContextMenuContext& context,
|
||||
const content::MenuItem& item) {
|
||||
mate::Dictionary v8_item = mate::Dictionary::CreateEmpty(isolate);
|
||||
switch (item.type) {
|
||||
case content::MenuItem::CHECKABLE_OPTION:
|
||||
case content::MenuItem::GROUP:
|
||||
v8_item.Set("checked", item.checked);
|
||||
FALLTHROUGH;
|
||||
case content::MenuItem::OPTION:
|
||||
case content::MenuItem::SUBMENU:
|
||||
v8_item.Set("label", item.label);
|
||||
v8_item.Set("enabled", item.enabled);
|
||||
FALLTHROUGH;
|
||||
default:
|
||||
v8_item.Set("type", item.type);
|
||||
}
|
||||
if (item.type == content::MenuItem::SUBMENU)
|
||||
v8_item.Set("submenu",
|
||||
MenuToV8(isolate, web_contents, context, item.submenu));
|
||||
else if (item.action > 0)
|
||||
v8_item.Set("click", base::BindRepeating(ExecuteCommand, web_contents,
|
||||
item.action, context));
|
||||
return v8_item.GetHandle();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> MenuToV8(v8::Isolate* isolate,
|
||||
content::WebContents* web_contents,
|
||||
const content::CustomContextMenuContext& context,
|
||||
const std::vector<content::MenuItem>& menu) {
|
||||
std::vector<v8::Local<v8::Value>> v8_menu;
|
||||
for (const auto& menu_item : menu)
|
||||
v8_menu.push_back(MenuItemToV8(isolate, web_contents, context, menu_item));
|
||||
return mate::ConvertToV8(isolate, v8_menu);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<content::MenuItem::Type>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const content::MenuItem::Type& val) {
|
||||
switch (val) {
|
||||
case content::MenuItem::CHECKABLE_OPTION:
|
||||
return StringToV8(isolate, "checkbox");
|
||||
case content::MenuItem::GROUP:
|
||||
return StringToV8(isolate, "radio");
|
||||
case content::MenuItem::SEPARATOR:
|
||||
return StringToV8(isolate, "separator");
|
||||
case content::MenuItem::SUBMENU:
|
||||
return StringToV8(isolate, "submenu");
|
||||
case content::MenuItem::OPTION:
|
||||
default:
|
||||
return StringToV8(isolate, "normal");
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<ContextMenuParamsWithWebContents>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const ContextMenuParamsWithWebContents& val) {
|
||||
const auto& params = val.first;
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("x", params.x);
|
||||
dict.Set("y", params.y);
|
||||
dict.Set("linkURL", params.link_url);
|
||||
dict.Set("linkText", params.link_text);
|
||||
dict.Set("pageURL", params.page_url);
|
||||
dict.Set("frameURL", params.frame_url);
|
||||
dict.Set("srcURL", params.src_url);
|
||||
dict.Set("mediaType", params.media_type);
|
||||
dict.Set("mediaFlags", MediaFlagsToV8(isolate, params.media_flags));
|
||||
bool has_image_contents =
|
||||
(params.media_type == blink::WebContextMenuData::kMediaTypeImage) &&
|
||||
params.has_image_contents;
|
||||
dict.Set("hasImageContents", has_image_contents);
|
||||
dict.Set("isEditable", params.is_editable);
|
||||
dict.Set("editFlags", EditFlagsToV8(isolate, params.edit_flags));
|
||||
dict.Set("selectionText", params.selection_text);
|
||||
dict.Set("titleText", params.title_text);
|
||||
dict.Set("misspelledWord", params.misspelled_word);
|
||||
dict.Set("frameCharset", params.frame_charset);
|
||||
dict.Set("inputFieldType", params.input_field_type);
|
||||
dict.Set("menuSourceType", params.source_type);
|
||||
|
||||
if (params.custom_context.is_pepper_menu)
|
||||
dict.Set("menu", MenuToV8(isolate, val.second, params.custom_context,
|
||||
params.custom_items));
|
||||
return mate::ConvertToV8(isolate, dict);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Converter<blink::mojom::PermissionStatus>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::mojom::PermissionStatus* out) {
|
||||
bool result;
|
||||
if (!ConvertFromV8(isolate, val, &result))
|
||||
return false;
|
||||
|
||||
if (result)
|
||||
*out = blink::mojom::PermissionStatus::GRANTED;
|
||||
else
|
||||
*out = blink::mojom::PermissionStatus::DENIED;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<content::PermissionType>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const content::PermissionType& val) {
|
||||
using PermissionType = atom::WebContentsPermissionHelper::PermissionType;
|
||||
switch (val) {
|
||||
case content::PermissionType::MIDI_SYSEX:
|
||||
return StringToV8(isolate, "midiSysex");
|
||||
case content::PermissionType::NOTIFICATIONS:
|
||||
return StringToV8(isolate, "notifications");
|
||||
case content::PermissionType::GEOLOCATION:
|
||||
return StringToV8(isolate, "geolocation");
|
||||
case content::PermissionType::AUDIO_CAPTURE:
|
||||
case content::PermissionType::VIDEO_CAPTURE:
|
||||
return StringToV8(isolate, "media");
|
||||
case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
|
||||
return StringToV8(isolate, "mediaKeySystem");
|
||||
case content::PermissionType::MIDI:
|
||||
return StringToV8(isolate, "midi");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (val == static_cast<content::PermissionType>(PermissionType::POINTER_LOCK))
|
||||
return StringToV8(isolate, "pointerLock");
|
||||
else if (val ==
|
||||
static_cast<content::PermissionType>(PermissionType::FULLSCREEN))
|
||||
return StringToV8(isolate, "fullscreen");
|
||||
else if (val ==
|
||||
static_cast<content::PermissionType>(PermissionType::OPEN_EXTERNAL))
|
||||
return StringToV8(isolate, "openExternal");
|
||||
|
||||
return StringToV8(isolate, "unknown");
|
||||
}
|
||||
|
||||
// static
|
||||
bool Converter<content::StopFindAction>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::StopFindAction* out) {
|
||||
std::string action;
|
||||
if (!ConvertFromV8(isolate, val, &action))
|
||||
return false;
|
||||
|
||||
if (action == "clearSelection")
|
||||
*out = content::STOP_FIND_ACTION_CLEAR_SELECTION;
|
||||
else if (action == "keepSelection")
|
||||
*out = content::STOP_FIND_ACTION_KEEP_SELECTION;
|
||||
else if (action == "activateSelection")
|
||||
*out = content::STOP_FIND_ACTION_ACTIVATE_SELECTION;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<content::WebContents*>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
content::WebContents* val) {
|
||||
if (!val)
|
||||
return v8::Null(isolate);
|
||||
return atom::api::WebContents::FromOrCreate(isolate, val).ToV8();
|
||||
}
|
||||
|
||||
// static
|
||||
bool Converter<content::WebContents*>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::WebContents** out) {
|
||||
atom::api::WebContents* web_contents = nullptr;
|
||||
if (!ConvertFromV8(isolate, val, &web_contents) || !web_contents)
|
||||
return false;
|
||||
|
||||
*out = web_contents->web_contents();
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<content::Referrer>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const content::Referrer& val) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("url", ConvertToV8(isolate, val.url));
|
||||
dict.Set("policy", ConvertToV8(isolate, val.policy));
|
||||
return mate::ConvertToV8(isolate, dict);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Converter<content::Referrer>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::Referrer* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
|
||||
if (!dict.Get("url", &out->url))
|
||||
return false;
|
||||
|
||||
if (!dict.Get("policy", &out->policy))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mate
|
79
shell/common/native_mate_converters/content_converter.h
Normal file
79
shell/common/native_mate_converters/content_converter.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
// 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_NATIVE_MATE_CONVERTERS_CONTENT_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_CONTENT_CONVERTER_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "content/public/browser/permission_type.h"
|
||||
#include "content/public/common/menu_item.h"
|
||||
#include "content/public/common/referrer.h"
|
||||
#include "content/public/common/stop_find_action.h"
|
||||
#include "native_mate/converter.h"
|
||||
#include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
|
||||
|
||||
namespace content {
|
||||
struct ContextMenuParams;
|
||||
class WebContents;
|
||||
} // namespace content
|
||||
|
||||
using ContextMenuParamsWithWebContents =
|
||||
std::pair<content::ContextMenuParams, content::WebContents*>;
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<content::MenuItem::Type> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const content::MenuItem::Type& val);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<ContextMenuParamsWithWebContents> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const ContextMenuParamsWithWebContents& val);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::mojom::PermissionStatus> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::mojom::PermissionStatus* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<content::PermissionType> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const content::PermissionType& val);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<content::StopFindAction> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::StopFindAction* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<content::WebContents*> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
content::WebContents* val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::WebContents** out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<content::Referrer> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const content::Referrer& val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::Referrer* out);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_CONTENT_CONVERTER_H_
|
76
shell/common/native_mate_converters/file_dialog_converter.cc
Normal file
76
shell/common/native_mate_converters/file_dialog_converter.cc
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/native_mate_converters/file_dialog_converter.h"
|
||||
|
||||
#include "atom/browser/api/atom_api_browser_window.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
bool Converter<file_dialog::Filter>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
file_dialog::Filter* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
if (!dict.Get("name", &(out->first)))
|
||||
return false;
|
||||
if (!dict.Get("extensions", &(out->second)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Converter<file_dialog::Filter>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const file_dialog::Filter& in) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
|
||||
dict.Set("name", in.first);
|
||||
dict.Set("extensions", in.second);
|
||||
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
bool Converter<file_dialog::DialogSettings>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
file_dialog::DialogSettings* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
dict.Get("window", &(out->parent_window));
|
||||
dict.Get("title", &(out->title));
|
||||
dict.Get("message", &(out->message));
|
||||
dict.Get("buttonLabel", &(out->button_label));
|
||||
dict.Get("nameFieldLabel", &(out->name_field_label));
|
||||
dict.Get("defaultPath", &(out->default_path));
|
||||
dict.Get("filters", &(out->filters));
|
||||
dict.Get("properties", &(out->properties));
|
||||
dict.Get("showsTagField", &(out->shows_tag_field));
|
||||
dict.Get("securityScopedBookmarks", &(out->security_scoped_bookmarks));
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Converter<file_dialog::DialogSettings>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const file_dialog::DialogSettings& in) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
|
||||
dict.Set("window", atom::api::BrowserWindow::From(isolate, in.parent_window));
|
||||
dict.Set("title", in.title);
|
||||
dict.Set("message", in.message);
|
||||
dict.Set("buttonLabel", in.button_label);
|
||||
dict.Set("nameFieldLabel", in.name_field_label);
|
||||
dict.Set("defaultPath", in.default_path);
|
||||
dict.Set("filters", in.filters);
|
||||
dict.Set("showsTagField", in.shows_tag_field);
|
||||
dict.Set("securityScopedBookmarks", in.security_scoped_bookmarks);
|
||||
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
} // namespace mate
|
33
shell/common/native_mate_converters/file_dialog_converter.h
Normal file
33
shell/common/native_mate_converters/file_dialog_converter.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_FILE_DIALOG_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_FILE_DIALOG_CONVERTER_H_
|
||||
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<file_dialog::Filter> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const file_dialog::Filter& in);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
file_dialog::Filter* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<file_dialog::DialogSettings> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const file_dialog::DialogSettings& in);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
file_dialog::DialogSettings* out);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_FILE_DIALOG_CONVERTER_H_
|
57
shell/common/native_mate_converters/file_path_converter.h
Normal file
57
shell/common/native_mate_converters/file_path_converter.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_FILE_PATH_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_FILE_PATH_CONVERTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
namespace gin {
|
||||
|
||||
template <>
|
||||
struct Converter<base::FilePath> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const base::FilePath& val) {
|
||||
return Converter<base::FilePath::StringType>::ToV8(isolate, val.value());
|
||||
}
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::FilePath* out) {
|
||||
if (val->IsNull())
|
||||
return true;
|
||||
|
||||
base::FilePath::StringType path;
|
||||
if (Converter<base::FilePath::StringType>::FromV8(isolate, val, &path)) {
|
||||
*out = base::FilePath(path);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gin
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<base::FilePath> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const base::FilePath& val) {
|
||||
return gin::Converter<base::FilePath::StringType>::ToV8(isolate,
|
||||
val.value());
|
||||
}
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::FilePath* out) {
|
||||
return gin::Converter<base::FilePath>::FromV8(isolate, val, out);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_FILE_PATH_CONVERTER_H_
|
161
shell/common/native_mate_converters/gfx_converter.cc
Normal file
161
shell/common/native_mate_converters/gfx_converter.cc
Normal file
|
@ -0,0 +1,161 @@
|
|||
// 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/native_mate_converters/gfx_converter.h"
|
||||
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/display/display.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/gfx/geometry/point.h"
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
#include "ui/gfx/geometry/size.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
v8::Local<v8::Value> Converter<gfx::Point>::ToV8(v8::Isolate* isolate,
|
||||
const gfx::Point& val) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.SetHidden("simple", true);
|
||||
dict.Set("x", val.x());
|
||||
dict.Set("y", val.y());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
bool Converter<gfx::Point>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::Point* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
double x, y;
|
||||
if (!dict.Get("x", &x) || !dict.Get("y", &y))
|
||||
return false;
|
||||
*out = gfx::Point(static_cast<int>(std::round(x)),
|
||||
static_cast<int>(std::round(y)));
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Converter<gfx::PointF>::ToV8(v8::Isolate* isolate,
|
||||
const gfx::PointF& val) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.SetHidden("simple", true);
|
||||
dict.Set("x", val.x());
|
||||
dict.Set("y", val.y());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
bool Converter<gfx::PointF>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::PointF* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
float x, y;
|
||||
if (!dict.Get("x", &x) || !dict.Get("y", &y))
|
||||
return false;
|
||||
*out = gfx::PointF(x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Converter<gfx::Size>::ToV8(v8::Isolate* isolate,
|
||||
const gfx::Size& val) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.SetHidden("simple", true);
|
||||
dict.Set("width", val.width());
|
||||
dict.Set("height", val.height());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
bool Converter<gfx::Size>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::Size* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
int width, height;
|
||||
if (!dict.Get("width", &width) || !dict.Get("height", &height))
|
||||
return false;
|
||||
*out = gfx::Size(width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Converter<gfx::Rect>::ToV8(v8::Isolate* isolate,
|
||||
const gfx::Rect& val) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.SetHidden("simple", true);
|
||||
dict.Set("x", val.x());
|
||||
dict.Set("y", val.y());
|
||||
dict.Set("width", val.width());
|
||||
dict.Set("height", val.height());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
bool Converter<gfx::Rect>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::Rect* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
int x, y, width, height;
|
||||
if (!dict.Get("x", &x) || !dict.Get("y", &y) || !dict.Get("width", &width) ||
|
||||
!dict.Get("height", &height))
|
||||
return false;
|
||||
*out = gfx::Rect(x, y, width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct Converter<display::Display::AccelerometerSupport> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const display::Display::AccelerometerSupport& val) {
|
||||
switch (val) {
|
||||
case display::Display::AccelerometerSupport::AVAILABLE:
|
||||
return StringToV8(isolate, "available");
|
||||
case display::Display::AccelerometerSupport::UNAVAILABLE:
|
||||
return StringToV8(isolate, "unavailable");
|
||||
default:
|
||||
return StringToV8(isolate, "unknown");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<display::Display::TouchSupport> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const display::Display::TouchSupport& val) {
|
||||
switch (val) {
|
||||
case display::Display::TouchSupport::AVAILABLE:
|
||||
return StringToV8(isolate, "available");
|
||||
case display::Display::TouchSupport::UNAVAILABLE:
|
||||
return StringToV8(isolate, "unavailable");
|
||||
default:
|
||||
return StringToV8(isolate, "unknown");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
v8::Local<v8::Value> Converter<display::Display>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const display::Display& val) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.SetHidden("simple", true);
|
||||
dict.Set("id", val.id());
|
||||
dict.Set("bounds", val.bounds());
|
||||
dict.Set("workArea", val.work_area());
|
||||
dict.Set("accelerometerSupport", val.accelerometer_support());
|
||||
dict.Set("monochrome", val.is_monochrome());
|
||||
dict.Set("colorDepth", val.color_depth());
|
||||
dict.Set("colorSpace", val.color_space().ToString());
|
||||
dict.Set("depthPerComponent", val.depth_per_component());
|
||||
dict.Set("size", val.size());
|
||||
dict.Set("workAreaSize", val.work_area_size());
|
||||
dict.Set("scaleFactor", val.device_scale_factor());
|
||||
dict.Set("rotation", val.RotationAsDegree());
|
||||
dict.Set("internal", val.IsInternal());
|
||||
dict.Set("touchSupport", val.touch_support());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
} // namespace mate
|
67
shell/common/native_mate_converters/gfx_converter.h
Normal file
67
shell/common/native_mate_converters/gfx_converter.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_GFX_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_GFX_CONVERTER_H_
|
||||
|
||||
#include "native_mate/converter.h"
|
||||
#include "ui/gfx/geometry/point_f.h"
|
||||
|
||||
namespace display {
|
||||
class Display;
|
||||
}
|
||||
|
||||
namespace gfx {
|
||||
class Point;
|
||||
class Size;
|
||||
class Rect;
|
||||
} // namespace gfx
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<gfx::Point> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, const gfx::Point& val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::Point* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<gfx::PointF> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const gfx::PointF& val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::PointF* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<gfx::Size> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, const gfx::Size& val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::Size* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<gfx::Rect> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, const gfx::Rect& val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::Rect* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<display::Display> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const display::Display& val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
display::Display* out);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_GFX_CONVERTER_H_
|
35
shell/common/native_mate_converters/gurl_converter.h
Normal file
35
shell/common/native_mate_converters/gurl_converter.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_GURL_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_GURL_CONVERTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "native_mate/converter.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<GURL> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, const GURL& val) {
|
||||
return ConvertToV8(isolate, val.spec());
|
||||
}
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
GURL* out) {
|
||||
std::string url;
|
||||
if (Converter<std::string>::FromV8(isolate, val, &url)) {
|
||||
*out = GURL(url);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_GURL_CONVERTER_H_
|
43
shell/common/native_mate_converters/image_converter.cc
Normal file
43
shell/common/native_mate_converters/image_converter.cc
Normal file
|
@ -0,0 +1,43 @@
|
|||
// 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 "atom/common/native_mate_converters/image_converter.h"
|
||||
|
||||
#include "atom/common/api/atom_api_native_image.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
bool Converter<gfx::ImageSkia>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::ImageSkia* out) {
|
||||
gfx::Image image;
|
||||
if (!ConvertFromV8(isolate, val, &image))
|
||||
return false;
|
||||
|
||||
*out = image.AsImageSkia();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter<gfx::Image>::FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::Image* out) {
|
||||
if (val->IsNull())
|
||||
return true;
|
||||
|
||||
Handle<atom::api::NativeImage> native_image;
|
||||
if (!ConvertFromV8(isolate, val, &native_image))
|
||||
return false;
|
||||
|
||||
*out = native_image->image();
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Converter<gfx::Image>::ToV8(v8::Isolate* isolate,
|
||||
const gfx::Image& val) {
|
||||
return ConvertToV8(isolate, atom::api::NativeImage::Create(isolate, val));
|
||||
}
|
||||
|
||||
} // namespace mate
|
34
shell/common/native_mate_converters/image_converter.h
Normal file
34
shell/common/native_mate_converters/image_converter.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_IMAGE_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_IMAGE_CONVERTER_H_
|
||||
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace gfx {
|
||||
class Image;
|
||||
class ImageSkia;
|
||||
} // namespace gfx
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<gfx::ImageSkia> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::ImageSkia* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<gfx::Image> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
gfx::Image* out);
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, const gfx::Image& val);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_IMAGE_CONVERTER_H_
|
70
shell/common/native_mate_converters/map_converter.h
Normal file
70
shell/common/native_mate_converters/map_converter.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Copyright (c) 2019 Slack Technologies, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_MAP_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_MAP_CONVERTER_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "gin/converter.h"
|
||||
|
||||
namespace gin {
|
||||
|
||||
template <typename T>
|
||||
struct Converter<std::map<std::string, T>> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
std::map<std::string, T>* out) {
|
||||
if (!val->IsObject())
|
||||
return false;
|
||||
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::Object> dict = val->ToObject(context).ToLocalChecked();
|
||||
v8::Local<v8::Array> keys =
|
||||
dict->GetOwnPropertyNames(context).ToLocalChecked();
|
||||
for (uint32_t i = 0; i < keys->Length(); ++i) {
|
||||
v8::Local<v8::Value> key = keys->Get(context, i).ToLocalChecked();
|
||||
T value;
|
||||
if (Converter<T>::FromV8(
|
||||
isolate, dict->Get(context, key).ToLocalChecked(), &value))
|
||||
(*out)[gin::V8ToString(isolate, key)] = std::move(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const std::map<std::string, T>& val) {
|
||||
v8::Local<v8::Object> result = v8::Object::New(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
for (auto i = val.begin(); i != val.end(); i++) {
|
||||
result
|
||||
->Set(context, Converter<T>::ToV8(isolate, i->first),
|
||||
Converter<T>::ToV8(isolate, i->second))
|
||||
.Check();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gin
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <typename T>
|
||||
struct Converter<std::map<std::string, T>> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
std::map<std::string, T>* out) {
|
||||
return gin::Converter<std::map<std::string, T>>::FromV8(isolate, val, out);
|
||||
}
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const std::map<std::string, T>& val) {
|
||||
return gin::Converter<std::map<std::string, T>>::ToV8(isolate, val);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_MAP_CONVERTER_H_
|
38
shell/common/native_mate_converters/message_box_converter.cc
Normal file
38
shell/common/native_mate_converters/message_box_converter.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/native_mate_converters/message_box_converter.h"
|
||||
|
||||
#include "atom/browser/api/atom_api_browser_window.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
bool Converter<atom::MessageBoxSettings>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
atom::MessageBoxSettings* out) {
|
||||
mate::Dictionary dict;
|
||||
int type = 0;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
dict.Get("window", &out->parent_window);
|
||||
dict.Get("type", &type);
|
||||
out->type = static_cast<atom::MessageBoxType>(type);
|
||||
dict.Get("buttons", &out->buttons);
|
||||
dict.Get("defaultId", &out->default_id);
|
||||
dict.Get("cancelId", &out->cancel_id);
|
||||
dict.Get("options", &out->options);
|
||||
dict.Get("title", &out->title);
|
||||
dict.Get("message", &out->message);
|
||||
dict.Get("detail", &out->detail);
|
||||
dict.Get("checkboxLabel", &out->checkbox_label);
|
||||
dict.Get("checkboxChecked", &out->checkbox_checked);
|
||||
dict.Get("icon", &out->icon);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mate
|
22
shell/common/native_mate_converters/message_box_converter.h
Normal file
22
shell/common/native_mate_converters/message_box_converter.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2019 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_MESSAGE_BOX_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_MESSAGE_BOX_CONVERTER_H_
|
||||
|
||||
#include "atom/browser/ui/message_box.h"
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<atom::MessageBoxSettings> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
atom::MessageBoxSettings* out);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_MESSAGE_BOX_CONVERTER_H_
|
324
shell/common/native_mate_converters/net_converter.cc
Normal file
324
shell/common/native_mate_converters/net_converter.cc
Normal file
|
@ -0,0 +1,324 @@
|
|||
// 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/native_mate_converters/net_converter.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/values.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/base/upload_bytes_element_reader.h"
|
||||
#include "net/base/upload_data_stream.h"
|
||||
#include "net/base/upload_element_reader.h"
|
||||
#include "net/base/upload_file_element_reader.h"
|
||||
#include "net/cert/x509_certificate.h"
|
||||
#include "net/cert/x509_util.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
#include "services/network/public/cpp/resource_request.h"
|
||||
#include "storage/browser/blob/upload_blob_element_reader.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace {
|
||||
|
||||
bool CertFromData(const std::string& data,
|
||||
scoped_refptr<net::X509Certificate>* out) {
|
||||
auto cert_list = net::X509Certificate::CreateCertificateListFromBytes(
|
||||
data.c_str(), data.length(),
|
||||
net::X509Certificate::FORMAT_SINGLE_CERTIFICATE);
|
||||
if (cert_list.empty())
|
||||
return false;
|
||||
|
||||
auto leaf_cert = cert_list.front();
|
||||
if (!leaf_cert)
|
||||
return false;
|
||||
|
||||
*out = leaf_cert;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<net::AuthChallengeInfo>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const net::AuthChallengeInfo& val) {
|
||||
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("isProxy", val.is_proxy);
|
||||
dict.Set("scheme", val.scheme);
|
||||
dict.Set("host", val.challenger.host());
|
||||
dict.Set("port", static_cast<uint32_t>(val.challenger.port()));
|
||||
dict.Set("realm", val.realm);
|
||||
return mate::ConvertToV8(isolate, dict);
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<scoped_refptr<net::X509Certificate>>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const scoped_refptr<net::X509Certificate>& val) {
|
||||
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||
std::string encoded_data;
|
||||
net::X509Certificate::GetPEMEncoded(val->cert_buffer(), &encoded_data);
|
||||
|
||||
dict.Set("data", encoded_data);
|
||||
dict.Set("issuer", val->issuer());
|
||||
dict.Set("issuerName", val->issuer().GetDisplayName());
|
||||
dict.Set("subject", val->subject());
|
||||
dict.Set("subjectName", val->subject().GetDisplayName());
|
||||
dict.Set("serialNumber", base::HexEncode(val->serial_number().data(),
|
||||
val->serial_number().size()));
|
||||
dict.Set("validStart", val->valid_start().ToDoubleT());
|
||||
dict.Set("validExpiry", val->valid_expiry().ToDoubleT());
|
||||
dict.Set("fingerprint",
|
||||
net::HashValue(val->CalculateFingerprint256(val->cert_buffer()))
|
||||
.ToString());
|
||||
|
||||
const auto& intermediate_buffers = val->intermediate_buffers();
|
||||
if (!intermediate_buffers.empty()) {
|
||||
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> issuer_intermediates;
|
||||
issuer_intermediates.reserve(intermediate_buffers.size() - 1);
|
||||
for (size_t i = 1; i < intermediate_buffers.size(); ++i) {
|
||||
issuer_intermediates.push_back(
|
||||
bssl::UpRef(intermediate_buffers[i].get()));
|
||||
}
|
||||
const scoped_refptr<net::X509Certificate>& issuer_cert =
|
||||
net::X509Certificate::CreateFromBuffer(
|
||||
bssl::UpRef(intermediate_buffers[0].get()),
|
||||
std::move(issuer_intermediates));
|
||||
dict.Set("issuerCert", issuer_cert);
|
||||
}
|
||||
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
bool Converter<scoped_refptr<net::X509Certificate>>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
scoped_refptr<net::X509Certificate>* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
|
||||
std::string data;
|
||||
dict.Get("data", &data);
|
||||
scoped_refptr<net::X509Certificate> leaf_cert;
|
||||
if (!CertFromData(data, &leaf_cert))
|
||||
return false;
|
||||
|
||||
scoped_refptr<net::X509Certificate> issuer_cert;
|
||||
if (dict.Get("issuerCert", &issuer_cert)) {
|
||||
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
|
||||
intermediates.push_back(bssl::UpRef(issuer_cert->cert_buffer()));
|
||||
auto cert = net::X509Certificate::CreateFromBuffer(
|
||||
bssl::UpRef(leaf_cert->cert_buffer()), std::move(intermediates));
|
||||
if (!cert)
|
||||
return false;
|
||||
|
||||
*out = cert;
|
||||
} else {
|
||||
*out = leaf_cert;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<net::CertPrincipal>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const net::CertPrincipal& val) {
|
||||
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||
|
||||
dict.Set("commonName", val.common_name);
|
||||
dict.Set("organizations", val.organization_names);
|
||||
dict.Set("organizationUnits", val.organization_unit_names);
|
||||
dict.Set("locality", val.locality_name);
|
||||
dict.Set("state", val.state_or_province_name);
|
||||
dict.Set("country", val.country_name);
|
||||
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<net::HttpResponseHeaders*>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
net::HttpResponseHeaders* headers) {
|
||||
base::DictionaryValue response_headers;
|
||||
if (headers) {
|
||||
size_t iter = 0;
|
||||
std::string key;
|
||||
std::string value;
|
||||
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
|
||||
key = base::ToLowerASCII(key);
|
||||
if (response_headers.FindKey(key)) {
|
||||
base::ListValue* values = nullptr;
|
||||
if (response_headers.GetList(key, &values))
|
||||
values->AppendString(value);
|
||||
} else {
|
||||
auto values = std::make_unique<base::ListValue>();
|
||||
values->AppendString(value);
|
||||
response_headers.Set(key, std::move(values));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ConvertToV8(isolate, response_headers);
|
||||
}
|
||||
|
||||
bool Converter<net::HttpResponseHeaders*>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
net::HttpResponseHeaders* out) {
|
||||
if (!val->IsObject()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto addHeaderFromValue = [&isolate, &out](
|
||||
const std::string& key,
|
||||
const v8::Local<v8::Value>& localVal) {
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::String> localStrVal;
|
||||
if (!localVal->ToString(context).ToLocal(&localStrVal)) {
|
||||
return false;
|
||||
}
|
||||
std::string value;
|
||||
mate::ConvertFromV8(isolate, localStrVal, &value);
|
||||
out->AddHeader(key + ": " + value);
|
||||
return true;
|
||||
};
|
||||
|
||||
auto context = isolate->GetCurrentContext();
|
||||
auto headers = v8::Local<v8::Object>::Cast(val);
|
||||
auto keys = headers->GetOwnPropertyNames(context).ToLocalChecked();
|
||||
for (uint32_t i = 0; i < keys->Length(); i++) {
|
||||
v8::Local<v8::Value> keyVal;
|
||||
if (!keys->Get(context, i).ToLocal(&keyVal)) {
|
||||
return false;
|
||||
}
|
||||
std::string key;
|
||||
mate::ConvertFromV8(isolate, keyVal, &key);
|
||||
|
||||
auto localVal = headers->Get(context, keyVal).ToLocalChecked();
|
||||
if (localVal->IsArray()) {
|
||||
auto values = v8::Local<v8::Array>::Cast(localVal);
|
||||
for (uint32_t j = 0; j < values->Length(); j++) {
|
||||
if (!addHeaderFromValue(key,
|
||||
values->Get(context, j).ToLocalChecked())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!addHeaderFromValue(key, localVal)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<network::ResourceRequest>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const network::ResourceRequest& val) {
|
||||
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||
dict.Set("method", val.method);
|
||||
dict.Set("url", val.url.spec());
|
||||
dict.Set("referrer", val.referrer.spec());
|
||||
mate::Dictionary headers(isolate, v8::Object::New(isolate));
|
||||
for (net::HttpRequestHeaders::Iterator it(val.headers); it.GetNext();)
|
||||
headers.Set(it.name(), it.value());
|
||||
dict.Set("headers", headers);
|
||||
if (val.request_body) {
|
||||
const auto& elements = *val.request_body->elements();
|
||||
v8::Local<v8::Array> arr = v8::Array::New(isolate, elements.size());
|
||||
for (size_t i = 0; i < elements.size(); ++i) {
|
||||
const auto& element = elements[i];
|
||||
mate::Dictionary upload_data(isolate, v8::Object::New(isolate));
|
||||
switch (element.type()) {
|
||||
case network::mojom::DataElementType::kFile:
|
||||
upload_data.Set("file", element.path().value());
|
||||
break;
|
||||
case network::mojom::DataElementType::kBytes:
|
||||
upload_data.Set("bytes", node::Buffer::Copy(isolate, element.bytes(),
|
||||
element.length())
|
||||
.ToLocalChecked());
|
||||
break;
|
||||
case network::mojom::DataElementType::kBlob:
|
||||
upload_data.Set("blobUUID", element.blob_uuid());
|
||||
break;
|
||||
default:
|
||||
NOTREACHED() << "Found unsupported data element";
|
||||
}
|
||||
arr->Set(isolate->GetCurrentContext(), static_cast<uint32_t>(i),
|
||||
upload_data.GetHandle())
|
||||
.Check();
|
||||
}
|
||||
dict.Set("uploadData", arr);
|
||||
}
|
||||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
void FillRequestDetails(base::DictionaryValue* details,
|
||||
const net::URLRequest* request) {
|
||||
details->SetString("method", request->method());
|
||||
std::string url;
|
||||
if (!request->url_chain().empty())
|
||||
url = request->url().spec();
|
||||
details->SetKey("url", base::Value(url));
|
||||
details->SetString("referrer", request->referrer());
|
||||
auto list = std::make_unique<base::ListValue>();
|
||||
GetUploadData(list.get(), request);
|
||||
if (!list->empty())
|
||||
details->Set("uploadData", std::move(list));
|
||||
auto headers_value = std::make_unique<base::DictionaryValue>();
|
||||
for (net::HttpRequestHeaders::Iterator it(request->extra_request_headers());
|
||||
it.GetNext();) {
|
||||
headers_value->SetString(it.name(), it.value());
|
||||
}
|
||||
details->Set("headers", std::move(headers_value));
|
||||
}
|
||||
|
||||
void GetUploadData(base::ListValue* upload_data_list,
|
||||
const net::URLRequest* request) {
|
||||
const net::UploadDataStream* upload_data = request->get_upload();
|
||||
if (!upload_data)
|
||||
return;
|
||||
const std::vector<std::unique_ptr<net::UploadElementReader>>* readers =
|
||||
upload_data->GetElementReaders();
|
||||
for (const auto& reader : *readers) {
|
||||
auto upload_data_dict = std::make_unique<base::DictionaryValue>();
|
||||
if (reader->AsBytesReader()) {
|
||||
const net::UploadBytesElementReader* bytes_reader =
|
||||
reader->AsBytesReader();
|
||||
auto bytes = std::make_unique<base::Value>(
|
||||
std::vector<char>(bytes_reader->bytes(),
|
||||
bytes_reader->bytes() + bytes_reader->length()));
|
||||
upload_data_dict->Set("bytes", std::move(bytes));
|
||||
} else if (reader->AsFileReader()) {
|
||||
const net::UploadFileElementReader* file_reader = reader->AsFileReader();
|
||||
auto file_path = file_reader->path().AsUTF8Unsafe();
|
||||
upload_data_dict->SetKey("file", base::Value(file_path));
|
||||
} else {
|
||||
const storage::UploadBlobElementReader* blob_reader =
|
||||
static_cast<storage::UploadBlobElementReader*>(reader.get());
|
||||
upload_data_dict->SetString("blobUUID", blob_reader->uuid());
|
||||
}
|
||||
upload_data_list->Append(std::move(upload_data_dict));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
80
shell/common/native_mate_converters/net_converter.h
Normal file
80
shell/common/native_mate_converters/net_converter.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
// 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_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
class ListValue;
|
||||
} // namespace base
|
||||
|
||||
namespace net {
|
||||
class AuthChallengeInfo;
|
||||
class URLRequest;
|
||||
class X509Certificate;
|
||||
class HttpResponseHeaders;
|
||||
struct CertPrincipal;
|
||||
} // namespace net
|
||||
|
||||
namespace network {
|
||||
struct ResourceRequest;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<net::AuthChallengeInfo> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const net::AuthChallengeInfo& val);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<scoped_refptr<net::X509Certificate>> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const scoped_refptr<net::X509Certificate>& val);
|
||||
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
scoped_refptr<net::X509Certificate>* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<net::CertPrincipal> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const net::CertPrincipal& val);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<net::HttpResponseHeaders*> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
net::HttpResponseHeaders* headers);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
net::HttpResponseHeaders* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<network::ResourceRequest> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const network::ResourceRequest& val);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
void FillRequestDetails(base::DictionaryValue* details,
|
||||
const net::URLRequest* request);
|
||||
|
||||
void GetUploadData(base::ListValue* upload_data_list,
|
||||
const net::URLRequest* request);
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_
|
94
shell/common/native_mate_converters/network_converter.cc
Normal file
94
shell/common/native_mate_converters/network_converter.cc
Normal file
|
@ -0,0 +1,94 @@
|
|||
// 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/native_mate_converters/network_converter.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "services/network/public/cpp/resource_request_body.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value>
|
||||
Converter<scoped_refptr<network::ResourceRequestBody>>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const scoped_refptr<network::ResourceRequestBody>& val) {
|
||||
if (!val)
|
||||
return v8::Null(isolate);
|
||||
auto list = std::make_unique<base::ListValue>();
|
||||
for (const auto& element : *(val->elements())) {
|
||||
auto post_data_dict = std::make_unique<base::DictionaryValue>();
|
||||
auto type = element.type();
|
||||
if (type == network::mojom::DataElementType::kBytes) {
|
||||
auto bytes = std::make_unique<base::Value>(std::vector<char>(
|
||||
element.bytes(), element.bytes() + (element.length())));
|
||||
post_data_dict->SetString("type", "rawData");
|
||||
post_data_dict->Set("bytes", std::move(bytes));
|
||||
} else if (type == network::mojom::DataElementType::kFile) {
|
||||
post_data_dict->SetString("type", "file");
|
||||
post_data_dict->SetKey("filePath",
|
||||
base::Value(element.path().AsUTF8Unsafe()));
|
||||
post_data_dict->SetInteger("offset", static_cast<int>(element.offset()));
|
||||
post_data_dict->SetInteger("length", static_cast<int>(element.length()));
|
||||
post_data_dict->SetDouble(
|
||||
"modificationTime", element.expected_modification_time().ToDoubleT());
|
||||
} else if (type == network::mojom::DataElementType::kBlob) {
|
||||
post_data_dict->SetString("type", "blob");
|
||||
post_data_dict->SetString("blobUUID", element.blob_uuid());
|
||||
}
|
||||
list->Append(std::move(post_data_dict));
|
||||
}
|
||||
return ConvertToV8(isolate, *list);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Converter<scoped_refptr<network::ResourceRequestBody>>::FromV8(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
scoped_refptr<network::ResourceRequestBody>* out) {
|
||||
auto list = std::make_unique<base::ListValue>();
|
||||
if (!ConvertFromV8(isolate, val, list.get()))
|
||||
return false;
|
||||
*out = new network::ResourceRequestBody();
|
||||
for (size_t i = 0; i < list->GetSize(); ++i) {
|
||||
base::DictionaryValue* dict = nullptr;
|
||||
std::string type;
|
||||
if (!list->GetDictionary(i, &dict))
|
||||
return false;
|
||||
dict->GetString("type", &type);
|
||||
if (type == "rawData") {
|
||||
base::Value* bytes = nullptr;
|
||||
dict->GetBinary("bytes", &bytes);
|
||||
(*out)->AppendBytes(
|
||||
reinterpret_cast<const char*>(bytes->GetBlob().data()),
|
||||
base::checked_cast<int>(bytes->GetBlob().size()));
|
||||
} else if (type == "file") {
|
||||
std::string file;
|
||||
int offset = 0, length = -1;
|
||||
double modification_time = 0.0;
|
||||
dict->GetStringWithoutPathExpansion("filePath", &file);
|
||||
dict->GetInteger("offset", &offset);
|
||||
dict->GetInteger("file", &length);
|
||||
dict->GetDouble("modificationTime", &modification_time);
|
||||
(*out)->AppendFileRange(base::FilePath::FromUTF8Unsafe(file),
|
||||
static_cast<uint64_t>(offset),
|
||||
static_cast<uint64_t>(length),
|
||||
base::Time::FromDoubleT(modification_time));
|
||||
} else if (type == "blob") {
|
||||
std::string uuid;
|
||||
dict->GetString("blobUUID", &uuid);
|
||||
(*out)->AppendBlob(uuid);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mate
|
29
shell/common/native_mate_converters/network_converter.h
Normal file
29
shell/common/native_mate_converters/network_converter.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// 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_NATIVE_MATE_CONVERTERS_NETWORK_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_NETWORK_CONVERTER_H_
|
||||
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace network {
|
||||
class ResourceRequestBody;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<scoped_refptr<network::ResourceRequestBody>> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const scoped_refptr<network::ResourceRequestBody>& val);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
scoped_refptr<network::ResourceRequestBody>* out);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_NETWORK_CONVERTER_H_
|
87
shell/common/native_mate_converters/once_callback.h
Normal file
87
shell/common/native_mate_converters/once_callback.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) 2019 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_ONCE_CALLBACK_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_ONCE_CALLBACK_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Manages the OnceCallback with ref-couting.
|
||||
template <typename Sig>
|
||||
class RefCountedOnceCallback
|
||||
: public base::RefCounted<RefCountedOnceCallback<Sig>> {
|
||||
public:
|
||||
explicit RefCountedOnceCallback(base::OnceCallback<Sig> callback)
|
||||
: callback_(std::move(callback)) {}
|
||||
|
||||
base::OnceCallback<Sig> GetCallback() { return std::move(callback_); }
|
||||
|
||||
private:
|
||||
friend class base::RefCounted<RefCountedOnceCallback<Sig>>;
|
||||
~RefCountedOnceCallback() = default;
|
||||
|
||||
base::OnceCallback<Sig> callback_;
|
||||
};
|
||||
|
||||
// Invokes the OnceCallback.
|
||||
template <typename Sig>
|
||||
struct InvokeOnceCallback {};
|
||||
|
||||
template <typename... ArgTypes>
|
||||
struct InvokeOnceCallback<void(ArgTypes...)> {
|
||||
static void Go(
|
||||
scoped_refptr<RefCountedOnceCallback<void(ArgTypes...)>> holder,
|
||||
ArgTypes... args) {
|
||||
base::OnceCallback<void(ArgTypes...)> callback = holder->GetCallback();
|
||||
DCHECK(!callback.is_null());
|
||||
std::move(callback).Run(std::move(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
struct InvokeOnceCallback<ReturnType(ArgTypes...)> {
|
||||
static ReturnType Go(
|
||||
scoped_refptr<RefCountedOnceCallback<ReturnType(ArgTypes...)>> holder,
|
||||
ArgTypes... args) {
|
||||
base::OnceCallback<void(ArgTypes...)> callback = holder->GetCallback();
|
||||
DCHECK(!callback.is_null());
|
||||
return std::move(callback).Run(std::move(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Sig>
|
||||
struct Converter<base::OnceCallback<Sig>> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
base::OnceCallback<Sig> val) {
|
||||
// Reuse the converter of base::RepeatingCallback by storing the callback
|
||||
// with a RefCounted.
|
||||
auto holder = base::MakeRefCounted<internal::RefCountedOnceCallback<Sig>>(
|
||||
std::move(val));
|
||||
return Converter<base::RepeatingCallback<Sig>>::ToV8(
|
||||
isolate,
|
||||
base::BindRepeating(&internal::InvokeOnceCallback<Sig>::Go, holder));
|
||||
}
|
||||
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::OnceCallback<Sig>* out) {
|
||||
if (!val->IsFunction())
|
||||
return false;
|
||||
*out = base::BindOnce(&internal::V8FunctionInvoker<Sig>::Go, isolate,
|
||||
internal::SafeV8Function(isolate, val));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_ONCE_CALLBACK_H_
|
64
shell/common/native_mate_converters/string16_converter.h
Normal file
64
shell/common/native_mate_converters/string16_converter.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_STRING16_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_STRING16_CONVERTER_H_
|
||||
|
||||
#include "base/strings/string16.h"
|
||||
#include "gin/converter.h"
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace gin {
|
||||
|
||||
template <>
|
||||
struct Converter<base::string16> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const base::string16& val) {
|
||||
return v8::String::NewFromTwoByte(
|
||||
isolate, reinterpret_cast<const uint16_t*>(val.data()),
|
||||
v8::NewStringType::kNormal, val.size())
|
||||
.ToLocalChecked();
|
||||
}
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::string16* out) {
|
||||
if (!val->IsString())
|
||||
return false;
|
||||
|
||||
v8::String::Value s(isolate, val);
|
||||
out->assign(reinterpret_cast<const base::char16*>(*s), s.length());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
inline v8::Local<v8::String> StringToV8(v8::Isolate* isolate,
|
||||
const base::string16& input) {
|
||||
return ConvertToV8(isolate, input).As<v8::String>();
|
||||
}
|
||||
|
||||
} // namespace gin
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<base::string16> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const base::string16& val) {
|
||||
return gin::Converter<base::string16>::ToV8(isolate, val);
|
||||
}
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::string16* out) {
|
||||
return gin::Converter<base::string16>::FromV8(isolate, val, out);
|
||||
}
|
||||
};
|
||||
|
||||
inline v8::Local<v8::String> StringToV8(v8::Isolate* isolate,
|
||||
const base::string16& input) {
|
||||
return ConvertToV8(isolate, input).As<v8::String>();
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_STRING16_CONVERTER_H_
|
|
@ -0,0 +1,34 @@
|
|||
// 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_NATIVE_MATE_CONVERTERS_UI_BASE_TYPES_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_UI_BASE_TYPES_CONVERTER_H_
|
||||
|
||||
#include "native_mate/converter.h"
|
||||
#include "ui/base/ui_base_types.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<ui::MenuSourceType> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const ui::MenuSourceType& in) {
|
||||
switch (in) {
|
||||
case ui::MENU_SOURCE_MOUSE:
|
||||
return mate::StringToV8(isolate, "mouse");
|
||||
case ui::MENU_SOURCE_KEYBOARD:
|
||||
return mate::StringToV8(isolate, "keyboard");
|
||||
case ui::MENU_SOURCE_TOUCH:
|
||||
return mate::StringToV8(isolate, "touch");
|
||||
case ui::MENU_SOURCE_TOUCH_EDIT_MENU:
|
||||
return mate::StringToV8(isolate, "touchMenu");
|
||||
default:
|
||||
return mate::StringToV8(isolate, "none");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_UI_BASE_TYPES_CONVERTER_H_
|
517
shell/common/native_mate_converters/v8_value_converter.cc
Normal file
517
shell/common/native_mate_converters/v8_value_converter.cc
Normal file
|
@ -0,0 +1,517 @@
|
|||
// 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/native_mate_converters/v8_value_converter.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/values.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_bindings.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kMaxRecursionDepth = 100;
|
||||
|
||||
} // namespace
|
||||
|
||||
// The state of a call to FromV8Value.
|
||||
class V8ValueConverter::FromV8ValueState {
|
||||
public:
|
||||
// Level scope which updates the current depth of some FromV8ValueState.
|
||||
class Level {
|
||||
public:
|
||||
explicit Level(FromV8ValueState* state) : state_(state) {
|
||||
state_->max_recursion_depth_--;
|
||||
}
|
||||
~Level() { state_->max_recursion_depth_++; }
|
||||
|
||||
private:
|
||||
FromV8ValueState* state_;
|
||||
};
|
||||
|
||||
FromV8ValueState() : max_recursion_depth_(kMaxRecursionDepth) {}
|
||||
|
||||
// If |handle| is not in |unique_map_|, then add it to |unique_map_| and
|
||||
// return true.
|
||||
//
|
||||
// Otherwise do nothing and return false. Here "A is unique" means that no
|
||||
// other handle B in the map points to the same object as A. Note that A can
|
||||
// be unique even if there already is another handle with the same identity
|
||||
// hash (key) in the map, because two objects can have the same hash.
|
||||
bool AddToUniquenessCheck(v8::Local<v8::Object> handle) {
|
||||
int hash;
|
||||
auto iter = GetIteratorInMap(handle, &hash);
|
||||
if (iter != unique_map_.end())
|
||||
return false;
|
||||
|
||||
unique_map_.insert(std::make_pair(hash, handle));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoveFromUniquenessCheck(v8::Local<v8::Object> handle) {
|
||||
int unused_hash;
|
||||
auto iter = GetIteratorInMap(handle, &unused_hash);
|
||||
if (iter == unique_map_.end())
|
||||
return false;
|
||||
unique_map_.erase(iter);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasReachedMaxRecursionDepth() { return max_recursion_depth_ < 0; }
|
||||
|
||||
private:
|
||||
using HashToHandleMap = std::multimap<int, v8::Local<v8::Object>>;
|
||||
using Iterator = HashToHandleMap::const_iterator;
|
||||
|
||||
Iterator GetIteratorInMap(v8::Local<v8::Object> handle, int* hash) {
|
||||
*hash = handle->GetIdentityHash();
|
||||
// We only compare using == with handles to objects with the same identity
|
||||
// hash. Different hash obviously means different objects, but two objects
|
||||
// in a couple of thousands could have the same identity hash.
|
||||
std::pair<Iterator, Iterator> range = unique_map_.equal_range(*hash);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
// Operator == for handles actually compares the underlying objects.
|
||||
if (it->second == handle)
|
||||
return it;
|
||||
}
|
||||
// Not found.
|
||||
return unique_map_.end();
|
||||
}
|
||||
|
||||
HashToHandleMap unique_map_;
|
||||
|
||||
int max_recursion_depth_;
|
||||
};
|
||||
|
||||
// A class to ensure that objects/arrays that are being converted by
|
||||
// this V8ValueConverterImpl do not have cycles.
|
||||
//
|
||||
// An example of cycle: var v = {}; v = {key: v};
|
||||
// Not an example of cycle: var v = {}; a = [v, v]; or w = {a: v, b: v};
|
||||
class V8ValueConverter::ScopedUniquenessGuard {
|
||||
public:
|
||||
ScopedUniquenessGuard(V8ValueConverter::FromV8ValueState* state,
|
||||
v8::Local<v8::Object> value)
|
||||
: state_(state),
|
||||
value_(value),
|
||||
is_valid_(state_->AddToUniquenessCheck(value_)) {}
|
||||
~ScopedUniquenessGuard() {
|
||||
if (is_valid_) {
|
||||
bool removed = state_->RemoveFromUniquenessCheck(value_);
|
||||
DCHECK(removed);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_valid() const { return is_valid_; }
|
||||
|
||||
private:
|
||||
typedef std::multimap<int, v8::Local<v8::Object>> HashToHandleMap;
|
||||
V8ValueConverter::FromV8ValueState* state_;
|
||||
v8::Local<v8::Object> value_;
|
||||
bool is_valid_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedUniquenessGuard);
|
||||
};
|
||||
|
||||
V8ValueConverter::V8ValueConverter() {}
|
||||
|
||||
void V8ValueConverter::SetRegExpAllowed(bool val) {
|
||||
reg_exp_allowed_ = val;
|
||||
}
|
||||
|
||||
void V8ValueConverter::SetFunctionAllowed(bool val) {
|
||||
function_allowed_ = val;
|
||||
}
|
||||
|
||||
void V8ValueConverter::SetStripNullFromObjects(bool val) {
|
||||
strip_null_from_objects_ = val;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> V8ValueConverter::ToV8Value(
|
||||
const base::Value* value,
|
||||
v8::Local<v8::Context> context) const {
|
||||
v8::Context::Scope context_scope(context);
|
||||
v8::EscapableHandleScope handle_scope(context->GetIsolate());
|
||||
return handle_scope.Escape(ToV8ValueImpl(context->GetIsolate(), value));
|
||||
}
|
||||
|
||||
std::unique_ptr<base::Value> V8ValueConverter::FromV8Value(
|
||||
v8::Local<v8::Value> val,
|
||||
v8::Local<v8::Context> context) const {
|
||||
v8::Context::Scope context_scope(context);
|
||||
v8::HandleScope handle_scope(context->GetIsolate());
|
||||
FromV8ValueState state;
|
||||
return FromV8ValueImpl(&state, val, context->GetIsolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> V8ValueConverter::ToV8ValueImpl(
|
||||
v8::Isolate* isolate,
|
||||
const base::Value* value) const {
|
||||
switch (value->type()) {
|
||||
case base::Value::Type::NONE:
|
||||
return v8::Null(isolate);
|
||||
|
||||
case base::Value::Type::BOOLEAN: {
|
||||
bool val = value->GetBool();
|
||||
return v8::Boolean::New(isolate, val);
|
||||
}
|
||||
|
||||
case base::Value::Type::INTEGER: {
|
||||
int val = value->GetInt();
|
||||
return v8::Integer::New(isolate, val);
|
||||
}
|
||||
|
||||
case base::Value::Type::DOUBLE: {
|
||||
double val = value->GetDouble();
|
||||
return v8::Number::New(isolate, val);
|
||||
}
|
||||
|
||||
case base::Value::Type::STRING: {
|
||||
std::string val = value->GetString();
|
||||
return v8::String::NewFromUtf8(isolate, val.c_str(),
|
||||
v8::NewStringType::kNormal, val.length())
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
case base::Value::Type::LIST:
|
||||
return ToV8Array(isolate, static_cast<const base::ListValue*>(value));
|
||||
|
||||
case base::Value::Type::DICTIONARY:
|
||||
return ToV8Object(isolate,
|
||||
static_cast<const base::DictionaryValue*>(value));
|
||||
|
||||
case base::Value::Type::BINARY:
|
||||
return ToArrayBuffer(isolate, static_cast<const base::Value*>(value));
|
||||
|
||||
default:
|
||||
LOG(ERROR) << "Unexpected value type: " << value->type();
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> V8ValueConverter::ToV8Array(
|
||||
v8::Isolate* isolate,
|
||||
const base::ListValue* val) const {
|
||||
v8::Local<v8::Array> result(v8::Array::New(isolate, val->GetSize()));
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
for (size_t i = 0; i < val->GetSize(); ++i) {
|
||||
const base::Value* child = nullptr;
|
||||
val->Get(i, &child);
|
||||
|
||||
v8::Local<v8::Value> child_v8 = ToV8ValueImpl(isolate, child);
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
result->Set(context, static_cast<uint32_t>(i), child_v8).Check();
|
||||
if (try_catch.HasCaught())
|
||||
LOG(ERROR) << "Setter for index " << i << " threw an exception.";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> V8ValueConverter::ToV8Object(
|
||||
v8::Isolate* isolate,
|
||||
const base::DictionaryValue* val) const {
|
||||
mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate);
|
||||
result.SetHidden("simple", true);
|
||||
|
||||
for (base::DictionaryValue::Iterator iter(*val); !iter.IsAtEnd();
|
||||
iter.Advance()) {
|
||||
const std::string& key = iter.key();
|
||||
v8::Local<v8::Value> child_v8 = ToV8ValueImpl(isolate, &iter.value());
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
result.Set(key, child_v8);
|
||||
if (try_catch.HasCaught()) {
|
||||
LOG(ERROR) << "Setter for property " << key.c_str() << " threw an "
|
||||
<< "exception.";
|
||||
}
|
||||
}
|
||||
|
||||
return result.GetHandle();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> V8ValueConverter::ToArrayBuffer(
|
||||
v8::Isolate* isolate,
|
||||
const base::Value* value) const {
|
||||
const auto* data = reinterpret_cast<const char*>(value->GetBlob().data());
|
||||
size_t length = value->GetBlob().size();
|
||||
|
||||
if (NodeBindings::IsInitialized()) {
|
||||
return node::Buffer::Copy(isolate, data, length).ToLocalChecked();
|
||||
}
|
||||
|
||||
if (length > node::Buffer::kMaxLength) {
|
||||
return v8::Local<v8::Object>();
|
||||
}
|
||||
auto context = isolate->GetCurrentContext();
|
||||
auto array_buffer = v8::ArrayBuffer::New(isolate, length);
|
||||
memcpy(array_buffer->GetContents().Data(), data, length);
|
||||
// From this point, if something goes wrong(can't find Buffer class for
|
||||
// example) we'll simply return a Uint8Array based on the created ArrayBuffer.
|
||||
// This can happen if no preload script was specified to the renderer.
|
||||
mate::Dictionary global(isolate, context->Global());
|
||||
v8::Local<v8::Value> buffer_value;
|
||||
|
||||
// Get the Buffer class stored as a hidden value in the global object. We'll
|
||||
// use it return a browserified Buffer.
|
||||
if (!global.GetHidden("Buffer", &buffer_value) ||
|
||||
!buffer_value->IsFunction()) {
|
||||
return v8::Uint8Array::New(array_buffer, 0, length);
|
||||
}
|
||||
|
||||
mate::Dictionary buffer_class(
|
||||
isolate,
|
||||
buffer_value->ToObject(isolate->GetCurrentContext()).ToLocalChecked());
|
||||
v8::Local<v8::Value> from_value;
|
||||
if (!buffer_class.Get("from", &from_value) || !from_value->IsFunction()) {
|
||||
return v8::Uint8Array::New(array_buffer, 0, length);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> args[] = {array_buffer};
|
||||
auto func = v8::Local<v8::Function>::Cast(from_value);
|
||||
auto result = func->Call(context, v8::Null(isolate), 1, args);
|
||||
if (!result.IsEmpty()) {
|
||||
return result.ToLocalChecked();
|
||||
}
|
||||
|
||||
return v8::Uint8Array::New(array_buffer, 0, length);
|
||||
}
|
||||
|
||||
std::unique_ptr<base::Value> V8ValueConverter::FromV8ValueImpl(
|
||||
FromV8ValueState* state,
|
||||
v8::Local<v8::Value> val,
|
||||
v8::Isolate* isolate) const {
|
||||
FromV8ValueState::Level state_level(state);
|
||||
if (state->HasReachedMaxRecursionDepth())
|
||||
return nullptr;
|
||||
|
||||
if (val->IsExternal())
|
||||
return std::make_unique<base::Value>();
|
||||
|
||||
if (val->IsNull())
|
||||
return std::make_unique<base::Value>();
|
||||
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
if (val->IsBoolean())
|
||||
return std::make_unique<base::Value>(val->ToBoolean(isolate)->Value());
|
||||
|
||||
if (val->IsInt32())
|
||||
return std::make_unique<base::Value>(val.As<v8::Int32>()->Value());
|
||||
|
||||
if (val->IsNumber()) {
|
||||
double val_as_double = val.As<v8::Number>()->Value();
|
||||
if (!std::isfinite(val_as_double))
|
||||
return nullptr;
|
||||
return std::make_unique<base::Value>(val_as_double);
|
||||
}
|
||||
|
||||
if (val->IsString()) {
|
||||
v8::String::Utf8Value utf8(isolate, val);
|
||||
return std::make_unique<base::Value>(std::string(*utf8, utf8.length()));
|
||||
}
|
||||
|
||||
if (val->IsUndefined())
|
||||
// JSON.stringify ignores undefined.
|
||||
return nullptr;
|
||||
|
||||
if (val->IsDate()) {
|
||||
v8::Date* date = v8::Date::Cast(*val);
|
||||
v8::Local<v8::Value> toISOString =
|
||||
date->Get(context, v8::String::NewFromUtf8(isolate, "toISOString",
|
||||
v8::NewStringType::kNormal)
|
||||
.ToLocalChecked())
|
||||
.ToLocalChecked();
|
||||
if (toISOString->IsFunction()) {
|
||||
v8::MaybeLocal<v8::Value> result =
|
||||
toISOString.As<v8::Function>()->Call(context, val, 0, nullptr);
|
||||
if (!result.IsEmpty()) {
|
||||
v8::String::Utf8Value utf8(isolate, result.ToLocalChecked());
|
||||
return std::make_unique<base::Value>(std::string(*utf8, utf8.length()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (val->IsRegExp()) {
|
||||
if (!reg_exp_allowed_)
|
||||
// JSON.stringify converts to an object.
|
||||
return FromV8Object(val.As<v8::Object>(), state, isolate);
|
||||
return std::make_unique<base::Value>(*v8::String::Utf8Value(isolate, val));
|
||||
}
|
||||
|
||||
// v8::Value doesn't have a ToArray() method for some reason.
|
||||
if (val->IsArray())
|
||||
return FromV8Array(val.As<v8::Array>(), state, isolate);
|
||||
|
||||
if (val->IsFunction()) {
|
||||
if (!function_allowed_)
|
||||
// JSON.stringify refuses to convert function(){}.
|
||||
return nullptr;
|
||||
return FromV8Object(val.As<v8::Object>(), state, isolate);
|
||||
}
|
||||
|
||||
if (node::Buffer::HasInstance(val)) {
|
||||
return FromNodeBuffer(val, state, isolate);
|
||||
}
|
||||
|
||||
if (val->IsObject()) {
|
||||
return FromV8Object(val.As<v8::Object>(), state, isolate);
|
||||
}
|
||||
|
||||
LOG(ERROR) << "Unexpected v8 value type encountered.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<base::Value> V8ValueConverter::FromV8Array(
|
||||
v8::Local<v8::Array> val,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const {
|
||||
ScopedUniquenessGuard uniqueness_guard(state, val);
|
||||
if (!uniqueness_guard.is_valid())
|
||||
return std::make_unique<base::Value>();
|
||||
|
||||
std::unique_ptr<v8::Context::Scope> scope;
|
||||
// If val was created in a different context than our current one, change to
|
||||
// that context, but change back after val is converted.
|
||||
if (!val->CreationContext().IsEmpty() &&
|
||||
val->CreationContext() != isolate->GetCurrentContext())
|
||||
scope.reset(new v8::Context::Scope(val->CreationContext()));
|
||||
|
||||
std::unique_ptr<base::ListValue> result(new base::ListValue());
|
||||
|
||||
// Only fields with integer keys are carried over to the ListValue.
|
||||
for (uint32_t i = 0; i < val->Length(); ++i) {
|
||||
v8::TryCatch try_catch(isolate);
|
||||
v8::Local<v8::Value> child_v8;
|
||||
v8::MaybeLocal<v8::Value> maybe_child =
|
||||
val->Get(isolate->GetCurrentContext(), i);
|
||||
if (try_catch.HasCaught() || !maybe_child.ToLocal(&child_v8)) {
|
||||
LOG(ERROR) << "Getter for index " << i << " threw an exception.";
|
||||
child_v8 = v8::Null(isolate);
|
||||
}
|
||||
|
||||
if (!val->HasRealIndexedProperty(isolate->GetCurrentContext(), i)
|
||||
.FromMaybe(false)) {
|
||||
result->Append(std::make_unique<base::Value>());
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<base::Value> child =
|
||||
FromV8ValueImpl(state, child_v8, isolate);
|
||||
if (child)
|
||||
result->Append(std::move(child));
|
||||
else
|
||||
// JSON.stringify puts null in places where values don't serialize, for
|
||||
// example undefined and functions. Emulate that behavior.
|
||||
result->Append(std::make_unique<base::Value>());
|
||||
}
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
std::unique_ptr<base::Value> V8ValueConverter::FromNodeBuffer(
|
||||
v8::Local<v8::Value> value,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const {
|
||||
std::vector<char> buffer(
|
||||
node::Buffer::Data(value),
|
||||
node::Buffer::Data(value) + node::Buffer::Length(value));
|
||||
return std::make_unique<base::Value>(std::move(buffer));
|
||||
}
|
||||
|
||||
std::unique_ptr<base::Value> V8ValueConverter::FromV8Object(
|
||||
v8::Local<v8::Object> val,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const {
|
||||
ScopedUniquenessGuard uniqueness_guard(state, val);
|
||||
if (!uniqueness_guard.is_valid())
|
||||
return std::make_unique<base::Value>();
|
||||
|
||||
std::unique_ptr<v8::Context::Scope> scope;
|
||||
// If val was created in a different context than our current one, change to
|
||||
// that context, but change back after val is converted.
|
||||
if (!val->CreationContext().IsEmpty() &&
|
||||
val->CreationContext() != isolate->GetCurrentContext())
|
||||
scope.reset(new v8::Context::Scope(val->CreationContext()));
|
||||
|
||||
auto result = std::make_unique<base::DictionaryValue>();
|
||||
v8::Local<v8::Array> property_names;
|
||||
if (!val->GetOwnPropertyNames(isolate->GetCurrentContext())
|
||||
.ToLocal(&property_names)) {
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < property_names->Length(); ++i) {
|
||||
v8::Local<v8::Value> key =
|
||||
property_names->Get(isolate->GetCurrentContext(), i).ToLocalChecked();
|
||||
|
||||
// Extend this test to cover more types as necessary and if sensible.
|
||||
if (!key->IsString() && !key->IsNumber()) {
|
||||
NOTREACHED() << "Key \"" << *v8::String::Utf8Value(isolate, key)
|
||||
<< "\" "
|
||||
"is neither a string nor a number";
|
||||
continue;
|
||||
}
|
||||
|
||||
v8::String::Utf8Value name_utf8(isolate, key);
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
v8::Local<v8::Value> child_v8;
|
||||
v8::MaybeLocal<v8::Value> maybe_child =
|
||||
val->Get(isolate->GetCurrentContext(), key);
|
||||
if (try_catch.HasCaught() || !maybe_child.ToLocal(&child_v8)) {
|
||||
LOG(ERROR) << "Getter for property " << *name_utf8
|
||||
<< " threw an exception.";
|
||||
child_v8 = v8::Null(isolate);
|
||||
}
|
||||
|
||||
std::unique_ptr<base::Value> child =
|
||||
FromV8ValueImpl(state, child_v8, isolate);
|
||||
if (!child)
|
||||
// JSON.stringify skips properties whose values don't serialize, for
|
||||
// example undefined and functions. Emulate that behavior.
|
||||
continue;
|
||||
|
||||
// Strip null if asked (and since undefined is turned into null, undefined
|
||||
// too). The use case for supporting this is JSON-schema support,
|
||||
// specifically for extensions, where "optional" JSON properties may be
|
||||
// represented as null, yet due to buggy legacy code elsewhere isn't
|
||||
// treated as such (potentially causing crashes). For example, the
|
||||
// "tabs.create" function takes an object as its first argument with an
|
||||
// optional "windowId" property.
|
||||
//
|
||||
// Given just
|
||||
//
|
||||
// tabs.create({})
|
||||
//
|
||||
// this will work as expected on code that only checks for the existence of
|
||||
// a "windowId" property (such as that legacy code). However given
|
||||
//
|
||||
// tabs.create({windowId: null})
|
||||
//
|
||||
// there *is* a "windowId" property, but since it should be an int, code
|
||||
// on the browser which doesn't additionally check for null will fail.
|
||||
// We can avoid all bugs related to this by stripping null.
|
||||
if (strip_null_from_objects_ && child->is_none())
|
||||
continue;
|
||||
|
||||
result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()),
|
||||
std::move(child));
|
||||
}
|
||||
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
} // namespace atom
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue