Merge branch 'master' into desktop-capture-api

This commit is contained in:
Cheng Zhao 2015-12-08 12:43:44 +08:00
commit 04f7ceab73
464 changed files with 18563 additions and 4629 deletions

View file

@ -30,6 +30,12 @@ IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync,
base::ListValue /* arguments */,
base::string16 /* result (in JSON) */)
IPC_MESSAGE_ROUTED1(AtomViewHostMsg_ZoomLevelChanged,
double /* level */)
IPC_MESSAGE_ROUTED1(AtomViewMsg_SetZoomLevel,
double /* level */)
IPC_MESSAGE_ROUTED2(AtomViewMsg_Message,
base::string16 /* channel */,
base::ListValue /* arguments */)

View file

@ -18,6 +18,8 @@
namespace {
v8::Persistent<v8::ObjectTemplate> template_;
class Archive : public mate::Wrappable {
public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate,
@ -101,15 +103,20 @@ class Archive : public mate::Wrappable {
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetValue("path", archive_->path())
.SetMethod("getFileInfo", &Archive::GetFileInfo)
.SetMethod("stat", &Archive::Stat)
.SetMethod("readdir", &Archive::Readdir)
.SetMethod("realpath", &Archive::Realpath)
.SetMethod("copyFileOut", &Archive::CopyFileOut)
.SetMethod("getFd", &Archive::GetFD)
.SetMethod("destroy", &Archive::Destroy);
if (template_.IsEmpty())
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
.SetValue("path", archive_->path())
.SetMethod("getFileInfo", &Archive::GetFileInfo)
.SetMethod("stat", &Archive::Stat)
.SetMethod("readdir", &Archive::Readdir)
.SetMethod("realpath", &Archive::Realpath)
.SetMethod("copyFileOut", &Archive::CopyFileOut)
.SetMethod("getFd", &Archive::GetFD)
.SetMethod("destroy", &Archive::Destroy)
.Build());
return mate::ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
}
private:

View 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.
#include "atom/common/api/atom_api_id_weak_map.h"
#include "atom/common/node_includes.h"
#include "native_mate/constructor.h"
#include "native_mate/dictionary.h"
namespace atom {
namespace api {
IDWeakMap::IDWeakMap() {
}
IDWeakMap::~IDWeakMap() {
}
void IDWeakMap::Set(v8::Isolate* isolate,
int32_t id,
v8::Local<v8::Object> object) {
id_weak_map_.Set(isolate, id, object);
}
v8::Local<v8::Object> IDWeakMap::Get(v8::Isolate* isolate, int32_t id) {
return id_weak_map_.Get(isolate, id).ToLocalChecked();
}
bool IDWeakMap::Has(int32_t id) {
return id_weak_map_.Has(id);
}
void IDWeakMap::Remove(int32_t id) {
id_weak_map_.Remove(id);
}
void IDWeakMap::Clear() {
id_weak_map_.Clear();
}
// static
void IDWeakMap::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("set", &IDWeakMap::Set)
.SetMethod("get", &IDWeakMap::Get)
.SetMethod("has", &IDWeakMap::Has)
.SetMethod("remove", &IDWeakMap::Remove)
.SetMethod("clear", &IDWeakMap::Clear);
}
// static
mate::Wrappable* IDWeakMap::Create(v8::Isolate* isolate) {
return new IDWeakMap;
}
} // namespace api
} // namespace atom
namespace {
using atom::api::IDWeakMap;
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::Function> constructor = mate::CreateConstructor<IDWeakMap>(
isolate, "IDWeakMap", base::Bind(&IDWeakMap::Create));
mate::Dictionary id_weak_map(isolate, constructor);
mate::Dictionary dict(isolate, exports);
dict.Set("IDWeakMap", id_weak_map);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_id_weak_map, Initialize)

View file

@ -0,0 +1,44 @@
// 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_ID_WEAK_MAP_H_
#define ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_
#include "atom/common/id_weak_map.h"
#include "native_mate/object_template_builder.h"
#include "native_mate/handle.h"
namespace atom {
namespace api {
class IDWeakMap : public mate::Wrappable {
public:
static mate::Wrappable* Create(v8::Isolate* isolate);
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected:
IDWeakMap();
~IDWeakMap();
private:
// Api for IDWeakMap.
void Set(v8::Isolate* isolate, int32_t id, v8::Local<v8::Object> object);
v8::Local<v8::Object> Get(v8::Isolate* isolate, int32_t id);
bool Has(int32_t id);
void Remove(int32_t id);
void Clear();
atom::IDWeakMap id_weak_map_;
DISALLOW_COPY_AND_ASSIGN(IDWeakMap);
};
} // namespace api
} // namespace atom
#endif // ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_

View file

@ -63,7 +63,8 @@ float GetScaleFactorFromPath(const base::FilePath& path) {
// We don't try to convert string to float here because it is very very
// expensive.
for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) {
if (base::EndsWith(filename, kScaleFactorPairs[i].name, true))
if (base::EndsWith(filename, kScaleFactorPairs[i].name,
base::CompareCase::INSENSITIVE_ASCII))
return kScaleFactorPairs[i].scale;
}
@ -168,7 +169,8 @@ mate::ObjectTemplateBuilder NativeImage::GetObjectTemplateBuilder(
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
.SetMethod("toPng", &NativeImage::ToPNG)
.SetMethod("toJpeg", &NativeImage::ToJPEG)
.SetMethod("toDataUrl", &NativeImage::ToDataURL)
.SetMethod("toDataURL", &NativeImage::ToDataURL)
.SetMethod("toDataUrl", &NativeImage::ToDataURL) // deprecated.
.SetMethod("isEmpty", &NativeImage::IsEmpty)
.SetMethod("getSize", &NativeImage::GetSize)
.SetMethod("setTemplateImage", &NativeImage::SetTemplateImage)
@ -309,7 +311,7 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
dict.SetMethod("createEmpty", &atom::api::NativeImage::CreateEmpty);
dict.SetMethod("createFromPath", &atom::api::NativeImage::CreateFromPath);
dict.SetMethod("createFromBuffer", &atom::api::NativeImage::CreateFromBuffer);
dict.SetMethod("createFromDataUrl",
dict.SetMethod("createFromDataURL",
&atom::api::NativeImage::CreateFromDataURL);
}

View file

@ -6,6 +6,7 @@
#include <algorithm>
#include <string>
#include <iostream>
#include "atom/common/atom_version.h"
#include "atom/common/chrome_version.h"
@ -40,7 +41,7 @@ void FatalErrorCallback(const char* location, const char* message) {
}
void Log(const base::string16& message) {
logging::LogMessage("CONSOLE", 0, 0).stream() << message;
std::cout << message << std::flush;
}
} // namespace
@ -68,8 +69,9 @@ void AtomBindings::BindTo(v8::Isolate* isolate,
dict.SetMethod("activateUvLoop",
base::Bind(&AtomBindings::ActivateUVLoop, base::Unretained(this)));
// Do not warn about deprecated APIs.
dict.Set("noDeprecation", true);
#if defined(MAS_BUILD)
dict.Set("mas", true);
#endif
mate::Dictionary versions;
if (dict.Get("versions", &versions)) {

View file

@ -19,7 +19,7 @@ v8::Local<v8::Value> CallEmitWithArgs(v8::Isolate* isolate,
// Perform microtask checkpoint after running JavaScript.
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate));
nullptr : new blink::WebScopedRunV8Script);
// Use node::MakeCallback to call the callback, and it will also run pending
// tasks in Node.js.
return node::MakeCallback(

View file

@ -1,27 +1,43 @@
savedGlobal = global # the "global.global" might be deleted later
v8Util = process.atomBinding 'v8_util'
module.exports =
class CallbacksRegistry
constructor: ->
@emptyFunc = -> throw new Error "Browser trying to call a non-exist callback
in renderer, this usually happens when renderer code forgot to release
a callback installed on objects in browser when renderer was going to be
unloaded or released."
@nextId = 0
@callbacks = {}
add: (callback) ->
id = Math.random().toString()
# The callback is already added.
id = v8Util.getHiddenValue callback, 'callbackId'
return id if id?
id = ++@nextId
# Capture the location of the function and put it in the ID string,
# so that release errors can be tracked down easily.
regexp = /at (.*)/gi
stackString = (new Error).stack
while (match = regexp.exec(stackString)) isnt null
[x, location] = match
continue if location.indexOf('(native)') isnt -1
continue if location.indexOf('atom.asar') isnt -1
[x, filenameAndLine] = /([^/^\)]*)\)?$/gi.exec(location)
break
@callbacks[id] = callback
v8Util.setHiddenValue callback, 'callbackId', id
v8Util.setHiddenValue callback, 'location', filenameAndLine
id
get: (id) ->
@callbacks[id] ? ->
call: (id, args...) ->
@get(id).call savedGlobal, args...
@get(id).call global, args...
apply: (id, args...) ->
@get(id).apply savedGlobal, args...
@get(id).apply global, args...
remove: (id) ->
delete @callbacks[id]

View file

@ -1,5 +1,5 @@
if process.platform is 'linux' and process.type is 'renderer'
# On Linux we could not access clipboard in renderer process.
module.exports = require('remote').require 'clipboard'
module.exports = require('electron').remote.clipboard
else
module.exports = process.atomBinding 'clipboard'

View file

@ -1,22 +1,26 @@
binding = process.atomBinding 'crash_reporter'
fs = require 'fs'
os = require 'os'
path = require 'path'
{spawn} = require 'child_process'
electron = require 'electron'
binding = process.atomBinding 'crash_reporter'
class CrashReporter
start: (options={}) ->
{@productName, companyName, submitUrl, autoSubmit, ignoreSystemCrashHandler, extra} = options
{@productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra} = options
app =
if process.type is 'browser'
require 'app'
else
require('remote').require 'app'
# Deprecated.
{deprecate} = electron
if options.submitUrl
submitURL ?= options.submitUrl
deprecate.warn 'submitUrl', 'submitURL'
{app} = if process.type is 'browser' then electron else electron.remote
@productName ?= app.getName()
companyName ?= 'GitHub, Inc'
submitUrl ?= 'http://54.249.141.255:1127/post'
submitURL ?= 'http://54.249.141.255:1127/post'
autoSubmit ?= true
ignoreSystemCrashHandler ?= false
extra ?= {}
@ -25,11 +29,11 @@ class CrashReporter
extra._companyName ?= companyName
extra._version ?= app.getVersion()
start = => binding.start @productName, companyName, submitUrl, autoSubmit, ignoreSystemCrashHandler, extra
start = => binding.start @productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra
if process.platform is 'win32'
args = [
"--reporter-url=#{submitUrl}"
"--reporter-url=#{submitURL}"
"--application-name=#{@productName}"
"--v=1"
]

View file

@ -0,0 +1,65 @@
# Deprecate a method.
deprecate = (oldName, newName, fn) ->
warned = false
->
unless warned or process.noDeprecation
warned = true
deprecate.warn oldName, newName
fn.apply this, arguments
# The method is renamed.
deprecate.rename = (object, oldName, newName) ->
warned = false
newMethod = ->
unless warned or process.noDeprecation
warned = true
deprecate.warn oldName, newName
this[newName].apply this, arguments
if typeof object is 'function'
object.prototype[oldName] = newMethod
else
object[oldName] = newMethod
# Forward the method to member.
deprecate.member = (object, method, member) ->
warned = false
object.prototype[method] = ->
unless warned or process.noDeprecation
warned = true
deprecate.warn method, "#{member}.#{method}"
this[member][method].apply this[member], arguments
# Deprecate a property.
deprecate.property = (object, property, method) ->
Object.defineProperty object, property,
get: ->
warned = false
unless warned or process.noDeprecation
warned = true
deprecate.warn "#{property} property", "#{method} method"
this[method]()
# Deprecate an event.
deprecate.event = (emitter, oldName, newName, fn) ->
warned = false
emitter.on newName, (args...) ->
if @listenerCount(oldName) > 0 # there is listeners for old API.
unless warned or process.noDeprecation
warned = true
deprecate.warn "'#{oldName}' event", "'#{newName}' event"
if fn?
fn.apply this, arguments
else
@emit oldName, args...
# Print deprecate warning.
deprecate.warn = (oldName, newName) ->
message = "#{oldName} is deprecated. Use #{newName} instead."
if process.throwDeprecation
throw new Error(message)
else if process.traceDeprecation
console.trace message
else
console.warn "(electron) #{message}"
module.exports = deprecate

View file

@ -0,0 +1,27 @@
# Do not expose the internal modules to `require`.
exports.hideInternalModules = ->
{globalPaths} = require 'module'
if globalPaths.length is 3
# Remove the "common/api/lib" and "browser-or-renderer/api/lib".
globalPaths.splice 0, 2
Object.defineProperties exports,
# Common modules, please sort with alphabet order.
clipboard:
# Must be enumerable, otherwise it woulde be invisible to remote module.
enumerable: true
get: -> require '../clipboard'
crashReporter:
enumerable: true
get: -> require '../crash-reporter'
nativeImage:
enumerable: true
get: -> require '../native-image'
shell:
enumerable: true
get: -> require '../shell'
# The internal modules, invisible unless you know their names.
CallbacksRegistry:
get: -> require '../callbacks-registry'
deprecate:
get: -> require '../deprecate'

View file

@ -1 +1,7 @@
module.exports = process.atomBinding 'native_image'
{deprecate} = require 'electron'
nativeImage = process.atomBinding 'native_image'
# Deprecated.
deprecate.rename nativeImage, 'createFromDataUrl', 'createFromDataURL'
module.exports = nativeImage

View file

@ -1,4 +1 @@
module.exports = process.atomBinding 'shell'
if process.platform is 'win32' and process.type is 'renderer'
module.exports.showItemInFolder = require('remote').process.atomBinding('shell').showItemInFolder

View file

@ -13,6 +13,7 @@
#include "atom/common/asar/scoped_temporary_file.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/pickle.h"
#include "base/json/json_reader.h"
@ -96,7 +97,6 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
return false;
info->size = static_cast<uint32>(size);
info->unpacked = false;
if (node->GetBoolean("unpacked", &info->unpacked) && info->unpacked)
return true;
@ -107,6 +107,8 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
return false;
info->offset += header_size;
node->GetBoolean("executable", &info->executable);
return true;
}
@ -270,9 +272,17 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
}
scoped_ptr<ScopedTemporaryFile> temp_file(new ScopedTemporaryFile);
if (!temp_file->InitFromFile(&file_, info.offset, info.size))
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_.set(path, temp_file.Pass());
return true;

View file

@ -25,8 +25,9 @@ class ScopedTemporaryFile;
class Archive {
public:
struct FileInfo {
FileInfo() : size(0), offset(0) {}
FileInfo() : unpacked(false), executable(false), size(0), offset(0) {}
bool unpacked;
bool executable;
uint32 size;
uint64 offset;
};

View file

@ -28,20 +28,34 @@ ScopedTemporaryFile::~ScopedTemporaryFile() {
}
}
bool ScopedTemporaryFile::Init() {
bool ScopedTemporaryFile::Init(const base::FilePath::StringType& ext) {
if (!path_.empty())
return true;
base::ThreadRestrictions::ScopedAllowIO allow_io;
return base::CreateTemporaryFile(&path_);
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 offset, uint64 size) {
if (!src->IsValid())
return false;
if (!Init())
if (!Init(ext))
return false;
std::vector<char> buf(size);

View file

@ -22,11 +22,13 @@ class ScopedTemporaryFile {
ScopedTemporaryFile();
virtual ~ScopedTemporaryFile();
// Init an empty temporary file.
bool Init();
// 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, uint64 offset, uint64 size);
bool InitFromFile(base::File* src,
const base::FilePath::StringType& ext,
uint64 offset, uint64 size);
base::FilePath path() const { return path_; }

View file

@ -0,0 +1,11 @@
// 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* kCORSHeader = "Access-Control-Allow-Origin: *";
} // namespace atom

View file

@ -0,0 +1,15 @@
// 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_
namespace atom {
// Header to ignore CORS.
extern const char* kCORSHeader;
} // namespace atom
#endif // ATOM_COMMON_ATOM_CONSTANTS_H_

View file

@ -6,8 +6,8 @@
#define ATOM_VERSION_H
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 33
#define ATOM_PATCH_VERSION 1
#define ATOM_MINOR_VERSION 35
#define ATOM_PATCH_VERSION 4
#define ATOM_VERSION_IS_RELEASE 1

View file

@ -8,7 +8,7 @@
#ifndef ATOM_COMMON_CHROME_VERSION_H_
#define ATOM_COMMON_CHROME_VERSION_H_
#define CHROME_VERSION_STRING "45.0.2454.85"
#define CHROME_VERSION_STRING "47.0.2526.73"
#define CHROME_VERSION "v" CHROME_VERSION_STRING
#endif // ATOM_COMMON_CHROME_VERSION_H_

View file

@ -48,11 +48,11 @@ CrashReporter::GetUploadedReports(const std::string& path) {
std::vector<CrashReporter::UploadReportResult> result;
if (base::ReadFileToString(base::FilePath::FromUTF8Unsafe(path),
&file_content)) {
std::vector<std::string> reports;
base::SplitString(file_content, '\n', &reports);
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, ',', &report_item);
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)) {
@ -64,4 +64,23 @@ CrashReporter::GetUploadedReports(const std::string& path) {
return result;
}
void CrashReporter::InitBreakpad(const std::string& product_name,
const std::string& version,
const std::string& company_name,
const std::string& submit_url,
bool auto_submit,
bool skip_system_crash_handler) {
}
void CrashReporter::SetUploadParameters() {
}
#if defined(OS_MACOSX) && defined(MAS_BUILD)
// static
CrashReporter* CrashReporter::GetInstance() {
static CrashReporter crash_reporter;
return &crash_reporter;
}
#endif
} // namespace crash_reporter

View file

@ -40,8 +40,8 @@ class CrashReporter {
const std::string& company_name,
const std::string& submit_url,
bool auto_submit,
bool skip_system_crash_handler) = 0;
virtual void SetUploadParameters() = 0;
bool skip_system_crash_handler);
virtual void SetUploadParameters();
StringMap upload_parameters_;
bool is_browser_;

View file

@ -130,7 +130,7 @@ bool CrashReporterLinux::CrashDone(const MinidumpDescriptor& minidump,
// static
CrashReporterLinux* CrashReporterLinux::GetInstance() {
return Singleton<CrashReporterLinux>::get();
return base::Singleton<CrashReporterLinux>::get();
}
// static

View file

@ -12,7 +12,9 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
namespace base {
template <typename T> struct DefaultSingletonTraits;
}
namespace google_breakpad {
class ExceptionHandler;
@ -34,7 +36,7 @@ class CrashReporterLinux : public CrashReporter {
void SetUploadParameters() override;
private:
friend struct DefaultSingletonTraits<CrashReporterLinux>;
friend struct base::DefaultSingletonTraits<CrashReporterLinux>;
CrashReporterLinux();
virtual ~CrashReporterLinux();

View file

@ -14,7 +14,9 @@
#include "base/strings/string_piece.h"
#include "vendor/crashpad/client/simple_string_dictionary.h"
namespace base {
template <typename T> struct DefaultSingletonTraits;
}
namespace crash_reporter {
@ -31,7 +33,7 @@ class CrashReporterMac : public CrashReporter {
void SetUploadParameters() override;
private:
friend struct DefaultSingletonTraits<CrashReporterMac>;
friend struct base::DefaultSingletonTraits<CrashReporterMac>;
CrashReporterMac();
virtual ~CrashReporterMac();

View file

@ -126,7 +126,7 @@ CrashReporterMac::GetUploadedReports(const std::string& path) {
// static
CrashReporterMac* CrashReporterMac::GetInstance() {
return Singleton<CrashReporterMac>::get();
return base::Singleton<CrashReporterMac>::get();
}
// static

View file

@ -11,6 +11,25 @@
#include "base/memory/singleton.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/result_codes.h"
#include "gin/public/debug.h"
#include "sandbox/win/src/nt_internals.h"
#pragma intrinsic(_AddressOfReturnAddress)
#pragma intrinsic(_ReturnAddress)
#ifdef _WIN64
// See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
typedef struct _UNWIND_INFO {
unsigned char Version : 3;
unsigned char Flags : 5;
unsigned char SizeOfProlog;
unsigned char CountOfCodes;
unsigned char FrameRegister : 4;
unsigned char FrameOffset : 4;
ULONG ExceptionHandler;
} UNWIND_INFO, *PUNWIND_INFO;
#endif
namespace crash_reporter {
@ -24,6 +43,94 @@ const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
NTSTATUS ExitStatus);
char* g_real_terminate_process_stub = NULL;
void TerminateProcessWithoutDump() {
// Patched stub exists based on conditions (See InitCrashReporter).
// As a side note this function also gets called from
// WindowProcExceptionFilter.
if (g_real_terminate_process_stub == NULL) {
::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
} else {
NtTerminateProcessPtr real_terminate_proc =
reinterpret_cast<NtTerminateProcessPtr>(
static_cast<char*>(g_real_terminate_process_stub));
real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
}
}
#ifdef _WIN64
int CrashForExceptionInNonABICompliantCodeRange(
PEXCEPTION_RECORD ExceptionRecord,
ULONG64 EstablisherFrame,
PCONTEXT ContextRecord,
PDISPATCHER_CONTEXT DispatcherContext) {
EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord };
if (!CrashReporter::GetInstance())
return EXCEPTION_CONTINUE_SEARCH;
return static_cast<CrashReporterWin*>(CrashReporter::GetInstance())->
CrashForException(&info);
}
struct ExceptionHandlerRecord {
RUNTIME_FUNCTION runtime_function;
UNWIND_INFO unwind_info;
unsigned char thunk[12];
};
bool RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start);
// We assume that the first page of the code range is executable and
// committed and reserved for breakpad. What could possibly go wrong?
// All addresses are 32bit relative offsets to start.
record->runtime_function.BeginAddress = 0;
record->runtime_function.EndAddress =
base::checked_cast<DWORD>(size_in_bytes);
record->runtime_function.UnwindData =
offsetof(ExceptionHandlerRecord, unwind_info);
// Create unwind info that only specifies an exception handler.
record->unwind_info.Version = 1;
record->unwind_info.Flags = UNW_FLAG_EHANDLER;
record->unwind_info.SizeOfProlog = 0;
record->unwind_info.CountOfCodes = 0;
record->unwind_info.FrameRegister = 0;
record->unwind_info.FrameOffset = 0;
record->unwind_info.ExceptionHandler =
offsetof(ExceptionHandlerRecord, thunk);
// Hardcoded thunk.
// mov imm64, rax
record->thunk[0] = 0x48;
record->thunk[1] = 0xb8;
void* handler = &CrashForExceptionInNonABICompliantCodeRange;
memcpy(&record->thunk[2], &handler, 8);
// jmp rax
record->thunk[10] = 0xff;
record->thunk[11] = 0xe0;
// Protect reserved page against modifications.
DWORD old_protect;
return VirtualProtect(start, sizeof(ExceptionHandlerRecord),
PAGE_EXECUTE_READ, &old_protect) &&
RtlAddFunctionTable(&record->runtime_function, 1,
reinterpret_cast<DWORD64>(start));
}
void UnregisterNonABICompliantCodeRange(void* start) {
ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start);
RtlDeleteFunctionTable(&record->runtime_function);
}
#endif // _WIN64
} // namespace
CrashReporterWin::CrashReporterWin() {
@ -46,9 +153,9 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
return;
}
base::string16 pipe_name = ReplaceStringPlaceholders(
base::string16 pipe_name = base::ReplaceStringPlaceholders(
kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL);
base::string16 wait_name = ReplaceStringPlaceholders(
base::string16 wait_name = base::ReplaceStringPlaceholders(
kWaitEventFormat, base::UTF8ToUTF16(product_name), NULL);
// Wait until the crash service is started.
@ -63,26 +170,48 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
// to allow any previous handler to detach in the correct order.
breakpad_.reset();
int handler_types = google_breakpad::ExceptionHandler::HANDLER_EXCEPTION |
google_breakpad::ExceptionHandler::HANDLER_PURECALL;
breakpad_.reset(new google_breakpad::ExceptionHandler(
temp_dir.value(),
FilterCallback,
MinidumpCallback,
this,
handler_types,
google_breakpad::ExceptionHandler::HANDLER_ALL,
kSmallDumpType,
pipe_name.c_str(),
GetCustomInfo(product_name, version, company_name)));
if (!breakpad_->IsOutOfProcess())
LOG(ERROR) << "Cannot initialize out-of-process crash handler";
#ifdef _WIN64
bool registered = false;
// Hook up V8 to breakpad.
{
// gin::Debug::SetCodeRangeCreatedCallback only runs the callback when
// Isolate is just created, so we have to manually run following code here.
void* code_range = nullptr;
size_t size = 0;
v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size);
if (code_range && size)
registered = RegisterNonABICompliantCodeRange(code_range, size);
}
if (registered)
gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange);
#endif
}
void CrashReporterWin::SetUploadParameters() {
upload_parameters_["platform"] = "win32";
}
int CrashReporterWin::CrashForException(EXCEPTION_POINTERS* info) {
if (breakpad_) {
breakpad_->WriteMinidumpForException(info);
TerminateProcessWithoutDump();
}
return EXCEPTION_CONTINUE_SEARCH;
}
// static
bool CrashReporterWin::FilterCallback(void* context,
EXCEPTION_POINTERS* exinfo,
@ -130,7 +259,7 @@ google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo(
// static
CrashReporterWin* CrashReporterWin::GetInstance() {
return Singleton<CrashReporterWin>::get();
return base::Singleton<CrashReporterWin>::get();
}
// static

View file

@ -13,7 +13,9 @@
#include "base/memory/scoped_ptr.h"
#include "vendor/breakpad/src/client/windows/handler/exception_handler.h"
namespace base {
template <typename T> struct DefaultSingletonTraits;
}
namespace crash_reporter {
@ -29,8 +31,11 @@ class CrashReporterWin : public CrashReporter {
bool skip_system_crash_handler) override;
void SetUploadParameters() override;
// Crashes the process after generating a dump for the provided exception.
int CrashForException(EXCEPTION_POINTERS* info);
private:
friend struct DefaultSingletonTraits<CrashReporterWin>;
friend struct base::DefaultSingletonTraits<CrashReporterWin>;
CrashReporterWin();
virtual ~CrashReporterWin();

View file

@ -118,7 +118,7 @@ HWND g_top_window = NULL;
bool CreateTopWindow(HINSTANCE instance,
const base::string16& application_name,
bool visible) {
base::string16 class_name = ReplaceStringPlaceholders(
base::string16 class_name = base::ReplaceStringPlaceholders(
kClassNameFormat, application_name, NULL);
WNDCLASSEXW wcx = {0};
@ -309,9 +309,9 @@ bool CrashService::Initialize(const base::string16& application_name,
// Create or open an event to signal the browser process that the crash
// service is initialized.
base::string16 wait_name = ReplaceStringPlaceholders(
base::string16 wait_name = base::ReplaceStringPlaceholders(
kWaitEventFormat, application_name, NULL);
HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
HANDLE wait_event = ::CreateEventW(NULL, TRUE, TRUE, wait_name.c_str());
::SetEvent(wait_event);
return true;
@ -524,4 +524,3 @@ PSECURITY_DESCRIPTOR CrashService::GetSecurityDescriptorForLowIntegrity() {
}
} // namespace breakpad

View file

@ -68,7 +68,7 @@ int Main(const wchar_t* cmd) {
VLOG(1) << "Session start. cmdline is [" << cmd << "]";
// Setting the crash reporter.
base::string16 pipe_name = ReplaceStringPlaceholders(kPipeNameFormat,
base::string16 pipe_name = base::ReplaceStringPlaceholders(kPipeNameFormat,
application_name,
NULL);
cmd_line.AppendSwitch("no-window");

View file

@ -32,12 +32,18 @@ IDWeakMap::IDWeakMap() : next_id_(0) {
IDWeakMap::~IDWeakMap() {
}
int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Local<v8::Object> object) {
int32_t id = GetNextID();
void IDWeakMap::Set(v8::Isolate* isolate,
int32_t id,
v8::Local<v8::Object> object) {
auto global = make_linked_ptr(new v8::Global<v8::Object>(isolate, object));
ObjectKey* key = new ObjectKey(id, this);
global->SetWeak(key, OnObjectGC, v8::WeakCallbackType::kParameter);
map_[id] = global;
}
int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Local<v8::Object> object) {
int32_t id = GetNextID();
Set(isolate, id, object);
return id;
}

View file

@ -19,6 +19,9 @@ class IDWeakMap {
IDWeakMap();
~IDWeakMap();
// Sets the object to WeakMap with the given |id|.
void Set(v8::Isolate* isolate, int32_t id, v8::Local<v8::Object> object);
// Adds |object| to WeakMap and returns its allocated |id|.
int32_t Add(v8::Isolate* isolate, v8::Local<v8::Object> object);

View file

@ -2,17 +2,19 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <string>
#include "atom/common/keyboad_util.h"
namespace atom {
// Return key code of the char.
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
ui::KeyboardCode KeyboardCodeFromCharCode(base::char16 c, bool* shifted) {
*shifted = false;
switch (c) {
case 8: case 0x7F: return ui::VKEY_BACK;
case 9: return ui::VKEY_TAB;
case 0xD: case 3: return ui::VKEY_RETURN;
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;
@ -70,4 +72,28 @@ ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
}
}
// Return key code of the char.
ui::KeyboardCode KeyboardCodeFromKeyIdentifier(const std::string& chr) {
if (chr == "enter") return ui::VKEY_RETURN;
if (chr == "backspace") return ui::VKEY_BACK;
if (chr == "delete") return ui::VKEY_DELETE;
if (chr == "tab") return ui::VKEY_TAB;
if (chr == "escape") return ui::VKEY_ESCAPE;
if (chr == "control") return ui::VKEY_CONTROL;
if (chr == "alt") return ui::VKEY_MENU;
if (chr == "shift") return ui::VKEY_SHIFT;
if (chr == "end") return ui::VKEY_END;
if (chr == "home") return ui::VKEY_HOME;
if (chr == "insert") return ui::VKEY_INSERT;
if (chr == "left") return ui::VKEY_LEFT;
if (chr == "up") return ui::VKEY_UP;
if (chr == "right") return ui::VKEY_RIGHT;
if (chr == "down") return ui::VKEY_DOWN;
if (chr == "pageup") return ui::VKEY_PRIOR;
if (chr == "pagedown") return ui::VKEY_NEXT;
if (chr == "printscreen") return ui::VKEY_SNAPSHOT;
return ui::VKEY_UNKNOWN;
}
} // namespace atom

View file

@ -5,13 +5,18 @@
#ifndef ATOM_COMMON_KEYBOAD_UTIL_H_
#define ATOM_COMMON_KEYBOAD_UTIL_H_
#include <string>
#include "ui/events/keycodes/keyboard_codes.h"
#include "base/strings/string_util.h"
namespace atom {
// Return key code of the char, and also determine whether the SHIFT key is
// pressed.
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted);
ui::KeyboardCode KeyboardCodeFromCharCode(base::char16 c, bool* shifted);
// Return key code of the char from a string representation of the char
ui::KeyboardCode KeyboardCodeFromKeyIdentifier(const std::string& chr);
} // namespace atom

View file

@ -18,6 +18,7 @@ process.on 'exit', ->
# Separate asar package's path from full path.
splitPath = (p) ->
return [false] if process.noAsar # shortcut to disable asar.
return [false] if typeof p isnt 'string'
return [true, p, ''] if p.substr(-5) is '.asar'
p = path.normalize p
@ -254,7 +255,8 @@ exports.wrapFsWithAsar = (fs) ->
openSync = fs.openSync
readFileSync = fs.readFileSync
fs.readFileSync = (p, options) ->
fs.readFileSync = (p, opts) ->
options = opts # this allows v8 to optimize this function
[isAsar, asarPath, filePath] = splitPath p
return readFileSync.apply this, arguments unless isAsar
@ -263,7 +265,9 @@ exports.wrapFsWithAsar = (fs) ->
info = archive.getFileInfo filePath
notFoundError asarPath, filePath unless info
return new Buffer(0) if info.size is 0
if info.size is 0
return if options then '' else new Buffer(0)
if info.unpacked
realPath = archive.copyFileOut filePath
@ -352,3 +356,4 @@ exports.wrapFsWithAsar = (fs) ->
overrideAPISync process, 'dlopen', 1
overrideAPISync require('module')._extensions, '.node', 1
overrideAPISync fs, 'openSync'
overrideAPISync child_process, 'execFileSync'

View file

@ -9,21 +9,9 @@ process.atomBinding = (name) ->
catch e
process.binding "atom_common_#{name}" if /No such module/.test e.message
# Global module search paths.
globalPaths = Module.globalPaths
# Don't lookup modules in user-defined search paths, see http://git.io/vf8sF.
homeDir =
if process.platform is 'win32'
process.env.USERPROFILE
else
process.env.HOME
if homeDir # Node only add user-defined search paths when $HOME is defined.
userModulePath = path.resolve homeDir, '.node_modules'
globalPaths.splice globalPaths.indexOf(userModulePath), 2
# Add common/api/lib to module search paths.
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
unless process.env.ELECTRON_HIDE_INTERNAL_MODULES
# Add common/api/lib to module search paths.
Module.globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
# setImmediate and process.nextTick makes use of uv_check and uv_prepare to
# run the callbacks, however since we only run uv loop on requests, the

View file

@ -0,0 +1,29 @@
path = require 'path'
Module = require 'module'
# Clear Node's global search paths.
Module.globalPaths.length = 0
# Clear current and parent(init.coffee)'s search paths.
module.paths = []
module.parent.paths = []
# Prevent Node from adding paths outside this app to search paths.
Module._nodeModulePaths = (from) ->
from = path.resolve from
# If "from" is outside the app then we do nothing.
skipOutsidePaths = from.startsWith process.resourcesPath
# Following logoic is copied from module.js.
splitRe = if process.platform is 'win32' then /[\/\\]/ else /\//
paths = []
parts = from.split splitRe
for part, tip in parts by -1
continue if part is 'node_modules'
dir = parts.slice(0, tip + 1).join path.sep
break if skipOutsidePaths and not dir.startsWith process.resourcesPath
paths.push path.join(dir, 'node_modules')
paths

View file

@ -9,6 +9,7 @@
#include "atom/common/keyboad_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 "native_mate/dictionary.h"
#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
@ -29,10 +30,10 @@ int VectorToBitArray(const std::vector<T>& vec) {
namespace mate {
template<>
struct Converter<char> {
struct Converter<base::char16> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
char* out) {
std::string code = base::StringToLowerASCII(V8ToString(val));
base::char16* out) {
base::string16 code = base::UTF8ToUTF16(V8ToString(val));
if (code.length() != 1)
return false;
*out = code[0];
@ -44,7 +45,7 @@ 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::StringToLowerASCII(V8ToString(val));
std::string type = base::ToLowerASCII(V8ToString(val));
if (type == "mousedown")
*out = blink::WebInputEvent::MouseDown;
else if (type == "mouseup")
@ -60,7 +61,7 @@ struct Converter<blink::WebInputEvent::Type> {
else if (type == "mousewheel")
*out = blink::WebInputEvent::MouseWheel;
else if (type == "keydown")
*out = blink::WebInputEvent::KeyDown;
*out = blink::WebInputEvent::RawKeyDown;
else if (type == "keyup")
*out = blink::WebInputEvent::KeyUp;
else if (type == "char")
@ -77,11 +78,26 @@ struct Converter<blink::WebInputEvent::Type> {
}
};
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(V8ToString(val));
if (button == "left")
*out = blink::WebMouseEvent::Button::ButtonLeft;
else if (button == "middle")
*out = blink::WebMouseEvent::Button::ButtonMiddle;
else if (button == "right")
*out = blink::WebMouseEvent::Button::ButtonRight;
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::StringToLowerASCII(V8ToString(val));
std::string modifier = base::ToLowerASCII(V8ToString(val));
if (modifier == "shift")
*out = blink::WebInputEvent::ShiftKey;
else if (modifier == "control" || modifier == "ctrl")
@ -142,16 +158,26 @@ bool Converter<blink::WebKeyboardEvent>::FromV8(
return false;
if (!ConvertFromV8(isolate, val, static_cast<blink::WebInputEvent*>(out)))
return false;
char code;
if (!dict.Get("keyCode", &code))
return false;
base::char16 code;
std::string identifier;
bool shifted = false;
out->windowsKeyCode = atom::KeyboardCodeFromCharCode(code, &shifted);
if (out->windowsKeyCode == ui::VKEY_UNKNOWN)
if (dict.Get("keyCode", &code))
out->windowsKeyCode = atom::KeyboardCodeFromCharCode(code, &shifted);
else if (dict.Get("keyCode", &identifier))
out->windowsKeyCode = atom::KeyboardCodeFromKeyIdentifier(
base::ToLowerASCII(identifier));
else
return false;
if (shifted)
out->modifiers |= blink::WebInputEvent::ShiftKey;
out->setKeyIdentifierFromWindowsKeyCode();
if (out->type == blink::WebInputEvent::Char ||
out->type == blink::WebInputEvent::RawKeyDown) {
out->text[0] = code;
out->unmodifiedText[0] = code;
}
return true;
}
@ -176,6 +202,7 @@ bool Converter<blink::WebMouseEvent>::FromV8(
return false;
if (!dict.Get("x", &out->x) || !dict.Get("y", &out->y))
return false;
dict.Get("button", &out->button);
dict.Get("globalX", &out->globalX);
dict.Get("globalY", &out->globalY);
dict.Get("movementX", &out->movementX);
@ -236,7 +263,7 @@ bool Converter<blink::WebDeviceEmulationParams>::FromV8(
std::string screen_position;
if (dict.Get("screenPosition", &screen_position)) {
screen_position = base::StringToLowerASCII(screen_position);
screen_position = base::ToLowerASCII(screen_position);
if (screen_position == "mobile")
out->screenPosition = blink::WebDeviceEmulationParams::Mobile;
else if (screen_position == "desktop")

View file

@ -0,0 +1,137 @@
// 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 "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace mate {
namespace internal {
namespace {
struct TranslaterHolder {
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) {
v8::Isolate* isolate = args->isolate();
// Check if the callback has already been called.
v8::Local<v8::String> called_symbol = mate::StringToSymbol(isolate, "called");
if (state->Has(called_symbol)) {
args->ThrowError("callback can only be called for once");
return;
} else {
state->Set(called_symbol, v8::Boolean::New(isolate, true));
}
TranslaterHolder* holder = static_cast<TranslaterHolder*>(external->Value());
holder->translater.Run(args);
delete holder;
}
// 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(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, arraysize(converted), converted).ToLocalChecked();
}
} // 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) {
// The FunctionTemplate is cached.
if (g_call_translater.IsEmpty())
g_call_translater.Reset(
isolate,
mate::CreateFunctionTemplate(isolate, base::Bind(&CallTranslater)));
v8::Local<v8::FunctionTemplate> call_translater =
v8::Local<v8::FunctionTemplate>::New(isolate, g_call_translater);
TranslaterHolder* holder = new TranslaterHolder;
holder->translater = translater;
return BindFunctionWith(isolate,
isolate->GetCurrentContext(),
call_translater->GetFunction(),
v8::External::New(isolate, holder),
v8::Object::New(isolate));
}
} // namespace internal
} // namespace mate

View file

@ -10,6 +10,7 @@
#include "atom/common/api/locker.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "native_mate/function_template.h"
#include "native_mate/scoped_persistent.h"
#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
@ -18,21 +19,40 @@ namespace mate {
namespace internal {
typedef scoped_refptr<RefCountedPersistent<v8::Function> > SafeV8Function;
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, SafeV8Function function,
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);
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function->NewHandle();
nullptr : new blink::WebScopedRunV8Script);
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, raw)... };
@ -43,14 +63,17 @@ struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
template <typename... ArgTypes>
struct V8FunctionInvoker<void(ArgTypes...)> {
static void Go(v8::Isolate* isolate, SafeV8Function function,
static void Go(v8::Isolate* isolate,
const SafeV8Function& function,
ArgTypes... raw) {
Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (!function.IsAlive())
return;
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function->NewHandle();
nullptr : new blink::WebScopedRunV8Script);
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, raw)... };
@ -60,31 +83,60 @@ struct V8FunctionInvoker<void(ArgTypes...)> {
template <typename ReturnType, typename... ArgTypes>
struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
static ReturnType Go(v8::Isolate* isolate, SafeV8Function function,
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;
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function->NewHandle();
nullptr : new blink::WebScopedRunV8Script);
v8::Local<v8::Function> holder = function.NewHandle(isolate);
v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context);
ReturnType ret;
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
v8::Local<v8::Value> val(holder->Call(holder, args.size(), &args.front()));
Converter<ReturnType>::FromV8(isolate, val, &ret);
v8::Local<v8::Value> result;
auto maybe_result =
holder->Call(context, holder, args.size(), &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);
// 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::Callback<Sig> > {
struct Converter<base::Callback<Sig>> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const base::Callback<Sig>& val) {
return CreateFunctionTemplate(isolate, val)->GetFunction();
const base::Callback<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);
return internal::CreateFunctionFromTranslater(isolate, translater);
}
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
@ -92,9 +144,8 @@ struct Converter<base::Callback<Sig> > {
if (!val->IsFunction())
return false;
internal::SafeV8Function function(
new RefCountedPersistent<v8::Function>(isolate, val));
*out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go, isolate, function);
*out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go,
isolate, internal::SafeV8Function(isolate, val));
return true;
}
};

View 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/native_mate_converters/content_converter.h"
#include <vector>
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/string16_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);
case content::MenuItem::OPTION:
case content::MenuItem::SUBMENU:
v8_item.Set("label", item.label);
v8_item.Set("enabled", item.enabled);
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::Bind(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);
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);
}
} // namespace mate

View file

@ -0,0 +1,37 @@
// 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/common/menu_item.h"
#include "native_mate/converter.h"
namespace content {
struct ContextMenuParams;
class WebContents;
}
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);
};
} // namespace mate
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_CONTENT_CONVERTER_H_

View file

@ -21,6 +21,9 @@ struct Converter<base::FilePath> {
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);

View file

@ -0,0 +1,53 @@
// 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 <string>
#include "atom/common/node_includes.h"
#include "native_mate/dictionary.h"
#include "net/cert/x509_certificate.h"
#include "net/url_request/url_request.h"
namespace mate {
// static
v8::Local<v8::Value> Converter<const net::URLRequest*>::ToV8(
v8::Isolate* isolate, const net::URLRequest* val) {
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.Set("method", val->method());
dict.Set("url", val->url().spec());
dict.Set("referrer", val->referrer());
return mate::ConvertToV8(isolate, dict);
}
// static
v8::Local<v8::Value> Converter<const 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->os_cert_handle(), &encoded_data);
auto buffer = node::Buffer::Copy(isolate,
encoded_data.data(),
encoded_data.size()).ToLocalChecked();
dict.Set("data", buffer);
dict.Set("issuerName", val->issuer().GetDisplayName());
return dict.GetHandle();
}
} // namespace mate

View file

@ -0,0 +1,39 @@
// 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 net {
class AuthChallengeInfo;
class URLRequest;
class X509Certificate;
}
namespace mate {
template<>
struct Converter<const net::URLRequest*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const net::URLRequest* val);
};
template<>
struct Converter<const 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);
};
} // namespace mate
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_

View file

@ -152,6 +152,10 @@ v8::Local<v8::Value> V8ValueConverter::ToV8ValueImpl(
return ToV8Object(isolate,
static_cast<const base::DictionaryValue*>(value));
case base::Value::TYPE_BINARY:
return ToArrayBuffer(isolate,
static_cast<const base::BinaryValue*>(value));
default:
LOG(ERROR) << "Unexpected value type: " << value->GetType();
return v8::Null(isolate);
@ -200,6 +204,13 @@ v8::Local<v8::Value> V8ValueConverter::ToV8Object(
return result.GetHandle();
}
v8::Local<v8::Value> V8ValueConverter::ToArrayBuffer(
v8::Isolate* isolate, const base::BinaryValue* value) const {
return node::Buffer::Copy(isolate,
value->GetBuffer(),
value->GetSize()).ToLocalChecked();
}
base::Value* V8ValueConverter::FromV8ValueImpl(
FromV8ValueState* state,
v8::Local<v8::Value> val,

View file

@ -41,6 +41,9 @@ class V8ValueConverter {
v8::Local<v8::Value> ToV8Object(
v8::Isolate* isolate,
const base::DictionaryValue* dictionary) const;
v8::Local<v8::Value> ToArrayBuffer(
v8::Isolate* isolate,
const base::BinaryValue* value) const;
base::Value* FromV8ValueImpl(FromV8ValueState* state,
v8::Local<v8::Value> value,

View file

@ -14,6 +14,7 @@
#include "atom/common/node_includes.h"
#include "base/command_line.h"
#include "base/base_paths.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
@ -49,6 +50,7 @@ REFERENCE_MODULE(atom_browser_window);
REFERENCE_MODULE(atom_common_asar);
REFERENCE_MODULE(atom_common_clipboard);
REFERENCE_MODULE(atom_common_crash_reporter);
REFERENCE_MODULE(atom_common_id_weak_map);
REFERENCE_MODULE(atom_common_native_image);
REFERENCE_MODULE(atom_common_screen);
REFERENCE_MODULE(atom_common_shell);
@ -141,6 +143,14 @@ void NodeBindings::Initialize() {
// Init node.
// (we assume node::Init would not modify the parameters under embedded mode).
node::Init(nullptr, nullptr, nullptr, nullptr);
#if defined(OS_WIN)
// uv_init overrides error mode to suppress the default crash dialog, bring
// it back if user wants to show it.
scoped_ptr<base::Environment> env(base::Environment::Create());
if (env->HasVar("ELECTRON_DEFAULT_ERROR_MODE"))
SetErrorMode(0);
#endif
}
node::Environment* NodeBindings::CreateEnvironment(
@ -218,7 +228,7 @@ void NodeBindings::UvRunOnce() {
// Perform microtask checkpoint after running JavaScript.
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
is_browser_ ? nullptr : new blink::WebScopedRunV8Script(env->isolate()));
is_browser_ ? nullptr : new blink::WebScopedRunV8Script);
// Deal with uv events.
int r = uv_run(uv_loop_, UV_RUN_NOWAIT);

View file

@ -6,7 +6,7 @@
namespace atom {
namespace switches {
namespace options {
const char kTitle[] = "title";
const char kIcon[] = "icon";
@ -17,51 +17,89 @@ const char kX[] = "x";
const char kY[] = "y";
const char kWidth[] = "width";
const char kHeight[] = "height";
const char kMinWidth[] = "min-width";
const char kMinHeight[] = "min-height";
const char kMaxWidth[] = "max-width";
const char kMaxHeight[] = "max-height";
const char kMinWidth[] = "minWidth";
const char kMinHeight[] = "minHeight";
const char kMaxWidth[] = "maxWidth";
const char kMaxHeight[] = "maxHeight";
const char kResizable[] = "resizable";
const char kFullscreen[] = "fullscreen";
// Whether the window should show in taskbar.
const char kSkipTaskbar[] = "skip-taskbar";
const char kSkipTaskbar[] = "skipTaskbar";
// Start with the kiosk mode, see Opera's page for description:
// http://www.opera.com/support/mastering/kiosk/
const char kKiosk[] = "kiosk";
// Make windows stays on the top of all other windows.
const char kAlwaysOnTop[] = "always-on-top";
const char kNodeIntegration[] = "node-integration";
const char kAlwaysOnTop[] = "alwaysOnTop";
// Enable the NSView to accept first mouse event.
const char kAcceptFirstMouse[] = "accept-first-mouse";
const char kAcceptFirstMouse[] = "acceptFirstMouse";
// Whether window size should include window frame.
const char kUseContentSize[] = "use-content-size";
const char kUseContentSize[] = "useContentSize";
// The requested title bar style for the window
const char kTitleBarStyle[] = "title-bar-style";
// The WebPreferences.
const char kWebPreferences[] = "web-preferences";
// The factor of which page should be zoomed.
const char kZoomFactor[] = "zoom-factor";
const char kTitleBarStyle[] = "titleBarStyle";
// The menu bar is hidden unless "Alt" is pressed.
const char kAutoHideMenuBar[] = "auto-hide-menu-bar";
const char kAutoHideMenuBar[] = "autoHideMenuBar";
// Enable window to be resized larger than screen.
const char kEnableLargerThanScreen[] = "enable-larger-than-screen";
const char kEnableLargerThanScreen[] = "enableLargerThanScreen";
// Forces to use dark theme on Linux.
const char kDarkTheme[] = "dark-theme";
const char kDarkTheme[] = "darkTheme";
// Whether the window should be transparent.
const char kTransparent[] = "transparent";
// Window type hint.
const char kType[] = "type";
// Disable auto-hiding cursor.
const char kDisableAutoHideCursor[] = "disableAutoHideCursor";
// Use the OS X's standard window instead of the textured window.
const char kStandardWindow[] = "standardWindow";
// Default browser window background color.
const char kBackgroundColor[] = "backgroundColor";
// The WebPreferences.
const char kWebPreferences[] = "webPreferences";
// The factor of which page should be zoomed.
const char kZoomFactor[] = "zoomFactor";
// Script that will be loaded by guest WebContents before other scripts.
const char kPreloadScript[] = "preload";
// Like --preload, but the passed argument is an URL.
const char kPreloadURL[] = "preloadURL";
// Enable the node integration.
const char kNodeIntegration[] = "nodeIntegration";
// Instancd ID of guest WebContents.
const char kGuestInstanceID[] = "guestInstanceId";
// Set page visiblity to always visible.
const char kPageVisibility[] = "pageVisibility";
// Enable DirectWrite on Windows.
const char kDirectWrite[] = "direct-write";
const char kDirectWrite[] = "directWrite";
// Web runtime features.
const char kExperimentalFeatures[] = "experimentalFeatures";
const char kExperimentalCanvasFeatures[] = "experimentalCanvasFeatures";
const char kOverlayScrollbars[] = "overlayScrollbars";
const char kSharedWorker[] = "sharedWorker";
} // namespace options
namespace switches {
// Enable plugins.
const char kEnablePlugins[] = "enable-plugins";
@ -72,41 +110,9 @@ const char kPpapiFlashPath[] = "ppapi-flash-path";
// Ppapi Flash version.
const char kPpapiFlashVersion[] = "ppapi-flash-version";
// Instancd ID of guest WebContents.
const char kGuestInstanceID[] = "guest-instance-id";
// Script that will be loaded by guest WebContents before other scripts.
const char kPreloadScript[] = "preload";
// Like --preload, but the passed argument is an URL.
const char kPreloadUrl[] = "preload-url";
// Whether the window should be transparent.
const char kTransparent[] = "transparent";
// Window type hint.
const char kType[] = "type";
// Disable auto-hiding cursor.
const char kDisableAutoHideCursor[] = "disable-auto-hide-cursor";
// Use the OS X's standard window instead of the textured window.
const char kStandardWindow[] = "standard-window";
// Path to client certificate.
const char kClientCertificate[] = "client-certificate";
// Web runtime features.
const char kExperimentalFeatures[] = "experimental-features";
const char kExperimentalCanvasFeatures[] = "experimental-canvas-features";
const char kSubpixelFontScaling[] = "subpixel-font-scaling";
const char kOverlayScrollbars[] = "overlay-scrollbars";
const char kOverlayFullscreenVideo[] = "overlay-fullscreen-video";
const char kSharedWorker[] = "shared-worker";
// Set page visiblity to always visible.
const char kPageVisibility[] = "page-visibility";
// Disable HTTP cache.
const char kDisableHttpCache[] = "disable-http-cache";
@ -117,9 +123,24 @@ const char kRegisterStandardSchemes[] = "register-standard-schemes";
// TLS fallback will accept.
const char kSSLVersionFallbackMin[] = "ssl-version-fallback-min";
// Comma-separated list of SSL cipher suites to disable.
const char kCipherSuiteBlacklist[] = "cipher-suite-blacklist";
// The browser process app model ID
const char kAppUserModelId[] = "app-user-model-id";
// The command line switch versions of the options.
const char kZoomFactor[] = "zoom-factor";
const char kPreloadScript[] = "preload";
const char kPreloadURL[] = "preload-url";
const char kNodeIntegration[] = "node-integration";
const char kGuestInstanceID[] = "guest-instance-id";
const char kExperimentalFeatures[] = "experimental-features";
const char kExperimentalCanvasFeatures[] = "experimental-canvas-features";
const char kOverlayScrollbars[] = "overlay-scrollbars";
const char kSharedWorker[] = "shared-worker";
const char kPageVisibility[] = "page-visiblity";
} // namespace switches
} // namespace atom

View file

@ -7,7 +7,7 @@
namespace atom {
namespace switches {
namespace options {
extern const char kTitle[];
extern const char kIcon[];
@ -27,42 +27,60 @@ extern const char kFullscreen[];
extern const char kSkipTaskbar[];
extern const char kKiosk[];
extern const char kAlwaysOnTop[];
extern const char kNodeIntegration[];
extern const char kAcceptFirstMouse[];
extern const char kUseContentSize[];
extern const char kTitleBarStyle[];
extern const char kWebPreferences[];
extern const char kZoomFactor[];
extern const char kAutoHideMenuBar[];
extern const char kEnableLargerThanScreen[];
extern const char kDarkTheme[];
extern const char kDirectWrite[];
extern const char kEnablePlugins[];
extern const char kPpapiFlashPath[];
extern const char kPpapiFlashVersion[];
extern const char kGuestInstanceID[];
extern const char kPreloadScript[];
extern const char kPreloadUrl[];
extern const char kTransparent[];
extern const char kType[];
extern const char kDisableAutoHideCursor[];
extern const char kStandardWindow[];
extern const char kClientCertificate[];
extern const char kBackgroundColor[];
extern const char kWebPreferences[];
// WebPreferences.
extern const char kDirectWrite[];
extern const char kZoomFactor[];
extern const char kPreloadScript[];
extern const char kPreloadURL[];
extern const char kNodeIntegration[];
extern const char kGuestInstanceID[];
extern const char kExperimentalFeatures[];
extern const char kExperimentalCanvasFeatures[];
extern const char kSubpixelFontScaling[];
extern const char kOverlayScrollbars[];
extern const char kOverlayFullscreenVideo[];
extern const char kSharedWorker[];
extern const char kPageVisibility[];
} // namespace options
// Following are actually command line switches, should be moved to other files.
namespace switches {
extern const char kEnablePlugins[];
extern const char kPpapiFlashPath[];
extern const char kPpapiFlashVersion[];
extern const char kClientCertificate[];
extern const char kDisableHttpCache[];
extern const char kRegisterStandardSchemes[];
extern const char kSSLVersionFallbackMin[];
extern const char kCipherSuiteBlacklist[];
extern const char kAppUserModelId[];
extern const char kZoomFactor[];
extern const char kPreloadScript[];
extern const char kPreloadURL[];
extern const char kNodeIntegration[];
extern const char kGuestInstanceID[];
extern const char kExperimentalFeatures[];
extern const char kExperimentalCanvasFeatures[];
extern const char kOverlayScrollbars[];
extern const char kSharedWorker[];
extern const char kPageVisibility[];
} // namespace switches
} // namespace atom

View file

@ -20,7 +20,7 @@ void ShowItemInFolder(const base::FilePath& full_path) {
DCHECK([NSThread isMainThread]);
NSString* path_string = base::SysUTF8ToNSString(full_path.value());
if (!path_string || ![[NSWorkspace sharedWorkspace] selectFile:path_string
inFileViewerRootedAtPath:nil])
inFileViewerRootedAtPath:@""])
LOG(WARNING) << "NSWorkspace failed to select file " << full_path.value();
}

View file

@ -5,7 +5,9 @@
#include "atom/common/platform_util.h"
#include <windows.h>
#include <atlbase.h>
#include <commdlg.h>
#include <comdef.h>
#include <dwmapi.h>
#include <shellapi.h>
#include <shlobj.h>
@ -19,6 +21,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "url/gurl.h"
@ -42,11 +45,168 @@ bool ValidateShellCommandForScheme(const std::string& scheme) {
return true;
}
// Required COM implementation of IFileOperationProgressSink so we can
// precheck files before deletion to make sure they can be move to the
// Recycle Bin.
class DeleteFileProgressSink : public IFileOperationProgressSink {
public:
DeleteFileProgressSink();
private:
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObj);
HRESULT STDMETHODCALLTYPE StartOperations(void);
HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT);
HRESULT STDMETHODCALLTYPE PreRenameItem(
DWORD, IShellItem*, LPCWSTR);
HRESULT STDMETHODCALLTYPE PostRenameItem(
DWORD, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE PreMoveItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR);
HRESULT STDMETHODCALLTYPE PostMoveItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE PreCopyItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR);
HRESULT STDMETHODCALLTYPE PostCopyItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD, IShellItem*);
HRESULT STDMETHODCALLTYPE PostDeleteItem(
DWORD, IShellItem*, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE PreNewItem(
DWORD, IShellItem*, LPCWSTR);
HRESULT STDMETHODCALLTYPE PostNewItem(
DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE UpdateProgress(UINT, UINT);
HRESULT STDMETHODCALLTYPE ResetTimer(void);
HRESULT STDMETHODCALLTYPE PauseTimer(void);
HRESULT STDMETHODCALLTYPE ResumeTimer(void);
ULONG m_cRef;
};
DeleteFileProgressSink::DeleteFileProgressSink() {
m_cRef = 0;
}
HRESULT DeleteFileProgressSink::PreDeleteItem(DWORD dwFlags, IShellItem*) {
if (!(dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE)) {
// TSF_DELETE_RECYCLE_IF_POSSIBLE will not be set for items that cannot be
// recycled. In this case, we abort the delete operation. This bubbles
// up and stops the Delete in IFileOperation.
return E_ABORT;
}
// Returns S_OK if successful, or an error value otherwise. In the case of an
// error value, the delete operation and all subsequent operations pending
// from the call to IFileOperation are canceled.
return S_OK;
}
HRESULT DeleteFileProgressSink::QueryInterface(REFIID riid, LPVOID* ppvObj) {
// Always set out parameter to NULL, validating it first.
if (!ppvObj)
return E_INVALIDARG;
*ppvObj = nullptr;
if (riid == IID_IUnknown || riid == IID_IFileOperationProgressSink) {
// Increment the reference count and return the pointer.
*ppvObj = reinterpret_cast<IUnknown*>(this);
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG DeleteFileProgressSink::AddRef() {
InterlockedIncrement(&m_cRef);
return m_cRef;
}
ULONG DeleteFileProgressSink::Release() {
// Decrement the object's internal counter.
ULONG ulRefCount = InterlockedDecrement(&m_cRef);
if (0 == m_cRef) {
delete this;
}
return ulRefCount;
}
HRESULT DeleteFileProgressSink::StartOperations() {
return S_OK;
}
HRESULT DeleteFileProgressSink::FinishOperations(HRESULT) {
return S_OK;
}
HRESULT DeleteFileProgressSink::PreRenameItem(DWORD, IShellItem*, LPCWSTR) {
return S_OK;
}
HRESULT DeleteFileProgressSink::PostRenameItem(
DWORD, IShellItem*, __RPC__in_string LPCWSTR, HRESULT, IShellItem*) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PreMoveItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PostMoveItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PreCopyItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PostCopyItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PostDeleteItem(
DWORD, IShellItem*, HRESULT, IShellItem*) {
return S_OK;
}
HRESULT DeleteFileProgressSink::PreNewItem(
DWORD dwFlags, IShellItem*, LPCWSTR) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PostNewItem(
DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::UpdateProgress(UINT, UINT) {
return S_OK;
}
HRESULT DeleteFileProgressSink::ResetTimer() {
return S_OK;
}
HRESULT DeleteFileProgressSink::PauseTimer() {
return S_OK;
}
HRESULT DeleteFileProgressSink::ResumeTimer() {
return S_OK;
}
} // namespace
namespace platform_util {
void ShowItemInFolder(const base::FilePath& full_path) {
base::win::ScopedCOMInitializer com_initializer;
if (!com_initializer.succeeded())
return;
base::FilePath dir = full_path.DirName().AsEndingWithSeparator();
// ParseDisplayName will fail if the directory is "C:", it must be "C:\\".
if (dir.empty())
@ -147,8 +307,8 @@ bool OpenExternal(const GURL& url) {
// "Some versions of windows (Win2k before SP3, Win XP before SP1) crash in
// ShellExecute on long URLs (bug 161357 on bugzilla.mozilla.org). IE 5 and 6
// support URLS of 2083 chars in length, 2K is safe."
const size_t kMaxUrlLength = 2048;
if (escaped_url.length() > kMaxUrlLength) {
const size_t kMaxURLLength = 2048;
if (escaped_url.length() > kMaxURLLength) {
NOTREACHED();
return false;
}
@ -170,32 +330,40 @@ bool OpenExternal(const GURL& url) {
}
bool MoveItemToTrash(const base::FilePath& path) {
// SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
// so we have to use wcscpy because wcscpy_s writes non-NULLs
// into the rest of the buffer.
wchar_t double_terminated_path[MAX_PATH + 1] = {0};
#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
wcscpy(double_terminated_path, path.value().c_str());
SHFILEOPSTRUCT file_operation = {0};
file_operation.wFunc = FO_DELETE;
file_operation.pFrom = double_terminated_path;
file_operation.fFlags = FOF_ALLOWUNDO | FOF_SILENT | FOF_NOCONFIRMATION;
int err = SHFileOperation(&file_operation);
// Since we're passing flags to the operation telling it to be silent,
// it's possible for the operation to be aborted/cancelled without err
// being set (although MSDN doesn't give any scenarios for how this can
// happen). See MSDN for SHFileOperation and SHFILEOPTSTRUCT.
if (file_operation.fAnyOperationsAborted)
base::win::ScopedCOMInitializer com_initializer;
if (!com_initializer.succeeded())
return false;
// Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
// an empty directory and some return 0x402 when they should be returning
// ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402. Windows 7
// can return DE_INVALIDFILES (0x7C) for nonexistent directories.
return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402 ||
err == 0x7C);
base::win::ScopedComPtr<IFileOperation> pfo;
if (FAILED(pfo.CreateInstance(CLSID_FileOperation)))
return false;
// Elevation prompt enabled for UAC protected files. This overrides the
// SILENT, NO_UI and NOERRORUI flags.
if (FAILED(pfo->SetOperationFlags(FOF_NO_UI |
FOF_ALLOWUNDO |
FOF_NOERRORUI |
FOF_SILENT |
FOFX_SHOWELEVATIONPROMPT |
FOFX_RECYCLEONDELETE)))
return false;
// Create an IShellItem from the supplied source path.
base::win::ScopedComPtr<IShellItem> delete_item;
if (FAILED(SHCreateItemFromParsingName(path.value().c_str(),
NULL,
IID_PPV_ARGS(delete_item.Receive()))))
return false;
base::win::ScopedComPtr<IFileOperationProgressSink> delete_sink(
new DeleteFileProgressSink);
if (!delete_sink)
return false;
// Processes the queued command DeleteItem. This will trigger
// the DeleteFileProgressSink to check for Recycle Bin.
return SUCCEEDED(pfo->DeleteItem(delete_item.get(), delete_sink.get())) &&
SUCCEEDED(pfo->PerformOperations());
}
void Beep() {

View file

@ -2,12 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>${PRODUCT_NAME} Framework</string>
<key>CFBundleIdentifier</key>
<string>${ATOM_BUNDLE_ID}</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME} Framework</string>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>NSSupportsAutomaticGraphicsSwitching</key>