diff --git a/README.md b/README.md index 7b582e6201cf..c3f7461c5e7e 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,37 @@ -# Electron [![Build Status](https://travis-ci.org/atom/electron.svg?branch=master)](https://travis-ci.org/atom/electron) +[![Electron Logo](http://electron.atom.io/images/electron-logo.svg)](http://electron.atom.io/) + +[![Build Status](https://travis-ci.org/atom/electron.svg?branch=master)](https://travis-ci.org/atom/electron) +[![devDependency Status](https://david-dm.org/atom/electron/dev-status.svg)](https://david-dm.org/atom/electron#info=devDependencies) + +:zap: *formerly known as Atom Shell* :zap: The Electron framework lets you write cross-platform desktop applications using JavaScript, HTML and CSS. It is based on [io.js](http://iojs.org) and [Chromium](http://www.chromium.org) and is used in the [Atom editor](https://github.com/atom/atom). +Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important +announcements. + ## Downloads Prebuilt binaries and debug symbols of Electron for Linux, Windows and Mac can be found on the [releases](https://github.com/atom/electron/releases) page. +You can also use [`npm`](https://docs.npmjs.com/) to install prebuilt electron +binaries: + +```sh +# Install the `electron` command globally in your $PATH +npm install electron-prebuilt -g + +# Install as a development dependency +npm install electron-prebuilt --save-dev +``` + ### Mirrors -- [China](https://npm.taobao.org/mirrors/atom-shell) +- [China](https://npm.taobao.org/mirrors/electron) ## Documentation @@ -22,5 +41,5 @@ contains documents describing how to build and contribute to Electron. ## Community -There is an [`atom-shell` category on the Atom forums](http://discuss.atom.io/category/atom-shell) +There is an [`electron` category on the Atom forums](http://discuss.atom.io/category/electron) as well as an `#atom-shell` channel on Freenode. diff --git a/atom.gyp b/atom.gyp index 0e391a998f42..9ae9a90a122b 100644 --- a/atom.gyp +++ b/atom.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '0.24.0', + 'version%': '0.26.0', 'atom_source_root': ' #include "atom/common/chrome_version.h" +#include "atom/common/options_switches.h" +#include "base/command_line.h" +#include "content/public/common/content_constants.h" +#include "content/public/common/pepper_plugin_info.h" +#include "ppapi/shared_impl/ppapi_permissions.h" namespace atom { +namespace { + +content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path, + const std::string& version) { + content::PepperPluginInfo plugin; + + plugin.is_out_of_process = true; + plugin.name = content::kFlashPluginName; + plugin.path = path; + plugin.permissions = ppapi::PERMISSION_ALL_BITS; + plugin.version = version; + + content::WebPluginMimeType swf_mime_type( + content::kFlashPluginSwfMimeType, + content::kFlashPluginSwfExtension, + content::kFlashPluginSwfDescription); + plugin.mime_types.push_back(swf_mime_type); + content::WebPluginMimeType spl_mime_type( + content::kFlashPluginSplMimeType, + content::kFlashPluginSplExtension, + content::kFlashPluginSplDescription); + plugin.mime_types.push_back(spl_mime_type); + + return plugin; +} + +} // namespace + AtomContentClient::AtomContentClient() { } @@ -27,4 +60,19 @@ void AtomContentClient::AddAdditionalSchemes( standard_schemes->push_back("chrome-extension"); } +void AtomContentClient::AddPepperPlugins( + std::vector* plugins) { + auto command_line = base::CommandLine::ForCurrentProcess(); + auto flash_path = command_line->GetSwitchValueNative( + switches::kPpapiFlashPath); + if (flash_path.empty()) + return; + + auto flash_version = command_line->GetSwitchValueASCII( + switches::kPpapiFlashVersion); + + plugins->push_back( + CreatePepperFlashInfo(base::FilePath(flash_path), flash_version)); +} + } // namespace atom diff --git a/atom/app/atom_content_client.h b/atom/app/atom_content_client.h index 732ac3587800..279ec7179f49 100644 --- a/atom/app/atom_content_client.h +++ b/atom/app/atom_content_client.h @@ -23,6 +23,8 @@ class AtomContentClient : public brightray::ContentClient { void AddAdditionalSchemes( std::vector* standard_schemes, std::vector* savable_schemes) override; + void AddPepperPlugins( + std::vector* plugins) override; private: DISALLOW_COPY_AND_ASSIGN(AtomContentClient); diff --git a/atom/app/atom_main_delegate.cc b/atom/app/atom_main_delegate.cc index c7ad0e11a0ca..c9cdc77e1173 100644 --- a/atom/app/atom_main_delegate.cc +++ b/atom/app/atom_main_delegate.cc @@ -10,6 +10,7 @@ #include "atom/browser/atom_browser_client.h" #include "atom/common/google_api_key.h" #include "atom/renderer/atom_renderer_client.h" +#include "atom/utility/atom_content_utility_client.h" #include "base/command_line.h" #include "base/debug/stack_trace.h" #include "base/environment.h" @@ -94,6 +95,11 @@ content::ContentRendererClient* return renderer_client_.get(); } +content::ContentUtilityClient* AtomMainDelegate::CreateContentUtilityClient() { + utility_client_.reset(new AtomContentUtilityClient); + return utility_client_.get(); +} + scoped_ptr AtomMainDelegate::CreateContentClient() { return scoped_ptr(new AtomContentClient).Pass(); } diff --git a/atom/app/atom_main_delegate.h b/atom/app/atom_main_delegate.h index 8cd4a28ee1c0..7bcde8125c8e 100644 --- a/atom/app/atom_main_delegate.h +++ b/atom/app/atom_main_delegate.h @@ -21,6 +21,7 @@ class AtomMainDelegate : public brightray::MainDelegate { void PreSandboxStartup() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentRendererClient* CreateContentRendererClient() override; + content::ContentUtilityClient* CreateContentUtilityClient() override; // brightray::MainDelegate: scoped_ptr CreateContentClient() override; @@ -35,6 +36,7 @@ class AtomMainDelegate : public brightray::MainDelegate { brightray::ContentClient content_client_; scoped_ptr browser_client_; scoped_ptr renderer_client_; + scoped_ptr utility_client_; DISALLOW_COPY_AND_ASSIGN(AtomMainDelegate); }; diff --git a/atom/app/node_main.cc b/atom/app/node_main.cc index 66cf9dcf12e7..7446a0a71106 100644 --- a/atom/app/node_main.cc +++ b/atom/app/node_main.cc @@ -26,7 +26,19 @@ int NodeMain(int argc, char *argv[]) { JavascriptEnvironment gin_env; node::Environment* env = node::CreateEnvironment( - gin_env.isolate(), gin_env.context(), argc, argv, exec_argc, exec_argv); + gin_env.isolate(), uv_default_loop(), gin_env.context(), argc, argv, + exec_argc, exec_argv); + + // Start debugger. + node::node_isolate = gin_env.isolate(); + if (node::use_debug_agent) + node::StartDebug(env, node::debug_wait_connect); + + node::LoadEnvironment(env); + + // Enable debugger. + if (node::use_debug_agent) + node::EnableDebug(env); bool more; do { diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 37cfaf640395..d3b04f043622 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -7,6 +7,10 @@ #include #include +#if defined(OS_WIN) +#include +#endif + #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/browser.h" @@ -25,6 +29,10 @@ #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" +#if defined(OS_WIN) +#include "base/strings/utf_string_conversions.h" +#endif + #include "atom/common/node_includes.h" using atom::Browser; @@ -200,6 +208,13 @@ void App::SetDesktopName(const std::string& desktop_name) { #endif } +void App::SetAppUserModelId(const std::string& app_id) { +#if defined(OS_WIN) + base::string16 app_id_utf16 = base::UTF8ToUTF16(app_id); + SetCurrentProcessExplicitAppUserModelID(app_id_utf16.c_str()); +#endif +} + mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( v8::Isolate* isolate) { auto browser = base::Unretained(Browser::Get()); @@ -222,7 +237,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( .SetMethod("setPath", &App::SetPath) .SetMethod("getPath", &App::GetPath) .SetMethod("resolveProxy", &App::ResolveProxy) - .SetMethod("setDesktopName", &App::SetDesktopName); + .SetMethod("setDesktopName", &App::SetDesktopName) + .SetMethod("setAppUserModelId", &App::SetAppUserModelId); } // static diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 062d2d083d2a..c2f9212b7ca7 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -61,6 +61,7 @@ class App : public mate::EventEmitter, void ResolveProxy(const GURL& url, ResolveProxyCallback callback); void SetDesktopName(const std::string& desktop_name); + void SetAppUserModelId(const std::string& app_id); DISALLOW_COPY_AND_ASSIGN(App); }; diff --git a/atom/browser/api/atom_api_content_tracing.cc b/atom/browser/api/atom_api_content_tracing.cc index 28a95aa71e6f..a3299e447a8f 100644 --- a/atom/browser/api/atom_api_content_tracing.cc +++ b/atom/browser/api/atom_api_content_tracing.cc @@ -17,38 +17,24 @@ using content::TracingController; namespace mate { -template -struct Converter > { - static v8::Handle ToV8(v8::Isolate* isolate, - const std::set& val) { - v8::Handle result = v8::Array::New( - isolate, static_cast(val.size())); - typename std::set::const_iterator it; - int i; - for (i = 0, it = val.begin(); it != val.end(); ++it, ++i) - result->Set(i, Converter::ToV8(isolate, *it)); - return result; - } -}; - template<> -struct Converter { +struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Handle val, - base::debug::CategoryFilter* out) { + base::trace_event::CategoryFilter* out) { std::string filter; if (!ConvertFromV8(isolate, val, &filter)) return false; - *out = base::debug::CategoryFilter(filter); + *out = base::trace_event::CategoryFilter(filter); return true; } }; template<> -struct Converter { +struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Handle val, - base::debug::TraceOptions* out) { + base::trace_event::TraceOptions* out) { std::string options; if (!ConvertFromV8(isolate, val, &options)) return false; diff --git a/atom/browser/api/atom_api_power_monitor.cc b/atom/browser/api/atom_api_power_monitor.cc index 905f61f590ea..8f87eec07280 100644 --- a/atom/browser/api/atom_api_power_monitor.cc +++ b/atom/browser/api/atom_api_power_monitor.cc @@ -4,6 +4,7 @@ #include "atom/browser/api/atom_api_power_monitor.h" +#include "atom/browser/browser.h" #include "base/power_monitor/power_monitor.h" #include "base/power_monitor/power_monitor_device_source.h" #include "native_mate/dictionary.h" @@ -38,8 +39,14 @@ void PowerMonitor::OnResume() { } // static -mate::Handle PowerMonitor::Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new PowerMonitor); +v8::Handle PowerMonitor::Create(v8::Isolate* isolate) { + if (!Browser::Get()->is_ready()) { + node::ThrowError("Cannot initialize \"power-monitor\" module" + "before app is ready"); + return v8::Null(isolate); + } + + return CreateHandle(isolate, new PowerMonitor).ToV8(); } } // namespace api @@ -57,9 +64,8 @@ void Initialize(v8::Handle exports, v8::Handle unused, using atom::api::PowerMonitor; v8::Isolate* isolate = context->GetIsolate(); - mate::Handle power_monitor = PowerMonitor::Create(isolate); mate::Dictionary dict(isolate, exports); - dict.Set("powerMonitor", power_monitor); + dict.Set("powerMonitor", PowerMonitor::Create(isolate)); } } // namespace diff --git a/atom/browser/api/atom_api_power_monitor.h b/atom/browser/api/atom_api_power_monitor.h index 2fccc7fd311b..cdd14ff6e859 100644 --- a/atom/browser/api/atom_api_power_monitor.h +++ b/atom/browser/api/atom_api_power_monitor.h @@ -17,7 +17,7 @@ namespace api { class PowerMonitor : public mate::EventEmitter, public base::PowerObserver { public: - static mate::Handle Create(v8::Isolate* isolate); + static v8::Handle Create(v8::Isolate* isolate); protected: PowerMonitor(); diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index ecb9d416875a..8a7e0ae6840a 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -105,6 +105,15 @@ class CustomProtocolRequestJob : public AdapterRequestJob { base::Bind(&AdapterRequestJob::CreateFileJobAndStart, GetWeakPtr(), path)); return; + } else if (name == "RequestErrorJob") { + // Default value net::ERR_NOT_IMPLEMENTED + int error = -11; + dict.Get("error", &error); + + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&AdapterRequestJob::CreateErrorJobAndStart, + GetWeakPtr(), error)); + return; } } diff --git a/atom/browser/api/atom_api_tray.cc b/atom/browser/api/atom_api_tray.cc index 94af89b81ecd..b66d95cb0732 100644 --- a/atom/browser/api/atom_api_tray.cc +++ b/atom/browser/api/atom_api_tray.cc @@ -9,6 +9,7 @@ #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/browser.h" #include "atom/browser/ui/tray_icon.h" +#include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "native_mate/constructor.h" @@ -39,8 +40,8 @@ mate::Wrappable* Tray::New(const gfx::Image& image) { return new Tray(image); } -void Tray::OnClicked() { - Emit("clicked"); +void Tray::OnClicked(const gfx::Rect& bounds) { + Emit("clicked", bounds); } void Tray::OnDoubleClicked() { diff --git a/atom/browser/api/atom_api_tray.h b/atom/browser/api/atom_api_tray.h index 48828d2c9366..5ed29ecd74f1 100644 --- a/atom/browser/api/atom_api_tray.h +++ b/atom/browser/api/atom_api_tray.h @@ -41,7 +41,7 @@ class Tray : public mate::EventEmitter, virtual ~Tray(); // TrayIconObserver: - void OnClicked() override; + void OnClicked(const gfx::Rect&) override; void OnDoubleClicked() override; void OnBalloonShow() override; void OnBalloonClicked() override; diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index e0c433695e74..e228a064f413 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -4,17 +4,24 @@ #include "atom/browser/api/atom_api_web_contents.h" +#include + +#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_context.h" +#include "atom/browser/atom_javascript_dialog_manager.h" #include "atom/browser/native_window.h" #include "atom/browser/web_dialog_helper.h" #include "atom/browser/web_view_manager.h" #include "atom/common/api/api_messages.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/image_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/value_converter.h" #include "base/strings/utf_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" +#include "brightray/browser/media/media_stream_devices_controller.h" +#include "content/public/browser/favicon_status.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_frame_host.h" @@ -22,11 +29,13 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/resource_request_details.h" +#include "content/public/browser/service_worker_context.h" +#include "content/public/browser/storage_partition.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" +#include "native_mate/callback.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" -#include "vendor/brightray/browser/media/media_stream_devices_controller.h" #include "atom/common/node_includes.h" @@ -49,6 +58,22 @@ NativeWindow* GetWindowFromGuest(const content::WebContents* guest) { return nullptr; } +content::ServiceWorkerContext* GetServiceWorkerContext( + const content::WebContents* web_contents) { + auto context = web_contents->GetBrowserContext(); + auto site_instance = web_contents->GetSiteInstance(); + if (!context || !site_instance) + return nullptr; + + content::StoragePartition* storage_partition = + content::BrowserContext::GetStoragePartition( + context, site_instance); + + DCHECK(storage_partition); + + return storage_partition->GetServiceWorkerContext(); +} + } // namespace WebContents::WebContents(content::WebContents* web_contents) @@ -136,11 +161,20 @@ content::WebContents* WebContents::OpenURLFromTab( load_url_params.is_renderer_initiated = params.is_renderer_initiated; load_url_params.transferred_global_request_id = params.transferred_global_request_id; + load_url_params.should_clear_history_list = true; web_contents()->GetController().LoadURLWithParams(load_url_params); return web_contents(); } +content::JavaScriptDialogManager* WebContents::GetJavaScriptDialogManager( + content::WebContents* source) { + if (!dialog_manager_) + dialog_manager_.reset(new AtomJavaScriptDialogManager); + + return dialog_manager_.get(); +} + void WebContents::RunFileChooser(content::WebContents* guest, const content::FileChooserParams& params) { if (!web_dialog_helper_) @@ -191,6 +225,12 @@ void WebContents::RenderProcessGone(base::TerminationStatus status) { Emit("crashed"); } +void WebContents::DocumentLoadedInFrame( + content::RenderFrameHost* render_frame_host) { + if (!render_frame_host->GetParent()) + Emit("dom-ready"); +} + void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url) { bool is_main_frame = !render_frame_host->GetParent(); @@ -253,7 +293,22 @@ void WebContents::DidNavigateMainFrame( void WebContents::TitleWasSet(content::NavigationEntry* entry, bool explicit_set) { - Emit("page-title-set", entry->GetTitle(), explicit_set); + // Back/Forward navigation may have pruned entries. + if (entry) + Emit("page-title-set", entry->GetTitle(), explicit_set); +} + +void WebContents::DidUpdateFaviconURL( + const std::vector& urls) { + std::set unique_urls; + for (auto iter = urls.begin(); iter != urls.end(); ++iter) { + if (iter->icon_type != content::FaviconURL::FAVICON) + continue; + const GURL& url = iter->icon_url; + if (url.is_valid()) + unique_urls.insert(url); + } + Emit("page-favicon-updated", unique_urls); } bool WebContents::OnMessageReceived(const IPC::Message& message) { @@ -294,9 +349,9 @@ void WebContents::WebContentsDestroyed() { } void WebContents::NavigationEntryCommitted( - const content::LoadCommittedDetails& load_details) { - auto entry = web_contents()->GetController().GetLastCommittedEntry(); - entry->SetVirtualURL(load_details.entry->GetOriginalRequestURL()); + const content::LoadCommittedDetails& details) { + Emit("navigation-entry-commited", details.entry->GetURL(), + details.is_in_page, details.did_replace_entry); } void WebContents::DidAttach(int guest_proxy_routing_id) { @@ -315,12 +370,11 @@ content::WebContents* WebContents::GetOwnerWebContents() const { return embedder_web_contents_; } -void WebContents::GuestSizeChanged(const gfx::Size& old_size, - const gfx::Size& new_size) { +void WebContents::GuestSizeChanged(const gfx::Size& new_size) { if (!auto_size_enabled_) return; + GuestSizeChangedDueToAutoSize(guest_size_, new_size); guest_size_ = new_size; - GuestSizeChangedDueToAutoSize(old_size, new_size); } void WebContents::RegisterDestructionCallback( @@ -365,17 +419,11 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) { blink::WebReferrerPolicyDefault); params.transition_type = ui::PAGE_TRANSITION_TYPED; + params.should_clear_history_list = true; params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; web_contents()->GetController().LoadURLWithParams(params); } -GURL WebContents::GetURL() const { - auto entry = web_contents()->GetController().GetLastCommittedEntry(); - if (!entry) - return GURL::EmptyGURL(); - return entry->GetVirtualURL(); -} - base::string16 WebContents::GetTitle() const { return web_contents()->GetTitle(); } @@ -392,45 +440,22 @@ void WebContents::Stop() { web_contents()->Stop(); } -void WebContents::Reload(const mate::Dictionary& options) { - // Navigating to a URL would always restart the renderer process, we want this - // because normal reloading will break our node integration. - // This is done by AtomBrowserClient::ShouldSwapProcessesForNavigation. - LoadURL(GetURL(), options); -} - -void WebContents::ReloadIgnoringCache(const mate::Dictionary& options) { - // Hack to remove pending entries that ignores cache and treated as a fresh - // load. +void WebContents::ReloadIgnoringCache() { web_contents()->GetController().ReloadIgnoringCache(false); - Reload(options); -} - -bool WebContents::CanGoBack() const { - return web_contents()->GetController().CanGoBack(); -} - -bool WebContents::CanGoForward() const { - return web_contents()->GetController().CanGoForward(); -} - -bool WebContents::CanGoToOffset(int offset) const { - return web_contents()->GetController().CanGoToOffset(offset); } void WebContents::GoBack() { + atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); web_contents()->GetController().GoBack(); } void WebContents::GoForward() { + atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); web_contents()->GetController().GoForward(); } -void WebContents::GoToIndex(int index) { - web_contents()->GetController().GoToIndex(index); -} - void WebContents::GoToOffset(int offset) { + atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); web_contents()->GetController().GoToOffset(offset); } @@ -471,6 +496,13 @@ bool WebContents::IsDevToolsOpened() { return storage_->IsDevToolsViewShowing(); } +void WebContents::InspectElement(int x, int y) { + OpenDevTools(); + scoped_refptr agent( + content::DevToolsAgentHost::GetOrCreateFor(storage_->GetWebContents())); + agent->InspectElement(x, y); +} + void WebContents::Undo() { web_contents()->Undo(); } @@ -562,6 +594,27 @@ void WebContents::SetAllowTransparency(bool allow) { } } +void WebContents::HasServiceWorker( + const base::Callback& callback) { + auto context = GetServiceWorkerContext(web_contents()); + if (!context) + return; + + context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(), + GURL::EmptyGURL(), + callback); +} + +void WebContents::UnregisterServiceWorker( + const base::Callback& callback) { + auto context = GetServiceWorkerContext(web_contents()); + if (!context) + return; + + context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(), + callback); +} + mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( v8::Isolate* isolate) { if (template_.IsEmpty()) @@ -569,20 +622,14 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( .SetMethod("destroy", &WebContents::Destroy) .SetMethod("isAlive", &WebContents::IsAlive) .SetMethod("_loadUrl", &WebContents::LoadURL) - .SetMethod("getUrl", &WebContents::GetURL) .SetMethod("getTitle", &WebContents::GetTitle) .SetMethod("isLoading", &WebContents::IsLoading) .SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse) - .SetMethod("stop", &WebContents::Stop) - .SetMethod("_reload", &WebContents::Reload) + .SetMethod("_stop", &WebContents::Stop) .SetMethod("_reloadIgnoringCache", &WebContents::ReloadIgnoringCache) - .SetMethod("canGoBack", &WebContents::CanGoBack) - .SetMethod("canGoForward", &WebContents::CanGoForward) - .SetMethod("canGoToOffset", &WebContents::CanGoToOffset) - .SetMethod("goBack", &WebContents::GoBack) - .SetMethod("goForward", &WebContents::GoForward) - .SetMethod("goToIndex", &WebContents::GoToIndex) - .SetMethod("goToOffset", &WebContents::GoToOffset) + .SetMethod("_goBack", &WebContents::GoBack) + .SetMethod("_goForward", &WebContents::GoForward) + .SetMethod("_goToOffset", &WebContents::GoToOffset) .SetMethod("getRoutingId", &WebContents::GetRoutingID) .SetMethod("getProcessId", &WebContents::GetProcessID) .SetMethod("isCrashed", &WebContents::IsCrashed) @@ -592,6 +639,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( .SetMethod("openDevTools", &WebContents::OpenDevTools) .SetMethod("closeDevTools", &WebContents::CloseDevTools) .SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened) + .SetMethod("inspectElement", &WebContents::InspectElement) .SetMethod("undo", &WebContents::Undo) .SetMethod("redo", &WebContents::Redo) .SetMethod("cut", &WebContents::Cut) @@ -606,6 +654,9 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( .SetMethod("setAutoSize", &WebContents::SetAutoSize) .SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency) .SetMethod("isGuest", &WebContents::is_guest) + .SetMethod("hasServiceWorker", &WebContents::HasServiceWorker) + .SetMethod("unregisterServiceWorker", + &WebContents::UnregisterServiceWorker) .Build()); return mate::ObjectTemplateBuilder( diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 9b2a9cd4e3e4..e75cfb0267f0 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -6,13 +6,16 @@ #define ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_ #include +#include #include "atom/browser/api/event_emitter.h" #include "brightray/browser/default_web_contents_delegate.h" #include "content/public/browser/browser_plugin_guest_delegate.h" +#include "content/public/common/favicon_url.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" #include "native_mate/handle.h" +#include "ui/gfx/image/image.h" namespace brightray { class InspectableWebContents; @@ -24,6 +27,7 @@ class Dictionary; namespace atom { +class AtomJavaScriptDialogManager; class WebDialogHelper; namespace api { @@ -44,19 +48,13 @@ class WebContents : public mate::EventEmitter, void Destroy(); bool IsAlive() const; void LoadURL(const GURL& url, const mate::Dictionary& options); - GURL GetURL() const; base::string16 GetTitle() const; bool IsLoading() const; bool IsWaitingForResponse() const; void Stop(); - void Reload(const mate::Dictionary& options); - void ReloadIgnoringCache(const mate::Dictionary& options); - bool CanGoBack() const; - bool CanGoForward() const; - bool CanGoToOffset(int offset) const; + void ReloadIgnoringCache(); void GoBack(); void GoForward(); - void GoToIndex(int index); void GoToOffset(int offset); int GetRoutingID() const; int GetProcessID() const; @@ -67,6 +65,9 @@ class WebContents : public mate::EventEmitter, void OpenDevTools(); void CloseDevTools(); bool IsDevToolsOpened(); + void InspectElement(int x, int y); + void HasServiceWorker(const base::Callback&); + void UnregisterServiceWorker(const base::Callback&); // Editing commands. void Undo(); @@ -130,6 +131,8 @@ class WebContents : public mate::EventEmitter, content::WebContents* OpenURLFromTab( content::WebContents* source, const content::OpenURLParams& params) override; + content::JavaScriptDialogManager* GetJavaScriptDialogManager( + content::WebContents* source) override; void RunFileChooser(content::WebContents* web_contents, const content::FileChooserParams& params) override; void EnumerateDirectory(content::WebContents* web_contents, @@ -149,6 +152,8 @@ class WebContents : public mate::EventEmitter, // content::WebContentsObserver: void RenderViewDeleted(content::RenderViewHost*) override; void RenderProcessGone(base::TerminationStatus status) override; + void DocumentLoadedInFrame( + content::RenderFrameHost* render_frame_host) override; void DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url) override; void DidFailLoad(content::RenderFrameHost* render_frame_host, @@ -175,13 +180,14 @@ class WebContents : public mate::EventEmitter, void NavigationEntryCommitted( const content::LoadCommittedDetails& load_details) override; void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override; + void DidUpdateFaviconURL( + const std::vector& urls) override; // content::BrowserPluginGuestDelegate: void DidAttach(int guest_proxy_routing_id) final; void ElementSizeChanged(const gfx::Size& size) final; content::WebContents* GetOwnerWebContents() const final; - void GuestSizeChanged(const gfx::Size& old_size, - const gfx::Size& new_size) final; + void GuestSizeChanged(const gfx::Size& new_size) final; void RegisterDestructionCallback(const DestructionCallback& callback) final; void SetGuestSizer(content::GuestSizer* guest_sizer) final; void WillAttach(content::WebContents* embedder_web_contents, @@ -202,6 +208,7 @@ class WebContents : public mate::EventEmitter, const gfx::Size& new_size); scoped_ptr web_dialog_helper_; + scoped_ptr dialog_manager_; // Unique ID for a guest WebContents. int guest_instance_id_; diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 22f40be27e30..b71499d3699c 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -15,6 +15,7 @@ #include "native_mate/callback.h" #include "native_mate/constructor.h" #include "native_mate/dictionary.h" +#include "ui/gfx/geometry/rect.h" #include "atom/common/node_includes.h" @@ -222,6 +223,14 @@ bool Window::IsFullscreen() { return window_->IsFullscreen(); } +void Window::SetBounds(const gfx::Rect& bounds) { + window_->SetBounds(bounds); +} + +gfx::Rect Window::GetBounds() { + return window_->GetBounds(); +} + void Window::SetSize(int width, int height) { window_->SetSize(gfx::Size(width, height)); } @@ -464,6 +473,8 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("isMinimized", &Window::IsMinimized) .SetMethod("setFullScreen", &Window::SetFullScreen) .SetMethod("isFullScreen", &Window::IsFullscreen) + .SetMethod("getBounds", &Window::GetBounds) + .SetMethod("setBounds", &Window::SetBounds) .SetMethod("getSize", &Window::GetSize) .SetMethod("setSize", &Window::SetSize) .SetMethod("getContentSize", &Window::GetContentSize) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 2894f0e50379..d5c3ceedd2eb 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -16,6 +16,10 @@ class GURL; +namespace gfx { +class Rect; +} + namespace mate { class Arguments; class Dictionary; @@ -85,6 +89,8 @@ class Window : public mate::EventEmitter, bool IsMinimized(); void SetFullScreen(bool fullscreen); bool IsFullscreen(); + void SetBounds(const gfx::Rect& bounds); + gfx::Rect GetBounds(); void SetSize(int width, int height); std::vector GetSize(); void SetContentSize(int width, int height); diff --git a/atom/browser/api/lib/navigation-controller.coffee b/atom/browser/api/lib/navigation-controller.coffee new file mode 100644 index 000000000000..f7945e07bf40 --- /dev/null +++ b/atom/browser/api/lib/navigation-controller.coffee @@ -0,0 +1,107 @@ +ipc = require 'ipc' + +# The history operation in renderer is redirected to browser. +ipc.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) -> + event.sender[method] args... + +# JavaScript implementation of Chromium's NavigationController. +# Instead of relying on Chromium for history control, we compeletely do history +# control on user land, and only rely on WebContents.loadUrl for navigation. +# This helps us avoid Chromium's various optimizations so we can ensure renderer +# process is restarted everytime. +class NavigationController + constructor: (@webContents) -> + @history = [] + @currentIndex = -1 + @pendingIndex = -1 + @inPageIndex = -1 + + @webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) => + if @inPageIndex > -1 and not inPage + # Navigated to a new page, clear in-page mark. + @inPageIndex = -1 + else if @inPageIndex is -1 and inPage + # Started in-page navigations. + @inPageIndex = @currentIndex + + if @pendingIndex >= 0 # Go to index. + @currentIndex = @pendingIndex + @pendingIndex = -1 + @history[@currentIndex] = url + else if replaceEntry # Non-user initialized navigation. + @history[@currentIndex] = url + else # Normal navigation. + @history = @history.slice 0, @currentIndex + 1 # Clear history. + currentEntry = @history[@currentIndex] + if currentEntry?.url isnt url + @currentIndex++ + @history.push url + + loadUrl: (url, options={}) -> + @pendingIndex = -1 + @webContents._loadUrl url, options + + getUrl: -> + if @currentIndex is -1 + '' + else + @history[@currentIndex] + + stop: -> + @pendingIndex = -1 + @webContents._stop() + + reload: -> + @pendingIndex = @currentIndex + @webContents._loadUrl @getUrl(), {} + + reloadIgnoringCache: -> + @webContents._reloadIgnoringCache() # Rely on WebContents to clear cache. + @reload() + + canGoBack: -> + @getActiveIndex() > 0 + + canGoForward: -> + @getActiveIndex() < @history.length - 1 + + canGoToIndex: (index) -> + index >=0 and index < @history.length + + canGoToOffset: (offset) -> + @canGoToIndex @currentIndex + offset + + goBack: -> + return unless @canGoBack() + @pendingIndex = @getActiveIndex() - 1 + if @inPageIndex > -1 and @pendingIndex >= @inPageIndex + @webContents._goBack() + else + @webContents._loadUrl @history[@pendingIndex], {} + + goForward: -> + return unless @canGoForward() + @pendingIndex = @getActiveIndex() + 1 + if @inPageIndex > -1 and @pendingIndex >= @inPageIndex + @webContents._goForward() + else + @webContents._loadUrl @history[@pendingIndex], {} + + goToIndex: (index) -> + return unless @canGoToIndex index + @pendingIndex = index + @webContents._loadUrl @history[@pendingIndex].url, {} + + goToOffset: (offset) -> + return unless @canGoToOffset offset + pendingIndex = @currentIndex + offset + if @inPageIndex > -1 and pendingIndex >= @inPageIndex + @pendingIndex = pendingIndex + @webContents._goToOffset offset + else + @goToIndex pendingIndex + + getActiveIndex: -> + if @pendingIndex is -1 then @currentIndex else @pendingIndex + +module.exports = NavigationController diff --git a/atom/browser/api/lib/protocol.coffee b/atom/browser/api/lib/protocol.coffee index 6eae01462b42..c2db7800c08d 100644 --- a/atom/browser/api/lib/protocol.coffee +++ b/atom/browser/api/lib/protocol.coffee @@ -30,4 +30,8 @@ protocol.RequestFileJob = class RequestFileJob constructor: (@path) -> +protocol.RequestErrorJob = +class RequestErrorJob + constructor: (@error) -> + module.exports = protocol diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index cb772fd8c27e..eb86c94500ce 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -1,4 +1,5 @@ EventEmitter = require('events').EventEmitter +NavigationController = require './navigation-controller' binding = process.atomBinding 'web_contents' ipc = require 'ipc' @@ -26,10 +27,11 @@ module.exports.wrap = (webContents) -> webContents.getId = -> "#{@getProcessId()}-#{@getRoutingId()}" webContents.equal = (other) -> @getId() is other.getId() - # Provide a default parameter for |urlOptions|. - webContents.loadUrl = (url, urlOptions={}) -> @_loadUrl url, urlOptions - webContents.reload = (urlOptions={}) -> @_reload urlOptions - webContents.reloadIgnoringCache = (urlOptions={}) -> @_reloadIgnoringCache urlOptions + # The navigation controller. + controller = new NavigationController(webContents) + for name, method of NavigationController.prototype when method instanceof Function + do (name, method) -> + webContents[name] = -> method.apply controller, arguments # Translate |disposition| to string for 'new-window' event. webContents.on '-new-window', (args..., disposition) -> diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index ef76693b2c27..fbc09d9fe15f 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -16,19 +16,25 @@ #include "base/command_line.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/printing/printing_message_filter.h" +#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h" #include "chrome/browser/speech/tts_message_filter.h" +#include "content/public/browser/browser_ppapi_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/common/web_preferences.h" +#include "ppapi/host/ppapi_host.h" #include "ui/base/l10n/l10n_util.h" namespace atom { namespace { +// Next navigation should not restart renderer process. +bool g_suppress_renderer_process_restart = false; + struct FindByProcessId { explicit FindByProcessId(int child_process_id) : child_process_id_(child_process_id) { @@ -48,8 +54,13 @@ struct FindByProcessId { } // namespace +// static +void AtomBrowserClient::SuppressRendererProcessRestartForOnce() { + g_suppress_renderer_process_restart = true; +} + AtomBrowserClient::AtomBrowserClient() - : dying_render_process_(NULL) { + : dying_render_process_(nullptr) { } AtomBrowserClient::~AtomBrowserClient() { @@ -79,7 +90,6 @@ void AtomBrowserClient::ResourceDispatcherHostCreated() { void AtomBrowserClient::OverrideWebkitPrefs( content::RenderViewHost* render_view_host, - const GURL& url, content::WebPreferences* prefs) { prefs->javascript_enabled = true; prefs->web_security_enabled = true; @@ -99,7 +109,9 @@ void AtomBrowserClient::OverrideWebkitPrefs( prefs->allow_running_insecure_content = false; // Turn off web security for devtools. - if (url.SchemeIs("chrome-devtools")) { + auto web_contents = content::WebContents::FromRenderViewHost( + render_view_host); + if (web_contents && web_contents->GetURL().SchemeIs("chrome-devtools")) { prefs->web_security_enabled = false; return; } @@ -115,30 +127,39 @@ void AtomBrowserClient::OverrideWebkitPrefs( NativeWindow* window = NativeWindow::FromRenderView( process->GetID(), render_view_host->GetRoutingID()); if (window) - window->OverrideWebkitPrefs(url, prefs); -} - -bool AtomBrowserClient::ShouldSwapBrowsingInstancesForNavigation( - content::SiteInstance* site_instance, - const GURL& current_url, - const GURL& new_url) { - if (site_instance->HasProcess()) - dying_render_process_ = site_instance->GetProcess(); - - // Restart renderer process for all navigations, this relies on a patch to - // Chromium: http://git.io/_PaNyg. - return true; + window->OverrideWebkitPrefs(prefs); } std::string AtomBrowserClient::GetApplicationLocale() { return l10n_util::GetApplicationLocale(""); } +void AtomBrowserClient::OverrideSiteInstanceForNavigation( + content::BrowserContext* browser_context, + content::SiteInstance* current_instance, + const GURL& url, + content::SiteInstance** new_instance) { + if (g_suppress_renderer_process_restart) { + g_suppress_renderer_process_restart = false; + return; + } + + if (current_instance->HasProcess()) + dying_render_process_ = current_instance->GetProcess(); + + // Restart renderer process for all navigations. + *new_instance = content::SiteInstance::CreateForURL(browser_context, url); +} + void AtomBrowserClient::AppendExtraCommandLineSwitches( base::CommandLine* command_line, int child_process_id) { + std::string process_type = command_line->GetSwitchValueASCII("type"); + if (process_type != "renderer") + return; + WindowList* list = WindowList::GetInstance(); - NativeWindow* window = NULL; + NativeWindow* window = nullptr; // Find the owner of this child process. WindowList::const_iterator iter = std::find_if( @@ -149,15 +170,25 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches( // If the render process is a newly started one, which means the window still // uses the old going-to-be-swapped render process, then we try to find the // window from the swapped render process. - if (window == NULL && dying_render_process_ != NULL) { - child_process_id = dying_render_process_->GetID(); + if (!window && dying_render_process_) { + int dying_process_id = dying_render_process_->GetID(); WindowList::const_iterator iter = std::find_if( - list->begin(), list->end(), FindByProcessId(child_process_id)); - if (iter != list->end()) + list->begin(), list->end(), FindByProcessId(dying_process_id)); + if (iter != list->end()) { window = *iter; + child_process_id = dying_process_id; + } else { + // It appears that the dying process doesn't belong to a BrowserWindow, + // then it might be a guest process, if it is we should update its + // process ID in the WebViewManager. + auto child_process = content::RenderProcessHost::FromID(child_process_id); + // Update the process ID in webview guests. + WebViewManager::UpdateGuestProcessID(dying_render_process_, + child_process); + } } - if (window != NULL) { + if (window) { window->AppendExtraCommandLineSwitches(command_line, child_process_id); } else { // Append commnad line arguments for guest web view. @@ -179,7 +210,16 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches( } } - dying_render_process_ = NULL; + dying_render_process_ = nullptr; +} + +void AtomBrowserClient::DidCreatePpapiPlugin( + content::BrowserPpapiHost* browser_host) { + auto command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kEnablePlugins)) + browser_host->GetPpapiHost()->AddHostFactoryFilter( + scoped_ptr( + new chrome::ChromeBrowserPepperHostFactory(browser_host))); } brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts( diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index f35dddac1238..cc69a1e12de8 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -18,6 +18,9 @@ class AtomBrowserClient : public brightray::BrowserClient { AtomBrowserClient(); virtual ~AtomBrowserClient(); + // Don't force renderer process to restart for once. + static void SuppressRendererProcessRestartForOnce(); + protected: // content::ContentBrowserClient: void RenderProcessWillLaunch(content::RenderProcessHost* host) override; @@ -26,15 +29,16 @@ class AtomBrowserClient : public brightray::BrowserClient { content::AccessTokenStore* CreateAccessTokenStore() override; void ResourceDispatcherHostCreated() override; void OverrideWebkitPrefs(content::RenderViewHost* render_view_host, - const GURL& url, content::WebPreferences* prefs) override; - bool ShouldSwapBrowsingInstancesForNavigation( - content::SiteInstance* site_instance, - const GURL& current_url, - const GURL& new_url) override; std::string GetApplicationLocale() override; + void OverrideSiteInstanceForNavigation( + content::BrowserContext* browser_context, + content::SiteInstance* current_instance, + const GURL& dest_url, + content::SiteInstance** new_instance); void AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id) override; + void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override; private: brightray::BrowserMainParts* OverrideCreateBrowserMainParts( diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index bcf685e6e3ac..aaf68836d0c3 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -8,7 +8,6 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/browser.h" #include "atom/browser/javascript_environment.h" -#include "atom/browser/node_debugger.h" #include "atom/common/api/atom_bindings.h" #include "atom/common/node_bindings.h" #include "base/command_line.h" @@ -60,16 +59,9 @@ void AtomBrowserMainParts::PostEarlyInitialization() { node_bindings_->Initialize(); - // Support the "--debug" switch. - node_debugger_.reset(new NodeDebugger(js_env_->isolate())); - // Create the global environment. global_env = node_bindings_->CreateEnvironment(js_env_->context()); - // Make sure node can get correct environment when debugging. - if (node_debugger_->IsRunning()) - global_env->AssignToContext(v8::Debug::GetDebugContext()); - // Add atom-shell extended APIs. atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object()); diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index a825862ff9be..6ca0686655ba 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -14,7 +14,6 @@ class AtomBindings; class Browser; class JavascriptEnvironment; class NodeBindings; -class NodeDebugger; class AtomBrowserMainParts : public brightray::BrowserMainParts { public: @@ -46,7 +45,6 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { scoped_ptr js_env_; scoped_ptr node_bindings_; scoped_ptr atom_bindings_; - scoped_ptr node_debugger_; base::Timer gc_timer_; diff --git a/atom/browser/atom_javascript_dialog_manager.cc b/atom/browser/atom_javascript_dialog_manager.cc index 8d4e10853495..c21d1fb11816 100644 --- a/atom/browser/atom_javascript_dialog_manager.cc +++ b/atom/browser/atom_javascript_dialog_manager.cc @@ -27,7 +27,6 @@ void AtomJavaScriptDialogManager::RunBeforeUnloadDialog( const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) { - bool prevent_reload = message_text.empty() || message_text == base::ASCIIToUTF16("false"); callback.Run(!prevent_reload, message_text); diff --git a/atom/browser/default_app/default_app.js b/atom/browser/default_app/default_app.js index dffe03c628e1..e471b23ae621 100644 --- a/atom/browser/default_app/default_app.js +++ b/atom/browser/default_app/default_app.js @@ -112,11 +112,12 @@ app.on('ready', function() { click: function() { mainWindow.restart(); } }, { - label: 'Enter Fullscreen', - click: function() { mainWindow.setFullScreen(true); } + label: 'Toggle Full Screen', + accelerator: 'Ctrl+Command+F', + click: function() { mainWindow.setFullScreen(!mainWindow.isFullScreen()); } }, { - label: 'Toggle DevTools', + label: 'Toggle Developer Tools', accelerator: 'Alt+Command+I', click: function() { mainWindow.toggleDevTools(); } }, @@ -144,6 +145,27 @@ app.on('ready', function() { }, ] }, + { + label: 'Help', + submenu: [ + { + label: 'Learn More', + click: function() { require('shell').openExternal('http://electron.atom.io') } + }, + { + label: 'Documentation', + click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') } + }, + { + label: 'Community Discussions', + click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') } + }, + { + label: 'Search Issues', + click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') } + } + ] + } ]; menu = Menu.buildFromTemplate(template); @@ -173,16 +195,38 @@ app.on('ready', function() { click: function() { mainWindow.restart(); } }, { - label: '&Enter Fullscreen', - click: function() { mainWindow.setFullScreen(true); } + label: 'Toggle &Full Screen', + accelerator: 'F11', + click: function() { mainWindow.setFullScreen(!mainWindow.isFullScreen()); } }, { - label: '&Toggle DevTools', + label: 'Toggle &Developer Tools', accelerator: 'Alt+Ctrl+I', click: function() { mainWindow.toggleDevTools(); } }, ] }, + { + label: 'Help', + submenu: [ + { + label: 'Learn More', + click: function() { require('shell').openExternal('http://electron.atom.io') } + }, + { + label: 'Documentation', + click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') } + }, + { + label: 'Community Discussions', + click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') } + }, + { + label: 'Search Issues', + click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') } + } + ] + } ]; menu = Menu.buildFromTemplate(template); diff --git a/atom/browser/default_app/main.js b/atom/browser/default_app/main.js index bdb88a7cc29a..5664fac4cd21 100644 --- a/atom/browser/default_app/main.js +++ b/atom/browser/default_app/main.js @@ -11,11 +11,14 @@ app.on('window-all-closed', function() { // Parse command line options. var argv = process.argv.slice(1); -var option = { file: null, version: null, webdriver: null }; +var option = { file: null, help: null, version: null, webdriver: null }; for (var i in argv) { if (argv[i] == '--version' || argv[i] == '-v') { option.version = true; break; + } else if (argv[i] == '--help' || argv[i] == '-h') { + option.help = true; + break; } else if (argv[i] == '--test-type=webdriver') { option.webdriver = true; } else if (argv[i][0] == '-') { @@ -58,7 +61,17 @@ if (option.file && !option.webdriver) { } } } else if (option.version) { - console.log('v' + process.versions['electron']); + console.log('v' + process.versions.electron); + process.exit(0); +} else if (option.help) { + var helpMessage = "Electron v" + process.versions.electron + " - Cross Platform Desktop Application Shell\n\n"; + helpMessage += "Usage: electron [options] [path]\n\n"; + helpMessage += "A path to an Electron application may be specified. The path must be to \n"; + helpMessage += "an index.js file or to a folder containing a package.json or index.js file.\n\n"; + helpMessage += "Options:\n"; + helpMessage += " -h, --help Print this usage message.\n"; + helpMessage += " -v, --version Print the version."; + console.log(helpMessage); process.exit(0); } else { require('./default_app.js'); diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index 51fb9424670f..43f4d7c98c5f 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -10,12 +10,14 @@ supportedWebViewEvents = [ 'did-stop-loading' 'did-get-response-details' 'did-get-redirect-request' + 'dom-ready' 'console-message' 'new-window' 'close' 'crashed' 'destroyed' 'page-title-set' + 'page-favicon-updated' ] nextInstanceId = 0 diff --git a/atom/browser/lib/init.coffee b/atom/browser/lib/init.coffee index 9ef590dc6265..cbee13655416 100644 --- a/atom/browser/lib/init.coffee +++ b/atom/browser/lib/init.coffee @@ -1,15 +1,15 @@ fs = require 'fs' path = require 'path' -module = require 'module' util = require 'util' +Module = require 'module' # We modified the original process.argv to let node.js load the atom.js, # we need to restore it here. process.argv.splice 1, 1 -# Add browser/api/lib to require's search paths, -# which contains javascript part of Atom's built-in libraries. -globalPaths = module.globalPaths +# Add browser/api/lib to module search paths, which contains javascript part of +# Electron's built-in libraries. +globalPaths = Module.globalPaths globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') # Import common settings. @@ -81,6 +81,9 @@ if packageJson.desktopName? else app.setDesktopName "#{app.getName()}.desktop" +# Chrome 42 disables NPAPI plugins by default, reenable them here +app.commandLine.appendSwitch 'enable-npapi' + # Set the user path according to application's name. app.setPath 'userData', path.join(app.getPath('appData'), app.getName()) app.setPath 'userCache', path.join(app.getPath('cache'), app.getName()) @@ -89,4 +92,4 @@ app.setPath 'userCache', path.join(app.getPath('cache'), app.getName()) require './chrome-extension' # Finally load app's main.js and transfer control to C++. -module._load path.join(packagePath, packageJson.main), module, true +Module._load path.join(packagePath, packageJson.main), Module, true diff --git a/atom/browser/lib/rpc-server.coffee b/atom/browser/lib/rpc-server.coffee index 1703f1e24751..48d00e9bd23b 100644 --- a/atom/browser/lib/rpc-server.coffee +++ b/atom/browser/lib/rpc-server.coffee @@ -107,6 +107,9 @@ ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, guestInstanceId) -> catch e event.returnValue = errorToMeta e +ipc.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) -> + event.returnValue = valueToMeta event.sender, event.sender + ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) -> try args = unwrapArgs event.sender, args diff --git a/atom/browser/mac/atom_application.h b/atom/browser/mac/atom_application.h index a41802087722..9fafb054b09a 100644 --- a/atom/browser/mac/atom_application.h +++ b/atom/browser/mac/atom_application.h @@ -18,6 +18,4 @@ // CrAppControlProtocol: - (void)setHandlingSendEvent:(BOOL)handlingSendEvent; -- (IBAction)closeAllWindows:(id)sender; - @end diff --git a/atom/browser/mac/atom_application.mm b/atom/browser/mac/atom_application.mm index b8377181359c..9eaabc410bda 100644 --- a/atom/browser/mac/atom_application.mm +++ b/atom/browser/mac/atom_application.mm @@ -36,10 +36,6 @@ andEventID:kAEGetURL]; } -- (IBAction)closeAllWindows:(id)sender { - atom::Browser::Get()->Quit(); -} - - (void)handleURLEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent { NSString* url = [ diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 739f1b3a2358..5bef1acfb872 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -192,7 +192,7 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) { int width = -1, height = -1; options.Get(switches::kWidth, &width); options.Get(switches::kHeight, &height); - Move(gfx::Rect(x, y, width, height)); + SetBounds(gfx::Rect(x, y, width, height)); } else if (options.Get(switches::kCenter, ¢er) && center) { Center(); } @@ -237,6 +237,22 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) { Show(); } +void NativeWindow::SetSize(const gfx::Size& size) { + SetBounds(gfx::Rect(GetPosition(), size)); +} + +gfx::Size NativeWindow::GetSize() { + return GetBounds().size(); +} + +void NativeWindow::SetPosition(const gfx::Point& position) { + SetBounds(gfx::Rect(position, GetSize())); +} + +gfx::Point NativeWindow::GetPosition() { + return GetBounds().origin(); +} + void NativeWindow::SetRepresentedFilename(const std::string& filename) { } @@ -435,8 +451,7 @@ void NativeWindow::AppendExtraCommandLineSwitches( } } -void NativeWindow::OverrideWebkitPrefs(const GURL& url, - content::WebPreferences* prefs) { +void NativeWindow::OverrideWebkitPrefs(content::WebPreferences* prefs) { if (web_preferences_.IsEmpty()) return; @@ -566,6 +581,7 @@ content::WebContents* NativeWindow::OpenURLFromTab( load_url_params.is_renderer_initiated = params.is_renderer_initiated; load_url_params.transferred_global_request_id = params.transferred_global_request_id; + load_url_params.should_clear_history_list = true; source->GetController().LoadURLWithParams(load_url_params); return source; @@ -646,8 +662,7 @@ void NativeWindow::DeactivateContents(content::WebContents* contents) { void NativeWindow::MoveContents(content::WebContents* source, const gfx::Rect& pos) { - SetPosition(pos.origin()); - SetSize(pos.size()); + SetBounds(pos); } void NativeWindow::CloseContents(content::WebContents* source) { @@ -686,6 +701,20 @@ void NativeWindow::RendererResponsive(content::WebContents* source) { FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive()); } +void NativeWindow::EnterFullscreenModeForTab(content::WebContents* source, + const GURL& origin) { + SetFullScreen(true); +} + +void NativeWindow::ExitFullscreenModeForTab(content::WebContents* source) { + SetFullScreen(false); +} + +bool NativeWindow::IsFullscreenForTabOrPending( + const content::WebContents* source) const { + return IsFullscreen(); +} + void NativeWindow::BeforeUnloadFired(const base::TimeTicks& proceed_time) { // Do nothing, we override this method just to avoid compilation error since // there are two virtual functions named BeforeUnloadFired. diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index d7661bf7487d..32c3493cdbf8 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -98,7 +98,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate, virtual void Close() = 0; virtual void CloseImmediately() = 0; - virtual void Move(const gfx::Rect& pos) = 0; virtual void Focus(bool focus) = 0; virtual bool IsFocused() = 0; virtual void Show() = 0; @@ -112,9 +111,13 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate, virtual void Restore() = 0; virtual bool IsMinimized() = 0; virtual void SetFullScreen(bool fullscreen) = 0; - virtual bool IsFullscreen() = 0; - virtual void SetSize(const gfx::Size& size) = 0; - virtual gfx::Size GetSize() = 0; + virtual bool IsFullscreen() const = 0; + virtual void SetBounds(const gfx::Rect& bounds) = 0; + virtual gfx::Rect GetBounds() = 0; + virtual void SetSize(const gfx::Size& size); + virtual gfx::Size GetSize(); + virtual void SetPosition(const gfx::Point& position); + virtual gfx::Point GetPosition(); virtual void SetContentSize(const gfx::Size& size) = 0; virtual gfx::Size GetContentSize() = 0; virtual void SetMinimumSize(const gfx::Size& size) = 0; @@ -126,8 +129,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate, virtual void SetAlwaysOnTop(bool top) = 0; virtual bool IsAlwaysOnTop() = 0; virtual void Center() = 0; - virtual void SetPosition(const gfx::Point& position) = 0; - virtual gfx::Point GetPosition() = 0; virtual void SetTitle(const std::string& title) = 0; virtual std::string GetTitle() = 0; virtual void FlashFrame(bool flash) = 0; @@ -192,7 +193,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate, // Called when renderer process is going to be started. void AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id); - void OverrideWebkitPrefs(const GURL& url, content::WebPreferences* prefs); + void OverrideWebkitPrefs(content::WebPreferences* prefs); // Public API used by platform-dependent delegates and observers to send UI // related notifications. @@ -273,6 +274,11 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate, const content::WebContents* source) const override; void RendererUnresponsive(content::WebContents* source) override; void RendererResponsive(content::WebContents* source) override; + void EnterFullscreenModeForTab(content::WebContents* source, + const GURL& origin) override; + void ExitFullscreenModeForTab(content::WebContents* source) override; + bool IsFullscreenForTabOrPending( + const content::WebContents* source) const override; // Implementations of content::WebContentsObserver. void RenderViewCreated(content::RenderViewHost* render_view_host) override; diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index d21b207841e2..8a6d141c34bf 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -30,7 +30,6 @@ class NativeWindowMac : public NativeWindow { // NativeWindow implementation. void Close() override; void CloseImmediately() override; - void Move(const gfx::Rect& pos) override; void Focus(bool focus) override; bool IsFocused() override; void Show() override; @@ -44,9 +43,9 @@ class NativeWindowMac : public NativeWindow { void Restore() override; bool IsMinimized() override; void SetFullScreen(bool fullscreen) override; - bool IsFullscreen() override; - void SetSize(const gfx::Size& size) override; - gfx::Size GetSize() override; + bool IsFullscreen() const override; + void SetBounds(const gfx::Rect& bounds) override; + gfx::Rect GetBounds() override; void SetContentSize(const gfx::Size& size) override; gfx::Size GetContentSize() override; void SetMinimumSize(const gfx::Size& size) override; @@ -58,8 +57,6 @@ class NativeWindowMac : public NativeWindow { void SetAlwaysOnTop(bool top) override; bool IsAlwaysOnTop() override; void Center() override; - void SetPosition(const gfx::Point& position) override; - gfx::Point GetPosition() override; void SetTitle(const std::string& title) override; std::string GetTitle() override; void FlashFrame(bool flash) override; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 668826624b4b..8dd6bcbacbe1 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -11,14 +11,14 @@ #include "atom/common/options_switches.h" #include "base/mac/mac_util.h" #include "base/strings/sys_string_conversions.h" +#include "brightray/browser/inspectable_web_contents.h" +#include "brightray/browser/inspectable_web_contents_view.h" #include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "native_mate/dictionary.h" -#include "vendor/brightray/browser/inspectable_web_contents.h" -#include "vendor/brightray/browser/inspectable_web_contents_view.h" static const CGFloat kAtomWindowCornerRadius = 4.0; @@ -54,10 +54,8 @@ static const CGFloat kAtomWindowCornerRadius = 4.0; @interface AtomNSWindowDelegate : NSObject { @private atom::NativeWindowMac* shell_; - BOOL acceptsFirstMouse_; } - (id)initWithShell:(atom::NativeWindowMac*)shell; -- (void)setAcceptsFirstMouse:(BOOL)accept; @end @implementation AtomNSWindowDelegate @@ -65,15 +63,10 @@ static const CGFloat kAtomWindowCornerRadius = 4.0; - (id)initWithShell:(atom::NativeWindowMac*)shell { if ((self = [super init])) { shell_ = shell; - acceptsFirstMouse_ = NO; } return self; } -- (void)setAcceptsFirstMouse:(BOOL)accept { - acceptsFirstMouse_ = accept; -} - - (void)windowDidBecomeMain:(NSNotification*)notification { content::WebContents* web_contents = shell_->GetWebContents(); if (!web_contents) @@ -151,10 +144,6 @@ static const CGFloat kAtomWindowCornerRadius = 4.0; return NO; } -- (BOOL)acceptsFirstMouse:(NSEvent*)event { - return acceptsFirstMouse_; -} - @end @interface AtomNSWindow : EventProcessingWindow { @@ -162,6 +151,8 @@ static const CGFloat kAtomWindowCornerRadius = 4.0; atom::NativeWindowMac* shell_; bool enable_larger_than_screen_; } +@property BOOL acceptsFirstMouse; +@property BOOL disableAutoHideCursor; - (void)setShell:(atom::NativeWindowMac*)shell; - (void)setEnableLargerThanScreen:(bool)enable; @end @@ -184,16 +175,6 @@ static const CGFloat kAtomWindowCornerRadius = 4.0; return [super constrainFrameRect:frameRect toScreen:screen]; } -- (IBAction)reload:(id)sender { - content::WebContents* web_contents = shell_->GetWebContents(); - content::NavigationController::LoadURLParams params(web_contents->GetURL()); - web_contents->GetController().LoadURLWithParams(params); -} - -- (IBAction)showDevTools:(id)sender { - shell_->OpenDevTools(true); -} - - (id)accessibilityAttributeValue:(NSString*)attribute { if (![attribute isEqualToString:@"AXChildren"]) return [super accessibilityAttributeValue:attribute]; @@ -329,11 +310,18 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents, width, height); + bool useStandardWindow = true; + options.Get(switches::kStandardWindow, &useStandardWindow); + + NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | NSResizableWindowMask; + if (!useStandardWindow) { + styleMask |= NSTexturedBackgroundWindowMask; + } + window_.reset([[AtomNSWindow alloc] initWithContentRect:cocoa_bounds - styleMask:NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSResizableWindowMask | - NSTexturedBackgroundWindowMask + styleMask:styleMask backing:NSBackingStoreBuffered defer:YES]); [window_ setShell:this]; @@ -349,6 +337,10 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents, [window_ setBackgroundColor:[NSColor clearColor]]; } + // Remove non-transparent corners, see http://git.io/vfonD. + if (!has_frame_) + [window_ setOpaque:NO]; + // We will manage window's lifetime ourselves. [window_ setReleasedWhenClosed:NO]; @@ -361,7 +353,12 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents, // Enable the NSView to accept first mouse event. bool acceptsFirstMouse = false; options.Get(switches::kAcceptFirstMouse, &acceptsFirstMouse); - [window_delegate_ setAcceptsFirstMouse:acceptsFirstMouse]; + [window_ setAcceptsFirstMouse:acceptsFirstMouse]; + + // Disable auto-hiding cursor. + bool disableAutoHideCursor = false; + options.Get(switches::kDisableAutoHideCursor, &disableAutoHideCursor); + [window_ setDisableAutoHideCursor:disableAutoHideCursor]; // Disable fullscreen button when 'fullscreen' is specified to false. bool fullscreen; @@ -392,18 +389,6 @@ void NativeWindowMac::CloseImmediately() { [window_ close]; } -void NativeWindowMac::Move(const gfx::Rect& pos) { - NSRect cocoa_bounds = NSMakeRect(pos.x(), 0, - pos.width(), - pos.height()); - // Flip coordinates based on the primary screen. - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; - cocoa_bounds.origin.y = - NSHeight([screen frame]) - pos.height() - pos.y(); - - [window_ setFrame:cocoa_bounds display:YES]; -} - void NativeWindowMac::Focus(bool focus) { if (!IsVisible()) return; @@ -476,22 +461,28 @@ void NativeWindowMac::SetFullScreen(bool fullscreen) { [window_ toggleFullScreen:nil]; } -bool NativeWindowMac::IsFullscreen() { +bool NativeWindowMac::IsFullscreen() const { return [window_ styleMask] & NSFullScreenWindowMask; } -void NativeWindowMac::SetSize(const gfx::Size& size) { - NSRect frame = [window_ frame]; - frame.origin.y -= size.height() - frame.size.height; - frame.size.width = size.width(); - frame.size.height = size.height(); +void NativeWindowMac::SetBounds(const gfx::Rect& bounds) { + NSRect cocoa_bounds = NSMakeRect(bounds.x(), 0, + bounds.width(), + bounds.height()); + // Flip coordinates based on the primary screen. + NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; + cocoa_bounds.origin.y = + NSHeight([screen frame]) - bounds.height() - bounds.y(); - [window_ setFrame:frame display:YES]; + [window_ setFrame:cocoa_bounds display:YES]; } -gfx::Size NativeWindowMac::GetSize() { +gfx::Rect NativeWindowMac::GetBounds() { NSRect frame = [window_ frame]; - return gfx::Size(frame.size.width, frame.size.height); + gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame)); + NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; + bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame)); + return bounds; } void NativeWindowMac::SetContentSize(const gfx::Size& size) { @@ -564,18 +555,6 @@ void NativeWindowMac::Center() { [window_ center]; } -void NativeWindowMac::SetPosition(const gfx::Point& position) { - Move(gfx::Rect(position, GetSize())); -} - -gfx::Point NativeWindowMac::GetPosition() { - NSRect frame = [window_ frame]; - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; - - return gfx::Point(frame.origin.x, - NSHeight([screen frame]) - frame.origin.y - frame.size.height); -} - void NativeWindowMac::SetTitle(const std::string& title) { // We don't want the title to show in transparent window. if (transparent_) diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 9dc0709946de..4c99f88969ba 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -291,10 +291,6 @@ void NativeWindowViews::CloseImmediately() { window_->CloseNow(); } -void NativeWindowViews::Move(const gfx::Rect& bounds) { - window_->SetBounds(bounds); -} - void NativeWindowViews::Focus(bool focus) { if (focus) window_->Activate(); @@ -369,40 +365,41 @@ void NativeWindowViews::SetFullScreen(bool fullscreen) { #endif } -bool NativeWindowViews::IsFullscreen() { +bool NativeWindowViews::IsFullscreen() const { return window_->IsFullscreen(); } -void NativeWindowViews::SetSize(const gfx::Size& size) { +void NativeWindowViews::SetBounds(const gfx::Rect& bounds) { #if defined(USE_X11) // On Linux the minimum and maximum size should be updated with window size // when window is not resizable. if (!resizable_) { - SetMaximumSize(size); - SetMinimumSize(size); + SetMaximumSize(bounds.size()); + SetMinimumSize(bounds.size()); } #endif - window_->SetSize(size); + window_->SetBounds(bounds); } -gfx::Size NativeWindowViews::GetSize() { +gfx::Rect NativeWindowViews::GetBounds() { #if defined(OS_WIN) if (IsMinimized()) - return window_->GetRestoredBounds().size(); + return window_->GetRestoredBounds(); #endif - return window_->GetWindowBoundsInScreen().size(); + return window_->GetWindowBoundsInScreen(); } void NativeWindowViews::SetContentSize(const gfx::Size& size) { if (!has_frame_) { - SetSize(size); + NativeWindow::SetSize(size); return; } gfx::Rect bounds = window_->GetWindowBoundsInScreen(); - SetSize(ContentBoundsToWindowBounds(gfx::Rect(bounds.origin(), size)).size()); + bounds.set_size(size); + SetBounds(ContentBoundsToWindowBounds(bounds)); } gfx::Size NativeWindowViews::GetContentSize() { @@ -492,19 +489,6 @@ void NativeWindowViews::Center() { window_->CenterWindow(GetSize()); } -void NativeWindowViews::SetPosition(const gfx::Point& position) { - window_->SetBounds(gfx::Rect(position, GetSize())); -} - -gfx::Point NativeWindowViews::GetPosition() { -#if defined(OS_WIN) - if (IsMinimized()) - return window_->GetRestoredBounds().origin(); -#endif - - return window_->GetWindowBoundsInScreen().origin(); -} - void NativeWindowViews::SetTitle(const std::string& title) { title_ = title; window_->UpdateWindowTitle(); diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 56d77afa2680..15f073d8d8c1 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -35,7 +35,6 @@ class NativeWindowViews : public NativeWindow, // NativeWindow: void Close() override; void CloseImmediately() override; - void Move(const gfx::Rect& pos) override; void Focus(bool focus) override; bool IsFocused() override; void Show() override; @@ -49,9 +48,9 @@ class NativeWindowViews : public NativeWindow, void Restore() override; bool IsMinimized() override; void SetFullScreen(bool fullscreen) override; - bool IsFullscreen() override; - void SetSize(const gfx::Size& size) override; - gfx::Size GetSize() override; + bool IsFullscreen() const override; + void SetBounds(const gfx::Rect& bounds) override; + gfx::Rect GetBounds() override; void SetContentSize(const gfx::Size& size) override; gfx::Size GetContentSize() override; void SetMinimumSize(const gfx::Size& size) override; @@ -63,8 +62,6 @@ class NativeWindowViews : public NativeWindow, void SetAlwaysOnTop(bool top) override; bool IsAlwaysOnTop() override; void Center() override; - void SetPosition(const gfx::Point& position) override; - gfx::Point GetPosition() override; void SetTitle(const std::string& title) override; std::string GetTitle() override; void FlashFrame(bool flash) override; diff --git a/atom/browser/net/adapter_request_job.cc b/atom/browser/net/adapter_request_job.cc index 86c82d7836ce..8b562bcbf248 100644 --- a/atom/browser/net/adapter_request_job.cc +++ b/atom/browser/net/adapter_request_job.cc @@ -5,10 +5,10 @@ #include "atom/browser/net/adapter_request_job.h" #include "base/threading/sequenced_worker_pool.h" +#include "atom/browser/net/url_request_buffer_job.h" #include "atom/browser/net/url_request_string_job.h" #include "atom/browser/net/asar/url_request_asar_job.h" #include "atom/common/asar/asar_util.h" -#include "atom/browser/net/url_request_buffer_job.h" #include "content/public/browser/browser_thread.h" #include "net/base/net_errors.h" #include "net/url_request/url_request_error_job.h" diff --git a/atom/browser/node_debugger.cc b/atom/browser/node_debugger.cc deleted file mode 100644 index 4e2302763c7e..000000000000 --- a/atom/browser/node_debugger.cc +++ /dev/null @@ -1,202 +0,0 @@ -// 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/browser/node_debugger.h" - -#include - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "content/public/browser/browser_thread.h" -#include "net/socket/tcp_listen_socket.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace { - -// NodeDebugger is stored in Isolate's data, slots 0, 1, 3 have already been -// taken by gin, blink and node, using 2 is a safe option for now. -const int kIsolateSlot = 2; - -const char* kContentLength = "Content-Length"; - -} // namespace - -NodeDebugger::NodeDebugger(v8::Isolate* isolate) - : isolate_(isolate), - thread_("NodeDebugger"), - content_length_(-1), - weak_factory_(this) { - bool use_debug_agent = false; - int port = 5858; - bool wait_for_connection = false; - - std::string port_str; - base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); - if (cmd->HasSwitch("debug")) { - use_debug_agent = true; - port_str = cmd->GetSwitchValueASCII("debug"); - } - if (cmd->HasSwitch("debug-brk")) { - use_debug_agent = true; - wait_for_connection = true; - port_str = cmd->GetSwitchValueASCII("debug-brk"); - } - - if (use_debug_agent) { - if (!port_str.empty()) - base::StringToInt(port_str, &port); - - isolate_->SetData(kIsolateSlot, this); - v8::Debug::SetMessageHandler(DebugMessageHandler); - - if (wait_for_connection) - v8::Debug::DebugBreak(isolate_); - - // Start a new IO thread. - base::Thread::Options options; - options.message_loop_type = base::MessageLoop::TYPE_IO; - if (!thread_.StartWithOptions(options)) { - LOG(ERROR) << "Unable to start debugger thread"; - return; - } - - // Start the server in new IO thread. - thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&NodeDebugger::StartServer, weak_factory_.GetWeakPtr(), - port)); - } -} - -NodeDebugger::~NodeDebugger() { - thread_.Stop(); -} - -bool NodeDebugger::IsRunning() const { - return thread_.IsRunning(); -} - -void NodeDebugger::StartServer(int port) { - server_ = net::TCPListenSocket::CreateAndListen("127.0.0.1", port, this); - if (!server_) { - LOG(ERROR) << "Cannot start debugger server"; - return; - } -} - -void NodeDebugger::CloseSession() { - accepted_socket_.reset(); -} - -void NodeDebugger::OnMessage(const std::string& message) { - if (message.find("\"type\":\"request\",\"command\":\"disconnect\"}") != - std::string::npos) - CloseSession(); - - base::string16 message16 = base::UTF8ToUTF16(message); - v8::Debug::SendCommand( - isolate_, - reinterpret_cast(message16.data()), message16.size()); - - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&v8::Debug::ProcessDebugMessages)); -} - -void NodeDebugger::SendMessage(const std::string& message) { - if (accepted_socket_) { - std::string header = base::StringPrintf( - "%s: %d\r\n\r\n", kContentLength, static_cast(message.size())); - accepted_socket_->Send(header); - accepted_socket_->Send(message); - } -} - -void NodeDebugger::SendConnectMessage() { - accepted_socket_->Send(base::StringPrintf( - "Type: connect\r\n" - "V8-Version: %s\r\n" - "Protocol-Version: 1\r\n" - "Embedding-Host: %s\r\n" - "%s: 0\r\n", - v8::V8::GetVersion(), ATOM_PRODUCT_NAME, kContentLength), true); -} - -// static -void NodeDebugger::DebugMessageHandler(const v8::Debug::Message& message) { - NodeDebugger* self = static_cast( - message.GetIsolate()->GetData(kIsolateSlot)); - - if (self) { - std::string message8(*v8::String::Utf8Value(message.GetJSON())); - self->thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&NodeDebugger::SendMessage, self->weak_factory_.GetWeakPtr(), - message8)); - } -} - -void NodeDebugger::DidAccept(net::StreamListenSocket* server, - scoped_ptr socket) { - // Only accept one session. - if (accepted_socket_) { - socket->Send(std::string("Remote debugging session already active"), true); - return; - } - - accepted_socket_ = socket.Pass(); - SendConnectMessage(); -} - -void NodeDebugger::DidRead(net::StreamListenSocket* socket, - const char* data, - int len) { - buffer_.append(data, len); - - do { - if (buffer_.size() == 0) - return; - - // Read the "Content-Length" header. - if (content_length_ < 0) { - size_t pos = buffer_.find("\r\n\r\n"); - if (pos == std::string::npos) - return; - - // We can be sure that the header is "Content-Length: xxx\r\n". - std::string content_length = buffer_.substr(16, pos - 16); - if (!base::StringToInt(content_length, &content_length_)) { - DidClose(accepted_socket_.get()); - return; - } - - // Strip header from buffer. - buffer_ = buffer_.substr(pos + 4); - } - - // Read the message. - if (buffer_.size() >= static_cast(content_length_)) { - std::string message = buffer_.substr(0, content_length_); - buffer_ = buffer_.substr(content_length_); - - OnMessage(message); - - // Get ready for next message. - content_length_ = -1; - } - } while (true); -} - -void NodeDebugger::DidClose(net::StreamListenSocket* socket) { - // If we lost the connection, then simulate a disconnect msg: - OnMessage("{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}"); -} - -} // namespace atom diff --git a/atom/browser/node_debugger.h b/atom/browser/node_debugger.h deleted file mode 100644 index 6ee5b1e20688..000000000000 --- a/atom/browser/node_debugger.h +++ /dev/null @@ -1,59 +0,0 @@ -// 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_BROWSER_NODE_DEBUGGER_H_ -#define ATOM_BROWSER_NODE_DEBUGGER_H_ - -#include - -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread.h" -#include "net/socket/stream_listen_socket.h" -#include "v8/include/v8-debug.h" - -namespace atom { - -// Add support for node's "--debug" switch. -class NodeDebugger : public net::StreamListenSocket::Delegate { - public: - explicit NodeDebugger(v8::Isolate* isolate); - virtual ~NodeDebugger(); - - bool IsRunning() const; - - private: - void StartServer(int port); - void CloseSession(); - void OnMessage(const std::string& message); - void SendMessage(const std::string& message); - void SendConnectMessage(); - - static void DebugMessageHandler(const v8::Debug::Message& message); - - // net::StreamListenSocket::Delegate: - void DidAccept(net::StreamListenSocket* server, - scoped_ptr socket) override; - void DidRead(net::StreamListenSocket* socket, - const char* data, - int len) override; - void DidClose(net::StreamListenSocket* socket) override; - - v8::Isolate* isolate_; - - base::Thread thread_; - scoped_ptr server_; - scoped_ptr accepted_socket_; - - std::string buffer_; - int content_length_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(NodeDebugger); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NODE_DEBUGGER_H_ diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 556419142bf7..406dc84403f2 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,7 +17,7 @@ CFBundleIconFile atom.icns CFBundleVersion - 0.24.0 + 0.26.0 LSMinimumSystemVersion 10.8.0 NSMainNibFile diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 9004d559012d..2de44863443c 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,24,0,0 - PRODUCTVERSION 0,24,0,0 + FILEVERSION 0,26,0,0 + PRODUCTVERSION 0,26,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "0.24.0" + VALUE "FileVersion", "0.26.0" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "0.24.0" + VALUE "ProductVersion", "0.26.0" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/browser/ui/accelerator_util.cc b/atom/browser/ui/accelerator_util.cc index 4978b102c525..87e56d063d7e 100644 --- a/atom/browser/ui/accelerator_util.cc +++ b/atom/browser/ui/accelerator_util.cc @@ -109,8 +109,12 @@ bool StringToAccelerator(const std::string& description, modifiers |= ui::EF_SHIFT_DOWN; } else if (tokens[i] == "ctrl" || tokens[i] == "control") { modifiers |= ui::EF_CONTROL_DOWN; + } else if (tokens[i] == "super") { + modifiers |= ui::EF_COMMAND_DOWN; +#if defined(OS_MACOSX) } else if (tokens[i] == "cmd" || tokens[i] == "command") { modifiers |= ui::EF_COMMAND_DOWN; +#endif } else if (tokens[i] == "commandorcontrol" || tokens[i] == "cmdorctrl") { #if defined(OS_MACOSX) modifiers |= ui::EF_COMMAND_DOWN; @@ -171,7 +175,7 @@ bool StringToAccelerator(const std::string& description, } else if (tokens[i].size() > 1 && tokens[i][0] == 'f') { // F1 - F24. int n; - if (base::StringToInt(tokens[i].c_str() + 1, &n)) { + if (base::StringToInt(tokens[i].c_str() + 1, &n) && n > 0 && n < 25) { key = static_cast(ui::VKEY_F1 + n - 1); } else { LOG(WARNING) << tokens[i] << "is not available on keyboard"; diff --git a/atom/browser/ui/tray_icon.cc b/atom/browser/ui/tray_icon.cc index 68770c1e5cfd..a3878f718a62 100644 --- a/atom/browser/ui/tray_icon.cc +++ b/atom/browser/ui/tray_icon.cc @@ -26,8 +26,8 @@ void TrayIcon::DisplayBalloon(const gfx::Image& icon, const base::string16& contents) { } -void TrayIcon::NotifyClicked() { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked()); +void TrayIcon::NotifyClicked(const gfx::Rect& bounds) { + FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds)); } void TrayIcon::NotifyDoubleClicked() { diff --git a/atom/browser/ui/tray_icon.h b/atom/browser/ui/tray_icon.h index 6293b39002b6..7dc67da1bac4 100644 --- a/atom/browser/ui/tray_icon.h +++ b/atom/browser/ui/tray_icon.h @@ -10,6 +10,7 @@ #include "atom/browser/ui/tray_icon_observer.h" #include "base/observer_list.h" #include "ui/base/models/simple_menu_model.h" +#include "ui/gfx/geometry/rect.h" namespace atom { @@ -50,7 +51,7 @@ class TrayIcon { void AddObserver(TrayIconObserver* obs) { observers_.AddObserver(obs); } void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); } - void NotifyClicked(); + void NotifyClicked(const gfx::Rect& = gfx::Rect()); void NotifyDoubleClicked(); void NotifyBalloonShow(); void NotifyBalloonClicked(); diff --git a/atom/browser/ui/tray_icon_cocoa.mm b/atom/browser/ui/tray_icon_cocoa.mm index db2508ecc6a4..f989b9b580e2 100644 --- a/atom/browser/ui/tray_icon_cocoa.mm +++ b/atom/browser/ui/tray_icon_cocoa.mm @@ -7,6 +7,7 @@ #include "atom/browser/ui/cocoa/atom_menu_controller.h" #include "base/strings/sys_string_conversions.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/screen.h" @interface StatusItemController : NSObject { atom::TrayIconCocoa* trayIcon_; // weak @@ -25,7 +26,14 @@ } - (void)handleClick:(id)sender { - trayIcon_->NotifyClicked(); + // Get the frame of the NSStatusItem. + NSRect frame = [NSApp currentEvent].window.frame; + gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame)); + // Flip coordinates to gfx (0,0 in top-left corner) using current screen. + NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; + bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame)); + + trayIcon_->NotifyClicked(bounds); } - (void)handleDoubleClick:(id)sender { diff --git a/atom/browser/ui/tray_icon_observer.h b/atom/browser/ui/tray_icon_observer.h index 293e5371c4cf..3a34888b5318 100644 --- a/atom/browser/ui/tray_icon_observer.h +++ b/atom/browser/ui/tray_icon_observer.h @@ -5,11 +5,15 @@ #ifndef ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_ #define ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_ +namespace gfx { +class Rect; +} + namespace atom { class TrayIconObserver { public: - virtual void OnClicked() {} + virtual void OnClicked(const gfx::Rect&) {} virtual void OnDoubleClicked() {} virtual void OnBalloonShow() {} virtual void OnBalloonClicked() {} diff --git a/atom/browser/web_view_manager.cc b/atom/browser/web_view_manager.cc index 1fda008d0dc5..77a772da9adf 100644 --- a/atom/browser/web_view_manager.cc +++ b/atom/browser/web_view_manager.cc @@ -10,18 +10,42 @@ namespace atom { +namespace { + +WebViewManager* GetManagerFromProcess(content::RenderProcessHost* process) { + if (!process) + return nullptr; + auto context = process->GetBrowserContext(); + if (!context) + return nullptr; + return static_cast(context->GetGuestManager()); +} + +} // namespace + // static bool WebViewManager::GetInfoForProcess(content::RenderProcessHost* process, WebViewInfo* info) { - if (!process) - return false; - auto context = process->GetBrowserContext(); - if (!context) - return false; - auto manager = context->GetGuestManager(); + auto manager = GetManagerFromProcess(process); if (!manager) return false; - return static_cast(manager)->GetInfo(process->GetID(), info); + return manager->GetInfo(process->GetID(), info); +} + +// static +void WebViewManager::UpdateGuestProcessID( + content::RenderProcessHost* old_process, + content::RenderProcessHost* new_process) { + auto manager = GetManagerFromProcess(old_process); + if (manager) { + base::AutoLock auto_lock(manager->lock_); + int old_id = old_process->GetID(); + int new_id = new_process->GetID(); + if (!ContainsKey(manager->webview_info_map_, old_id)) + return; + manager->webview_info_map_[new_id] = manager->webview_info_map_[old_id]; + manager->webview_info_map_.erase(old_id); + } } WebViewManager::WebViewManager(content::BrowserContext* context) { @@ -42,7 +66,8 @@ void WebViewManager::AddGuest(int guest_instance_id, webview_info_map_[guest_process_id] = info; // Map the element in embedder to guest. - ElementInstanceKey key(embedder, element_instance_id); + int owner_process_id = embedder->GetRenderProcessHost()->GetID(); + ElementInstanceKey key(owner_process_id, element_instance_id); element_instance_id_to_guest_map_[key] = guest_instance_id; } @@ -76,9 +101,9 @@ bool WebViewManager::GetInfo(int guest_process_id, WebViewInfo* webview_info) { } content::WebContents* WebViewManager::GetGuestByInstanceID( - content::WebContents* embedder, + int owner_process_id, int element_instance_id) { - ElementInstanceKey key(embedder, element_instance_id); + ElementInstanceKey key(owner_process_id, element_instance_id); if (!ContainsKey(element_instance_id_to_guest_map_, key)) return nullptr; diff --git a/atom/browser/web_view_manager.h b/atom/browser/web_view_manager.h index f87284c39e82..2327b2e02b4c 100644 --- a/atom/browser/web_view_manager.h +++ b/atom/browser/web_view_manager.h @@ -34,6 +34,10 @@ class WebViewManager : public content::BrowserPluginGuestManager { static bool GetInfoForProcess(content::RenderProcessHost* process, WebViewInfo* info); + // Updates the guest process ID. + static void UpdateGuestProcessID(content::RenderProcessHost* old_process, + content::RenderProcessHost* new_process); + explicit WebViewManager(content::BrowserContext* context); virtual ~WebViewManager(); @@ -50,9 +54,8 @@ class WebViewManager : public content::BrowserPluginGuestManager { protected: // content::BrowserPluginGuestManager: - content::WebContents* GetGuestByInstanceID( - content::WebContents* embedder_web_contents, - int element_instance_id) override; + content::WebContents* GetGuestByInstanceID(int owner_process_id, + int element_instance_id) override; bool ForEachGuest(content::WebContents* embedder, const GuestCallback& callback) override; @@ -65,26 +68,25 @@ class WebViewManager : public content::BrowserPluginGuestManager { std::map web_contents_embdder_map_; struct ElementInstanceKey { - content::WebContents* owner_web_contents; + int embedder_process_id; int element_instance_id; - ElementInstanceKey(content::WebContents* owner_web_contents, - int element_instance_id) - : owner_web_contents(owner_web_contents), + ElementInstanceKey(int embedder_process_id, int element_instance_id) + : embedder_process_id(embedder_process_id), element_instance_id(element_instance_id) {} bool operator<(const ElementInstanceKey& other) const { - if (owner_web_contents != other.owner_web_contents) - return owner_web_contents < other.owner_web_contents; + if (embedder_process_id != other.embedder_process_id) + return embedder_process_id < other.embedder_process_id; return element_instance_id < other.element_instance_id; } bool operator==(const ElementInstanceKey& other) const { - return (owner_web_contents == other.owner_web_contents) && + return (embedder_process_id == other.embedder_process_id) && (element_instance_id == other.element_instance_id); } }; - // (web_contents, element_instance_id) => guest_instance_id + // (embedder_process_id, element_instance_id) => guest_instance_id std::map element_instance_id_to_guest_map_; typedef std::map WebViewInfoMap; diff --git a/atom/common/api/atom_api_asar.cc b/atom/common/api/atom_api_asar.cc index d035159380a4..3fd2ca6f86f7 100644 --- a/atom/common/api/atom_api_asar.cc +++ b/atom/common/api/atom_api_asar.cc @@ -88,6 +88,13 @@ class Archive : public mate::Wrappable { return mate::ConvertToV8(isolate, new_path); } + // Return the file descriptor. + int GetFD() const { + if (!archive_) + return -1; + return archive_->GetFD(); + } + // Free the resources used by archive. void Destroy() { archive_.reset(); @@ -102,6 +109,7 @@ class Archive : public mate::Wrappable { .SetMethod("readdir", &Archive::Readdir) .SetMethod("realpath", &Archive::Realpath) .SetMethod("copyFileOut", &Archive::CopyFileOut) + .SetMethod("getFd", &Archive::GetFD) .SetMethod("destroy", &Archive::Destroy); } diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc index 4ad8c1817a90..98e464650bac 100644 --- a/atom/common/asar/archive.cc +++ b/atom/common/asar/archive.cc @@ -4,6 +4,10 @@ #include "atom/common/asar/archive.h" +#if defined(OS_WIN) +#include +#endif + #include #include @@ -104,6 +108,7 @@ bool FillFileInfoWithNode(Archive::FileInfo* info, Archive::Archive(const base::FilePath& path) : path_(path), + file_(path_, base::File::FLAG_OPEN | base::File::FLAG_READ), header_size_(0) { } @@ -111,15 +116,14 @@ Archive::~Archive() { } bool Archive::Init() { - base::File file(path_, base::File::FLAG_OPEN | base::File::FLAG_READ); - if (!file.IsValid()) + if (!file_.IsValid()) return false; std::vector buf; int len; buf.resize(8); - len = file.ReadAtCurrentPos(buf.data(), buf.size()); + len = file_.ReadAtCurrentPos(buf.data(), buf.size()); if (len != static_cast(buf.size())) { PLOG(ERROR) << "Failed to read header size from " << path_.value(); return false; @@ -132,7 +136,7 @@ bool Archive::Init() { } buf.resize(size); - len = file.ReadAtCurrentPos(buf.data(), buf.size()); + len = file_.ReadAtCurrentPos(buf.data(), buf.size()); if (len != static_cast(buf.size())) { PLOG(ERROR) << "Failed to read header from " << path_.value(); return false; @@ -250,7 +254,7 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) { } scoped_ptr temp_file(new ScopedTemporaryFile); - if (!temp_file->InitFromFile(path_, info.offset, info.size)) + if (!temp_file->InitFromFile(&file_, info.offset, info.size)) return false; *out = temp_file->path(); @@ -258,4 +262,18 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) { return true; } +int Archive::GetFD() const { + if (!file_.IsValid()) + return -1; + +#if defined(OS_WIN) + return + _open_osfhandle(reinterpret_cast(file_.GetPlatformFile()), 0); +#elif defined(OS_POSIX) + return file_.GetPlatformFile(); +#else + return -1; +#endif +} + } // namespace asar diff --git a/atom/common/asar/archive.h b/atom/common/asar/archive.h index 53adbfc13c41..2acd17fd7ab4 100644 --- a/atom/common/asar/archive.h +++ b/atom/common/asar/archive.h @@ -8,6 +8,7 @@ #include #include "base/containers/scoped_ptr_hash_map.h" +#include "base/files/file.h" #include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" @@ -59,11 +60,15 @@ class Archive { // 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_; uint32 header_size_; scoped_ptr header_; diff --git a/atom/common/asar/scoped_temporary_file.cc b/atom/common/asar/scoped_temporary_file.cc index 574f178f6f34..6fccc9434fdb 100644 --- a/atom/common/asar/scoped_temporary_file.cc +++ b/atom/common/asar/scoped_temporary_file.cc @@ -36,17 +36,16 @@ bool ScopedTemporaryFile::Init() { return base::CreateTemporaryFile(&path_); } -bool ScopedTemporaryFile::InitFromFile(const base::FilePath& path, +bool ScopedTemporaryFile::InitFromFile(base::File* src, uint64 offset, uint64 size) { + if (!src->IsValid()) + return false; + if (!Init()) return false; - base::File src(path, base::File::FLAG_OPEN | base::File::FLAG_READ); - if (!src.IsValid()) - return false; - std::vector buf(size); - int len = src.Read(offset, buf.data(), buf.size()); + int len = src->Read(offset, buf.data(), buf.size()); if (len != static_cast(size)) return false; diff --git a/atom/common/asar/scoped_temporary_file.h b/atom/common/asar/scoped_temporary_file.h index 62aafc8f07d6..ffaee22e514e 100644 --- a/atom/common/asar/scoped_temporary_file.h +++ b/atom/common/asar/scoped_temporary_file.h @@ -7,6 +7,10 @@ #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 @@ -22,7 +26,7 @@ class ScopedTemporaryFile { bool Init(); // Init an temporary file and fill it with content of |path|. - bool InitFromFile(const base::FilePath& path, uint64 offset, uint64 size); + bool InitFromFile(base::File* src, uint64 offset, uint64 size); base::FilePath path() const { return path_; } diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 2223747054d8..b14baf7ad702 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -6,7 +6,7 @@ #define ATOM_VERSION_H #define ATOM_MAJOR_VERSION 0 -#define ATOM_MINOR_VERSION 24 +#define ATOM_MINOR_VERSION 26 #define ATOM_PATCH_VERSION 0 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/atom/common/chrome_version.h b/atom/common/chrome_version.h index 1971756871b9..6b2ea8d91a45 100644 --- a/atom/common/chrome_version.h +++ b/atom/common/chrome_version.h @@ -8,7 +8,7 @@ #ifndef ATOM_COMMON_CHROME_VERSION_H_ #define ATOM_COMMON_CHROME_VERSION_H_ -#define CHROME_VERSION_STRING "41.0.2272.76" +#define CHROME_VERSION_STRING "42.0.2311.107" #define CHROME_VERSION "v" CHROME_VERSION_STRING #endif // ATOM_COMMON_CHROME_VERSION_H_ diff --git a/atom/common/lib/asar.coffee b/atom/common/lib/asar.coffee index 8530071e2c90..f70d2c456d78 100644 --- a/atom/common/lib/asar.coffee +++ b/atom/common/lib/asar.coffee @@ -53,11 +53,20 @@ asarStatsToFsStats = (stats) -> } # Create a ENOENT error. -createNotFoundError = (asarPath, filePath) -> +notFoundError = (asarPath, filePath, callback) -> error = new Error("ENOENT, #{filePath} not found in #{asarPath}") error.code = "ENOENT" error.errno = -2 - error + unless typeof callback is 'function' + throw error + process.nextTick -> callback error + +# Create invalid archive error. +invalidArchiveError = (asarPath, callback) -> + error = new Error("Invalid package #{asarPath}") + unless typeof callback is 'function' + throw error + process.nextTick -> callback error # Override APIs that rely on passing file path instead of content to C++. overrideAPISync = (module, name, arg = 0) -> @@ -68,10 +77,10 @@ overrideAPISync = (module, name, arg = 0) -> return old.apply this, arguments unless isAsar archive = getOrCreateArchive asarPath - throw new Error("Invalid package #{asarPath}") unless archive + invalidArchiveError asarPath unless archive newPath = archive.copyFileOut filePath - throw createNotFoundError(asarPath, filePath) unless newPath + notFoundError asarPath, filePath unless newPath arguments[arg] = newPath old.apply this, arguments @@ -87,10 +96,10 @@ overrideAPI = (module, name, arg = 0) -> return overrideAPISync module, name, arg unless typeof callback is 'function' archive = getOrCreateArchive asarPath - return callback new Error("Invalid package #{asarPath}") unless archive + return invalidArchiveError asarPath, callback unless archive newPath = archive.copyFileOut filePath - return callback createNotFoundError(asarPath, filePath) unless newPath + return notFoundError asarPath, filePath, callback unless newPath arguments[arg] = newPath old.apply this, arguments @@ -103,10 +112,10 @@ exports.wrapFsWithAsar = (fs) -> return lstatSync p unless isAsar archive = getOrCreateArchive asarPath - throw new Error("Invalid package #{asarPath}") unless archive + invalidArchiveError asarPath unless archive stats = archive.stat filePath - throw createNotFoundError(asarPath, filePath) unless stats + notFoundError asarPath, filePath unless stats asarStatsToFsStats stats @@ -116,10 +125,10 @@ exports.wrapFsWithAsar = (fs) -> return lstat p, callback unless isAsar archive = getOrCreateArchive asarPath - return callback new Error("Invalid package #{asarPath}") unless archive + return invalidArchiveError asarPath, callback unless archive stats = getOrCreateArchive(asarPath).stat filePath - return callback createNotFoundError(asarPath, filePath) unless stats + return notFoundError asarPath, filePath, callback unless stats process.nextTick -> callback null, asarStatsToFsStats stats @@ -156,10 +165,10 @@ exports.wrapFsWithAsar = (fs) -> return realpathSync.apply this, arguments unless isAsar archive = getOrCreateArchive asarPath - throw new Error("Invalid package #{asarPath}") unless archive + invalidArchiveError asarPath unless archive real = archive.realpath filePath - throw createNotFoundError(asarPath, filePath) if real is false + notFoundError asarPath, filePath if real is false path.join realpathSync(asarPath), real @@ -173,10 +182,11 @@ exports.wrapFsWithAsar = (fs) -> cache = undefined archive = getOrCreateArchive asarPath - return callback new Error("Invalid package #{asarPath}") unless archive + return invalidArchiveError asarPath, callback unless archive real = archive.realpath filePath - return callback createNotFoundError(asarPath, filePath) if real is false + if real is false + return notFoundError asarPath, filePath, callback realpath asarPath, (err, p) -> return callback err if err @@ -188,7 +198,7 @@ exports.wrapFsWithAsar = (fs) -> return exists p, callback unless isAsar archive = getOrCreateArchive asarPath - return callback new Error("Invalid package #{asarPath}") unless archive + return invalidArchiveError asarPath, callback unless archive process.nextTick -> callback archive.stat(filePath) isnt false @@ -213,32 +223,33 @@ exports.wrapFsWithAsar = (fs) -> options = undefined archive = getOrCreateArchive asarPath - return callback new Error("Invalid package #{asarPath}") unless archive + return invalidArchiveError asarPath, callback unless archive info = archive.getFileInfo filePath - return callback createNotFoundError(asarPath, filePath) unless info - return callback null, new Buffer(0) if info.size is 0 + return notFoundError asarPath, filePath, callback unless info + + if info.size is 0 + return process.nextTick -> callback null, new Buffer(0) if info.unpacked realPath = archive.copyFileOut filePath return fs.readFile realPath, options, callback if not options - options = encoding: null, flag: 'r' + options = encoding: null else if util.isString options - options = encoding: options, flag: 'r' + options = encoding: options else if not util.isObject options throw new TypeError('Bad arguments') - flag = options.flag || 'r' encoding = options.encoding buffer = new Buffer(info.size) - open archive.path, flag, (error, fd) -> - return callback error if error - fs.read fd, buffer, 0, info.size, info.offset, (error) -> - fs.close fd, -> - callback error, if encoding then buffer.toString encoding else buffer + fd = archive.getFd() + return notFoundError asarPath, filePath, callback unless fd >= 0 + + fs.read fd, buffer, 0, info.size, info.offset, (error) -> + callback error, if encoding then buffer.toString encoding else buffer openSync = fs.openSync readFileSync = fs.readFileSync @@ -247,10 +258,10 @@ exports.wrapFsWithAsar = (fs) -> return readFileSync.apply this, arguments unless isAsar archive = getOrCreateArchive asarPath - throw new Error("Invalid package #{asarPath}") unless archive + invalidArchiveError asarPath unless archive info = archive.getFileInfo filePath - throw createNotFoundError(asarPath, filePath) unless info + notFoundError asarPath, filePath unless info return new Buffer(0) if info.size is 0 if info.unpacked @@ -258,23 +269,19 @@ exports.wrapFsWithAsar = (fs) -> return fs.readFileSync realPath, options if not options - options = encoding: null, flag: 'r' + options = encoding: null else if util.isString options - options = encoding: options, flag: 'r' + options = encoding: options else if not util.isObject options throw new TypeError('Bad arguments') - flag = options.flag || 'r' encoding = options.encoding buffer = new Buffer(info.size) - fd = openSync archive.path, flag - try - fs.readSync fd, buffer, 0, info.size, info.offset - catch e - throw e - finally - fs.closeSync fd + fd = archive.getFd() + notFoundError asarPath, filePath unless fd >= 0 + + fs.readSync fd, buffer, 0, info.size, info.offset if encoding then buffer.toString encoding else buffer readdir = fs.readdir @@ -283,10 +290,10 @@ exports.wrapFsWithAsar = (fs) -> return readdir.apply this, arguments unless isAsar archive = getOrCreateArchive asarPath - return callback new Error("Invalid package #{asarPath}") unless archive + return invalidArchiveError asarPath, callback unless archive files = archive.readdir filePath - return callback createNotFoundError(asarPath, filePath) unless files + return notFoundError asarPath, filePath, callback unless files process.nextTick -> callback null, files @@ -296,10 +303,10 @@ exports.wrapFsWithAsar = (fs) -> return readdirSync.apply this, arguments unless isAsar archive = getOrCreateArchive asarPath - throw new Error("Invalid package #{asarPath}") unless archive + invalidArchiveError asarPath unless archive files = archive.readdir filePath - throw createNotFoundError(asarPath, filePath) unless files + notFoundError asarPath, filePath unless files files diff --git a/atom/common/lib/init.coffee b/atom/common/lib/init.coffee index 4fd1f8289d55..88b32d8c0254 100644 --- a/atom/common/lib/init.coffee +++ b/atom/common/lib/init.coffee @@ -10,8 +10,20 @@ process.atomBinding = (name) -> catch e process.binding "atom_common_#{name}" if /No such module/.test e.message -# Add common/api/lib to module search paths. +# 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') # setImmediate and process.nextTick makes use of uv_check and uv_prepare to diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 01df48fdc66c..10ab8f4929a4 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -128,9 +128,13 @@ void NodeBindings::Initialize() { node::g_standalone_mode = is_browser_; node::g_upstream_node_mode = false; + // Parse the debug args. + auto args = AtomCommandLine::argv(); + for (const std::string& arg : args) + node::ParseDebugOpt(arg.c_str()); + // Init node. - // (we assume it would not node::Init would not modify the parameters under - // embedded mode). + // (we assume node::Init would not modify the parameters under embedded mode). node::Init(nullptr, nullptr, nullptr, nullptr); } @@ -166,7 +170,14 @@ node::Environment* NodeBindings::CreateEnvironment( } void NodeBindings::LoadEnvironment(node::Environment* env) { + node::node_isolate = env->isolate(); + if (node::use_debug_agent) + node::StartDebug(env, node::debug_wait_connect); + node::LoadEnvironment(env); + + if (node::use_debug_agent) + node::EnableDebug(env); } void NodeBindings::PrepareMessageLoop() { diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index f67a6456964c..7f642ecbbabd 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -63,6 +63,12 @@ const char kDirectWrite[] = "direct-write"; // Enable plugins. const char kEnablePlugins[] = "enable-plugins"; +// Ppapi Flash path. +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"; @@ -75,6 +81,12 @@ 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"; + // Web runtime features. const char kExperimentalFeatures[] = "experimental-features"; const char kExperimentalCanvasFeatures[] = "experimental-canvas-features"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index 967f62638733..aaaa86addb15 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -37,10 +37,14 @@ 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 kTransparent[]; extern const char kType[]; +extern const char kDisableAutoHideCursor[]; +extern const char kStandardWindow[]; extern const char kExperimentalFeatures[]; extern const char kExperimentalCanvasFeatures[]; diff --git a/atom/common/platform_util_win.cc b/atom/common/platform_util_win.cc index 78fb0ca00540..1998b8873189 100644 --- a/atom/common/platform_util_win.cc +++ b/atom/common/platform_util_win.cc @@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -128,7 +129,10 @@ void ShowItemInFolder(const base::FilePath& full_path) { } void OpenItem(const base::FilePath& full_path) { - ui::win::OpenItemViaShell(full_path); + if (base::DirectoryExists(full_path)) + ui::win::OpenFolderViaShell(full_path); + else + ui::win::OpenFileViaShell(full_path); } void OpenExternal(const GURL& url) { diff --git a/atom/common/resources/mac/MainMenu.xib b/atom/common/resources/mac/MainMenu.xib index edabb62f7c92..fb4656cac618 100644 --- a/atom/common/resources/mac/MainMenu.xib +++ b/atom/common/resources/mac/MainMenu.xib @@ -1,14 +1,14 @@ - 1080 - 12D78 - 3084 - 1187.37 - 626.00 + 101000 + 14D136 + 7531 + 1347.57 + 758.70 com.apple.InterfaceBuilder.CocoaPlugin - 3084 + 7531 NSCustomObject @@ -40,7 +40,7 @@ - Atom + Electron 2147483647 @@ -52,106 +52,10 @@ NSMenuMixedState submenuAction: + - Atom + Electron - - - About - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Preferences… - , - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Services - - 2147483647 - - - submenuAction: - - Services - - _NSServicesMenu - - - - - YES - YES - - - 2147483647 - - - - - - Hide - h - 1048576 - 2147483647 - - - - - - Hide Others - h - 1572864 - 2147483647 - - - - - - Show All - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - Quit @@ -165,1805 +69,19 @@ _NSAppleMenu - - - File - - 2147483647 - - - submenuAction: - - File - - - - New - n - 1048576 - 2147483647 - - - - - - Open… - o - 1048576 - 2147483647 - - - - - - Open Recent - - 2147483647 - - - submenuAction: - - Open Recent - - - - Clear Menu - - 2147483647 - - - - - _NSRecentDocumentsMenu - - - - - YES - YES - - - 2147483647 - - - - - - Close - w - 1048576 - 2147483647 - - - - - - Save… - s - 1048576 - 2147483647 - - - - - - Revert to Saved - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Page Setup... - P - 1179648 - 2147483647 - - - - - - - Print… - p - 1048576 - 2147483647 - - - - - - - - - Edit - - 2147483647 - - - submenuAction: - - Edit - - - - Undo - z - 1048576 - 2147483647 - - - - - - Redo - Z - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Cut - x - 1048576 - 2147483647 - - - - - - Copy - c - 1048576 - 2147483647 - - - - - - Paste - v - 1048576 - 2147483647 - - - - - - Paste and Match Style - V - 1572864 - 2147483647 - - - - - - Delete - - 2147483647 - - - - - - Select All - a - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Find - - 2147483647 - - - submenuAction: - - Find - - - - Find… - f - 1048576 - 2147483647 - - - 1 - - - - Find and Replace… - f - 1572864 - 2147483647 - - - 12 - - - - Find Next - g - 1048576 - 2147483647 - - - 2 - - - - Find Previous - G - 1048576 - 2147483647 - - - 3 - - - - Use Selection for Find - e - 1048576 - 2147483647 - - - 7 - - - - Jump to Selection - j - 1048576 - 2147483647 - - - - - - - - - Spelling and Grammar - - 2147483647 - - - submenuAction: - - Spelling - - - - Show Spelling and Grammar - : - 1048576 - 2147483647 - - - - - - Check Document Now - ; - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Check Spelling While Typing - - 2147483647 - - - - - - Check Grammar With Spelling - - 2147483647 - - - - - - Correct Spelling Automatically - - 2147483647 - - - - - - - - - Substitutions - - 2147483647 - - - submenuAction: - - Substitutions - - - - Show Substitutions - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Smart Copy/Paste - - 2147483647 - - - - - - Smart Quotes - - 2147483647 - - - - - - Smart Dashes - - 2147483647 - - - - - - Smart Links - - 2147483647 - - - - - - Data Detectors - - 2147483647 - - - - - - Text Replacement - - 2147483647 - - - - - - - - - Transformations - - 2147483647 - - - submenuAction: - - Transformations - - - - Make Upper Case - - 2147483647 - - - - - - Make Lower Case - - 2147483647 - - - - - - Capitalize - - 2147483647 - - - - - - - - - Speech - - 2147483647 - - - submenuAction: - - Speech - - - - Start Speaking - - 2147483647 - - - - - - Stop Speaking - - 2147483647 - - - - - - - - - - - - Format - - 2147483647 - - - submenuAction: - - Format - - - - Font - - 2147483647 - - - submenuAction: - - Font - - - - Show Fonts - t - 1048576 - 2147483647 - - - - - - Bold - b - 1048576 - 2147483647 - - - 2 - - - - Italic - i - 1048576 - 2147483647 - - - 1 - - - - Underline - u - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Bigger - + - 1048576 - 2147483647 - - - 3 - - - - Smaller - - - 1048576 - 2147483647 - - - 4 - - - - YES - YES - - - 2147483647 - - - - - - Kern - - 2147483647 - - - submenuAction: - - Kern - - - - Use Default - - 2147483647 - - - - - - Use None - - 2147483647 - - - - - - Tighten - - 2147483647 - - - - - - Loosen - - 2147483647 - - - - - - - - - Ligatures - - 2147483647 - - - submenuAction: - - Ligatures - - - - Use Default - - 2147483647 - - - - - - Use None - - 2147483647 - - - - - - Use All - - 2147483647 - - - - - - - - - Baseline - - 2147483647 - - - submenuAction: - - Baseline - - - - Use Default - - 2147483647 - - - - - - Superscript - - 2147483647 - - - - - - Subscript - - 2147483647 - - - - - - Raise - - 2147483647 - - - - - - Lower - - 2147483647 - - - - - - - - - YES - YES - - - 2147483647 - - - - - - Show Colors - C - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Copy Style - c - 1572864 - 2147483647 - - - - - - Paste Style - v - 1572864 - 2147483647 - - - - - _NSFontMenu - - - - - Text - - 2147483647 - - - submenuAction: - - Text - - - - Align Left - { - 1048576 - 2147483647 - - - - - - Center - | - 1048576 - 2147483647 - - - - - - Justify - - 2147483647 - - - - - - Align Right - } - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Writing Direction - - 2147483647 - - - submenuAction: - - Writing Direction - - - - YES - Paragraph - - 2147483647 - - - - - - CURlZmF1bHQ - - 2147483647 - - - - - - CUxlZnQgdG8gUmlnaHQ - - 2147483647 - - - - - - CVJpZ2h0IHRvIExlZnQ - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - YES - Selection - - 2147483647 - - - - - - CURlZmF1bHQ - - 2147483647 - - - - - - CUxlZnQgdG8gUmlnaHQ - - 2147483647 - - - - - - CVJpZ2h0IHRvIExlZnQ - - 2147483647 - - - - - - - - - YES - YES - - - 2147483647 - - - - - - Show Ruler - - 2147483647 - - - - - - Copy Ruler - c - 1310720 - 2147483647 - - - - - - Paste Ruler - v - 1310720 - 2147483647 - - - - - - - - - - - - View - - 2147483647 - - - submenuAction: - - View - - - - Show Toolbar - t - 1572864 - 2147483647 - - - - - - Customize Toolbar… - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Reload - r - 1048576 - 2147483647 - - - - - - Show Developer Tools - i - 1572864 - 2147483647 - - - - - - - - - Window - - 2147483647 - - - submenuAction: - - Window - - - - Minimize - m - 1048576 - 2147483647 - - - - - - Zoom - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Bring All to Front - - 2147483647 - - - - - _NSWindowsMenu - - - - - Help - - 2147483647 - - - submenuAction: - - Help - - - - Brightray Example Help - ? - 1048576 - 2147483647 - - - - - _NSHelpMenu - - _NSMainMenu - + - orderFrontStandardAboutPanel: - - - - 142 - - - - closeAllWindows: - + terminate: + - 803 - - - - performMiniaturize: - - - - 37 - - - - arrangeInFront: - - - - 39 - - - - print: - - - - 86 - - - - runPageLayout: - - - - 87 - - - - clearRecentDocuments: - - - - 127 - - - - performClose: - - - - 193 - - - - performZoom: - - - - 240 - - - - showHelp: - - - - 360 - - - - saveDocument: - - - - 362 - - - - revertDocumentToSaved: - - - - 364 - - - - runToolbarCustomizationPalette: - - - - 365 - - - - toggleToolbarShown: - - - - 366 - - - - hide: - - - - 367 - - - - hideOtherApplications: - - - - 368 - - - - unhideAllApplications: - - - - 370 - - - - raiseBaseline: - - - - 423 - - - - lowerBaseline: - - - - 424 - - - - copyFont: - - - - 425 - - - - subscript: - - - - 426 - - - - superscript: - - - - 427 - - - - tightenKerning: - - - - 428 - - - - underline: - - - - 429 - - - - orderFrontColorPanel: - - - - 430 - - - - useAllLigatures: - - - - 431 - - - - loosenKerning: - - - - 432 - - - - pasteFont: - - - - 433 - - - - unscript: - - - - 434 - - - - useStandardKerning: - - - - 435 - - - - useStandardLigatures: - - - - 436 - - - - turnOffLigatures: - - - - 437 - - - - turnOffKerning: - - - - 438 - - - - alignLeft: - - - - 439 - - - - alignJustified: - - - - 440 - - - - copyRuler: - - - - 441 - - - - alignCenter: - - - - 442 - - - - toggleRuler: - - - - 443 - - - - alignRight: - - - - 444 - - - - pasteRuler: - - - - 445 - - - - capitalizeWord: - - - - 737 - - - - cut: - - - - 738 - - - - paste: - - - - 739 - - - - toggleSmartInsertDelete: - - - - 740 - - - - toggleAutomaticQuoteSubstitution: - - - - 741 - - - - redo: - - - - 742 - - - - toggleAutomaticDashSubstitution: - - - - 743 - - - - toggleContinuousSpellChecking: - - - - 744 - - - - toggleAutomaticDataDetection: - - - - 745 - - - - undo: - - - - 746 - - - - toggleGrammarChecking: - - - - 747 - - - - startSpeaking: - - - - 748 - - - - showGuessPanel: - - - - 749 - - - - checkSpelling: - - - - 750 - - - - pasteAsPlainText: - - - - 751 - - - - copy: - - - - 752 - - - - delete: - - - - 753 - - - - lowercaseWord: - - - - 754 - - - - selectAll: - - - - 755 - - - - stopSpeaking: - - - - 756 - - - - orderFrontSubstitutionsPanel: - - - - 757 - - - - toggleAutomaticTextReplacement: - - - - 758 - - - - toggleAutomaticLinkDetection: - - - - 759 - - - - toggleAutomaticSpellingCorrection: - - - - 760 - - - - uppercaseWord: - - - - 761 - - - - performFindPanelAction: - - - - 768 - - - - performFindPanelAction: - - - - 769 - - - - performFindPanelAction: - - - - 770 - - - - centerSelectionInVisibleArea: - - - - 771 - - - - performFindPanelAction: - - - - 772 - - - - makeBaseWritingDirectionNatural: - - - - 785 - - - - makeBaseWritingDirectionLeftToRight: - - - - 786 - - - - makeBaseWritingDirectionRightToLeft: - - - - 787 - - - - makeTextWritingDirectionNatural: - - - - 788 - - - - makeTextWritingDirectionLeftToRight: - - - - 789 - - - - makeTextWritingDirectionRightToLeft: - - - - 790 - - - - performFindPanelAction: - - - - 792 - - - - showDevTools: - - - - 805 - - - - reload: - - - - 806 - - - - addFontTrait: - - - - 418 - - - - addFontTrait: - - - - 419 - - - - modifyFont: - - - - 420 - - - - orderFrontFontPanel: - - - - 421 - - - - modifyFont: - - - - 422 + 807 @@ -1993,26 +111,17 @@ Application - 29 - - - - - - - - - - + 371 + - 19 - + 29 + - + - + 56 @@ -2022,1184 +131,49 @@ - - 103 - - - - - - - - 83 - - - - - - - - 81 - - - - - - - - - - - - - - - - - 75 - - - - - 78 - - - - - 72 - - - - - 82 - - - - - 124 - - - - - - - - 77 - - - - - 73 - - - - - 79 - - - - - 112 - - - - - 74 - - - - - 125 - - - - - - - - 126 - - - - - 106 - - - - - - - - 111 - - - 57 - - - - - - - - - - - - 58 - - - - - 134 - - - - - 150 - - - 136 - - 144 - - - - - 129 - - - - - 143 - - - - - 236 - - - - - 131 - - - - - - - - 149 - - - - - 145 - - - - - 130 - - - - - 24 - - - - - - - - - - - 92 - - - - - 5 - - - - - 239 - - - - - 23 - - - - - 295 - - - - - - - - 296 - - - - - - - - - - - - 297 - - - - - 298 - - - - - 371 - - - - - 373 - - - - - - - - 374 - - - - - - - - - 375 - - - - - - - - 376 - - - - - - - - 377 - - - - - - - - - - - - - - - - - 378 - - - - - 379 - - - - - 380 - - - - - 381 - - - - - 382 - - - - - 383 - - - - - 384 - - - - - 385 - - - - - 386 - - - - - - - - - - - - - - - - - - - - - - - 387 - - - - - 388 - - - - - 389 - - - - - 390 - - - - - 391 - - - - - 392 - - - - - 393 - - - - - 394 - - - - - 395 - - - - - - - - 396 - - - - - - - - 397 - - - - - - - - 398 - - - - - 399 - - - - - 400 - - - - - 401 - - - - - 402 - - - - - 403 - - - - - - - - - - - - 404 - - - - - 405 - - - - - 406 - - - - - 407 - - - - - 408 - - - - - 409 - - - - - - - - - - 410 - - - - - 411 - - - - - 412 - - - - - 413 - - - - - - - - - - - 414 - - - - - 415 - - - - - 416 - - - - - 417 - - - - - 681 - - - - - - - - 682 - - - - - - - - - - - - - - - - - - - - - - 683 - - - - - 684 - - - - - 685 - - - - - 686 - - - - - 687 - - - - - 688 - - - - - 689 - - - - - 690 - - - - - 691 - - - - - 692 - - - - - 693 - - - - - - - - 694 - - - - - - - - 695 - - - - - - - - 696 - - - - - - - - 697 - - - - - - - - 708 - - - - - - - - - 709 - - - - - 710 - - - - - 711 - - - - - - - - - - 712 - - - - - 713 - - - - - 714 - - - - - 715 - - - - - - - - - - - - - - - 716 - - - - - 717 - - - - - 718 - - - - - 719 - - - - - 720 - - - - - 721 - - - - - 722 - - - - - 723 - - - - - 724 - - - - - - - - - - - - - 725 - - - - - 726 - - - - - 727 - - - - - 728 - - - - - 729 - - - - - 730 - - - - - 731 - - - - - - - - - - - - - 732 - - - - - 733 - - - - - 734 - - - - - 735 - - - - - 736 - - - - - 773 - - - - - 774 - - - - - - - - 775 - - - - - - - - - - - - - - - - 776 - - - - - 777 - - - - - 778 - - - - - 779 - - - - - 780 - - - - - 781 - - - - - 782 - - - - - 783 - - - - - 784 - - - - - 791 - - - - - 798 - - - - - 799 - - - - - 804 - - - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - 806 - - - - - AtomApplication - NSApplication - - closeAllWindows: - id - - - closeAllWindows: - - closeAllWindows: - id - - - - IBProjectSource - ./Classes/AtomApplication.h - - - - BRYInspectableWebContentsView - NSView - - showDevTools: - id - - - showDevTools: - - showDevTools: - id - - - - IBProjectSource - ./Classes/BRYInspectableWebContentsView.h - - - - FirstResponder - - showDevTools: - id - - - showDevTools: - - showDevTools: - id - - - - IBUserSource - - - - + 807 0 IBCocoaFramework + NO + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + YES 3 - {11, 11} - {10, 3} + {12, 12} + {10, 2} YES diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee index 673a01cb20b5..569678476587 100644 --- a/atom/renderer/api/lib/remote.coffee +++ b/atom/renderer/api/lib/remote.coffee @@ -110,13 +110,20 @@ exports.require = (module) -> meta = ipc.sendSync 'ATOM_BROWSER_REQUIRE', module moduleCache[module] = metaToValue meta -# Get current window object. +# Get current BrowserWindow object. windowCache = null exports.getCurrentWindow = -> return windowCache if windowCache? meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WINDOW', process.guestInstanceId windowCache = metaToValue meta +# Get current WebContents object. +webContentsCache = null +exports.getCurrentWebContents = -> + return webContentsCache if webContentsCache? + meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WEB_CONTENTS' + webContentsCache = metaToValue meta + # Get a global object in browser. exports.getGlobal = (name) -> meta = ipc.sendSync 'ATOM_BROWSER_GLOBAL', name diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index cc48bc0481d1..d90a90b9415f 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -11,6 +11,7 @@ #include "atom/common/options_switches.h" #include "atom/renderer/atom_render_view_observer.h" #include "atom/renderer/guest_view_container.h" +#include "chrome/renderer/pepper/pepper_helper.h" #include "chrome/renderer/printing/print_web_view_helper.h" #include "chrome/renderer/tts_dispatcher.h" #include "content/public/common/content_constants.h" @@ -79,6 +80,11 @@ void AtomRendererClient::RenderThreadStarted() { content::RenderThread::Get()->AddObserver(this); } +void AtomRendererClient::RenderFrameCreated( + content::RenderFrame* render_frame) { + new PepperHelper(render_frame); +} + void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) { new printing::PrintWebViewHelper(render_view); new AtomRenderViewObserver(render_view, this); diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index 4aba42c5ad48..a7096125580c 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -34,6 +34,7 @@ class AtomRendererClient : public content::ContentRendererClient, // content::ContentRendererClient: void RenderThreadStarted() override; + void RenderFrameCreated(content::RenderFrame*) override; void RenderViewCreated(content::RenderView*) override; blink::WebSpeechSynthesizer* OverrideSpeechSynthesizer( blink::WebSpeechSynthesizerClient* client) override; diff --git a/atom/renderer/lib/init.coffee b/atom/renderer/lib/init.coffee index 43d0fa9cfa06..1e0167d6e154 100644 --- a/atom/renderer/lib/init.coffee +++ b/atom/renderer/lib/init.coffee @@ -103,5 +103,8 @@ if preloadScript try require preloadScript catch error - throw error unless error.code is 'MODULE_NOT_FOUND' - console.error "Unable to load preload script #{preloadScript}" + if error.code is 'MODULE_NOT_FOUND' + console.error "Unable to load preload script #{preloadScript}" + else + console.error(error) + console.error(error.stack) diff --git a/atom/renderer/lib/override.coffee b/atom/renderer/lib/override.coffee index 6e02c2eb8222..1ca6e692ba21 100644 --- a/atom/renderer/lib/override.coffee +++ b/atom/renderer/lib/override.coffee @@ -74,9 +74,17 @@ window.confirm = (message, title='') -> window.prompt = -> throw new Error('prompt() is and will not be supported.') +# Simple implementation of postMessage. window.opener = postMessage: (message, targetOrigin='*') -> ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', message, targetOrigin ipc.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (message, targetOrigin) -> window.postMessage message, targetOrigin + +# Forward history operations to browser. +sendHistoryOperation = (args...) -> + ipc.send 'ATOM_SHELL_NAVIGATION_CONTROLLER', args... +window.history.back = -> sendHistoryOperation 'goBack' +window.history.forward = -> sendHistoryOperation 'goForward' +window.history.go = (offset) -> sendHistoryOperation 'goToOffset', offset diff --git a/atom/renderer/lib/web-view/guest-view-internal.coffee b/atom/renderer/lib/web-view/guest-view-internal.coffee index 345491030147..04aa5c5494f0 100644 --- a/atom/renderer/lib/web-view/guest-view-internal.coffee +++ b/atom/renderer/lib/web-view/guest-view-internal.coffee @@ -12,12 +12,14 @@ WEB_VIEW_EVENTS = 'did-get-response-details': ['status', 'newUrl', 'originalUrl', 'httpResponseCode', 'requestMethod', 'referrer'] 'did-get-redirect-request': ['oldUrl', 'newUrl', 'isMainFrame'] + 'dom-ready': [] 'console-message': ['level', 'message', 'line', 'sourceId'] 'new-window': ['url', 'frameName', 'disposition'] 'close': [] 'crashed': [] 'destroyed': [] 'page-title-set': ['title', 'explicitSet'] + 'page-favicon-updated': ['favicons'] dispatchEvent = (webView, event, args...) -> throw new Error("Unkown event #{event}") unless WEB_VIEW_EVENTS[event]? diff --git a/atom/renderer/lib/web-view/web-view-attributes.coffee b/atom/renderer/lib/web-view/web-view-attributes.coffee index e4b5dcb45bda..05bd6141203f 100644 --- a/atom/renderer/lib/web-view/web-view-attributes.coffee +++ b/atom/renderer/lib/web-view/web-view-attributes.coffee @@ -138,10 +138,7 @@ class SrcAttribute extends WebViewAttribute setupMutationObserver: -> @observer = new MutationObserver (mutations) => for mutation in mutations - oldValue = mutation.oldValue - newValue = @getValue() - return if oldValue isnt newValue - @handleMutation oldValue, newValue + @handleMutation mutation.oldValue, @getValue() params = attributes: true, attributeOldValue: true, diff --git a/atom/renderer/lib/web-view/web-view.coffee b/atom/renderer/lib/web-view/web-view.coffee index 3058863f7b52..bf163c0cfb5c 100644 --- a/atom/renderer/lib/web-view/web-view.coffee +++ b/atom/renderer/lib/web-view/web-view.coffee @@ -255,6 +255,7 @@ registerWebViewElement = -> "openDevTools" "closeDevTools" "isDevToolsOpened" + "inspectElement" "undo" "redo" "cut" diff --git a/atom/utility/atom_content_utility_client.cc b/atom/utility/atom_content_utility_client.cc new file mode 100644 index 000000000000..cc739227aad8 --- /dev/null +++ b/atom/utility/atom_content_utility_client.cc @@ -0,0 +1,74 @@ +// 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/utility/atom_content_utility_client.h" + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/time/time.h" +#include "chrome/common/chrome_utility_messages.h" +#include "chrome/utility/utility_message_handler.h" +#include "content/public/common/content_switches.h" +#include "content/public/utility/utility_thread.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_message_macros.h" + + +#if defined(OS_WIN) +#include "chrome/utility/printing_handler.h" +#endif + + +namespace { + +bool Send(IPC::Message* message) { + return content::UtilityThread::Get()->Send(message); +} + +} // namespace + +namespace atom { + +int64_t AtomContentUtilityClient::max_ipc_message_size_ = + IPC::Channel::kMaximumMessageSize; + +AtomContentUtilityClient::AtomContentUtilityClient() + : filter_messages_(false) { +#if defined(OS_WIN) + handlers_.push_back(new PrintingHandler()); +#endif +} + +AtomContentUtilityClient::~AtomContentUtilityClient() { +} + +void AtomContentUtilityClient::UtilityThreadStarted() { +} + +bool AtomContentUtilityClient::OnMessageReceived( + const IPC::Message& message) { + if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type())) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(AtomContentUtilityClient, message) + IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + for (Handlers::iterator it = handlers_.begin(); + !handled && it != handlers_.end(); ++it) { + handled = (*it)->OnMessageReceived(message); + } + + return handled; +} + +void AtomContentUtilityClient::OnStartupPing() { + Send(new ChromeUtilityHostMsg_ProcessStarted); + // Don't release the process, we assume further messages are on the way. +} + +} // namespace atom diff --git a/atom/utility/atom_content_utility_client.h b/atom/utility/atom_content_utility_client.h new file mode 100644 index 000000000000..2c245b62f61e --- /dev/null +++ b/atom/utility/atom_content_utility_client.h @@ -0,0 +1,57 @@ +// 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_UTILITY_ATOM_CONTENT_UTILITY_CLIENT_H_ +#define ATOM_UTILITY_ATOM_CONTENT_UTILITY_CLIENT_H_ + +#include +#include +#include + +#include "base/compiler_specific.h" +#include "base/memory/scoped_vector.h" +#include "content/public/utility/content_utility_client.h" +#include "ipc/ipc_platform_file.h" + +namespace base { +class FilePath; +struct FileDescriptor; +} + +class UtilityMessageHandler; + +namespace atom { + +class AtomContentUtilityClient : public content::ContentUtilityClient { + public: + AtomContentUtilityClient(); + ~AtomContentUtilityClient() override; + + void UtilityThreadStarted() override; + bool OnMessageReceived(const IPC::Message& message) override; + + + static void set_max_ipc_message_size_for_test(int64_t max_message_size) { + max_ipc_message_size_ = max_message_size; + } + + private: + void OnStartupPing(); + + typedef ScopedVector Handlers; + Handlers handlers_; + + // Flag to enable whitelisting. + bool filter_messages_; + // A list of message_ids to filter. + std::set message_id_whitelist_; + // Maximum IPC msg size (default to kMaximumMessageSize; override for testing) + static int64_t max_ipc_message_size_; + + DISALLOW_COPY_AND_ASSIGN(AtomContentUtilityClient); +}; + +} // namespace atom + +#endif // ATOM_UTILITY_ATOM_CONTENT_UTILITY_CLIENT_H_ diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc b/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc index 8f6f1912e36f..248ec6b890ef 100644 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc +++ b/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc @@ -58,6 +58,8 @@ void GlobalShortcutListenerWin::OnWndProc(HWND hwnd, modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0; modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0; modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0; + modifiers |= (LOWORD(lparam) & MOD_WIN) ? ui::EF_COMMAND_DOWN : 0; + ui::Accelerator accelerator( ui::KeyboardCodeForWindowsKeyCode(key_code), modifiers); @@ -72,6 +74,8 @@ bool GlobalShortcutListenerWin::RegisterAcceleratorImpl( modifiers |= accelerator.IsShiftDown() ? MOD_SHIFT : 0; modifiers |= accelerator.IsCtrlDown() ? MOD_CONTROL : 0; modifiers |= accelerator.IsAltDown() ? MOD_ALT : 0; + modifiers |= accelerator.IsCmdDown() ? MOD_WIN : 0; + static int hotkey_id = 0; bool success = !!RegisterHotKey( gfx::SingletonHwnd::GetInstance()->hwnd(), diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc b/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc index 5a3ad1a7a6ce..9a3cca69d538 100644 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc +++ b/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc @@ -35,6 +35,7 @@ int GetNativeModifiers(const ui::Accelerator& accelerator) { modifiers |= accelerator.IsShiftDown() ? ShiftMask : 0; modifiers |= accelerator.IsCtrlDown() ? ControlMask : 0; modifiers |= accelerator.IsAltDown() ? Mod1Mask : 0; + modifiers |= accelerator.IsCmdDown() ? Mod4Mask : 0; return modifiers; } @@ -148,6 +149,8 @@ void GlobalShortcutListenerX11::OnXKeyPressEvent(::XEvent* x_event) { modifiers |= (x_event->xkey.state & ShiftMask) ? ui::EF_SHIFT_DOWN : 0; modifiers |= (x_event->xkey.state & ControlMask) ? ui::EF_CONTROL_DOWN : 0; modifiers |= (x_event->xkey.state & Mod1Mask) ? ui::EF_ALT_DOWN : 0; + // For Windows key + modifiers |= (x_event->xkey.state & Mod4Mask) ? ui::EF_COMMAND_DOWN: 0; ui::Accelerator accelerator( ui::KeyboardCodeFromXKeyEvent(x_event), modifiers); diff --git a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc new file mode 100644 index 000000000000..89bac3b68dca --- /dev/null +++ b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc @@ -0,0 +1,495 @@ +// 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 file. + +#include "chrome/browser/printing/pdf_to_emf_converter.h" + +#include + +#include "base/files/file.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/logging.h" +#include "chrome/common/chrome_utility_messages.h" +#include "chrome/common/print_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_data.h" +#include "content/public/browser/utility_process_host.h" +#include "content/public/browser/utility_process_host_client.h" +#include "printing/emf_win.h" +#include "printing/pdf_render_settings.h" + +namespace printing { + +namespace { + +using content::BrowserThread; + +class PdfToEmfConverterImpl; + +// Allows to delete temporary directory after all temporary files created inside +// are closed. Windows cannot delete directory with opened files. Directory is +// used to store PDF and metafiles. PDF should be gone by the time utility +// process exits. Metafiles should be gone when all LazyEmf destroyed. +class RefCountedTempDir + : public base::RefCountedThreadSafe { + public: + RefCountedTempDir() { ignore_result(temp_dir_.CreateUniqueTempDir()); } + bool IsValid() const { return temp_dir_.IsValid(); } + const base::FilePath& GetPath() const { return temp_dir_.path(); } + + private: + friend struct BrowserThread::DeleteOnThread; + friend class base::DeleteHelper; + ~RefCountedTempDir() {} + + base::ScopedTempDir temp_dir_; + DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir); +}; + +typedef scoped_ptr + ScopedTempFile; + +// Wrapper for Emf to keep only file handle in memory, and load actual data only +// on playback. Emf::InitFromFile() can play metafile directly from disk, but it +// can't open file handles. We need file handles to reliably delete temporary +// files, and to efficiently interact with utility process. +class LazyEmf : public MetafilePlayer { + public: + LazyEmf(const scoped_refptr& temp_dir, ScopedTempFile file) + : temp_dir_(temp_dir), file_(file.Pass()) {} + virtual ~LazyEmf() { Close(); } + + virtual bool SafePlayback(HDC hdc) const override; + virtual bool SaveTo(base::File* file) const override; + + private: + void Close() const; + bool LoadEmf(Emf* emf) const; + + mutable scoped_refptr temp_dir_; + mutable ScopedTempFile file_; // Mutable because of consts in base class. + + DISALLOW_COPY_AND_ASSIGN(LazyEmf); +}; + +// Converts PDF into EMF. +// Class uses 3 threads: UI, IO and FILE. +// Internal workflow is following: +// 1. Create instance on the UI thread. (files_, settings_,) +// 2. Create pdf file on the FILE thread. +// 3. Start utility process and start conversion on the IO thread. +// 4. Utility process returns page count. +// 5. For each page: +// 1. Clients requests page with file handle to a temp file. +// 2. Utility converts the page, save it to the file and reply. +// +// All these steps work sequentially, so no data should be accessed +// simultaneously by several threads. +class PdfToEmfUtilityProcessHostClient + : public content::UtilityProcessHostClient { + public: + PdfToEmfUtilityProcessHostClient( + base::WeakPtr converter, + const PdfRenderSettings& settings); + + void Start(const scoped_refptr& data, + const PdfToEmfConverter::StartCallback& start_callback); + + void GetPage(int page_number, + const PdfToEmfConverter::GetPageCallback& get_page_callback); + + void Stop(); + + // UtilityProcessHostClient implementation. + virtual void OnProcessCrashed(int exit_code) override; + virtual void OnProcessLaunchFailed() override; + virtual bool OnMessageReceived(const IPC::Message& message) override; + + private: + class GetPageCallbackData { + MOVE_ONLY_TYPE_FOR_CPP_03(GetPageCallbackData, RValue); + + public: + GetPageCallbackData(int page_number, + PdfToEmfConverter::GetPageCallback callback) + : page_number_(page_number), callback_(callback) {} + + // Move constructor for STL. + GetPageCallbackData(RValue other) { this->operator=(other); } + + // Move assignment for STL. + GetPageCallbackData& operator=(RValue rhs) { + page_number_ = rhs.object->page_number_; + callback_ = rhs.object->callback_; + emf_ = rhs.object->emf_.Pass(); + return *this; + } + + int page_number() const { return page_number_; } + const PdfToEmfConverter::GetPageCallback& callback() const { + return callback_; + } + ScopedTempFile emf() { return emf_.Pass(); } + void set_emf(ScopedTempFile emf) { emf_ = emf.Pass(); } + + private: + int page_number_; + PdfToEmfConverter::GetPageCallback callback_; + ScopedTempFile emf_; + }; + + virtual ~PdfToEmfUtilityProcessHostClient(); + + bool Send(IPC::Message* msg); + + // Message handlers. + void OnProcessStarted(); + void OnPageCount(int page_count); + void OnPageDone(bool success, float scale_factor); + + void OnFailed(); + void OnTempPdfReady(ScopedTempFile pdf); + void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf); + + scoped_refptr temp_dir_; + + // Used to suppress callbacks after PdfToEmfConverterImpl is deleted. + base::WeakPtr converter_; + PdfRenderSettings settings_; + scoped_refptr data_; + + // Document loaded callback. + PdfToEmfConverter::StartCallback start_callback_; + + // Process host for IPC. + base::WeakPtr utility_process_host_; + + // Queue of callbacks for GetPage() requests. Utility process should reply + // with PageDone in the same order as requests were received. + // Use containers that keeps element pointers valid after push() and pop(). + typedef std::queue GetPageCallbacks; + GetPageCallbacks get_page_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); +}; + +class PdfToEmfConverterImpl : public PdfToEmfConverter { + public: + PdfToEmfConverterImpl(); + + virtual ~PdfToEmfConverterImpl(); + + virtual void Start(const scoped_refptr& data, + const PdfRenderSettings& conversion_settings, + const StartCallback& start_callback) override; + + virtual void GetPage(int page_number, + const GetPageCallback& get_page_callback) override; + + // Helps to cancel callbacks if this object is destroyed. + void RunCallback(const base::Closure& callback); + + private: + scoped_refptr utility_client_; + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl); +}; + +ScopedTempFile CreateTempFile(scoped_refptr* temp_dir) { + if (!temp_dir->get()) + *temp_dir = new RefCountedTempDir(); + ScopedTempFile file; + if (!(*temp_dir)->IsValid()) + return file.Pass(); + base::FilePath path; + if (!base::CreateTemporaryFileInDir((*temp_dir)->GetPath(), &path)) + return file.Pass(); + file.reset(new base::File(path, + base::File::FLAG_CREATE_ALWAYS | + base::File::FLAG_WRITE | + base::File::FLAG_READ | + base::File::FLAG_DELETE_ON_CLOSE | + base::File::FLAG_TEMPORARY)); + if (!file->IsValid()) + file.reset(); + return file.Pass(); +} + +ScopedTempFile CreateTempPdfFile( + const scoped_refptr& data, + scoped_refptr* temp_dir) { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + + ScopedTempFile pdf_file = CreateTempFile(temp_dir); + if (!pdf_file || + static_cast(data->size()) != + pdf_file->WriteAtCurrentPos(data->front_as(), data->size())) { + pdf_file.reset(); + } + pdf_file->Seek(base::File::FROM_BEGIN, 0); + return pdf_file.Pass(); +} + +bool LazyEmf::SafePlayback(HDC hdc) const { + Emf emf; + bool result = LoadEmf(&emf) && emf.SafePlayback(hdc); + // TODO(vitalybuka): Fix destruction of metafiles. For some reasons + // instances of Emf are not deleted. crbug.com/411683 + // It's known that the Emf going to be played just once to a printer. So just + // release file here. + Close(); + return result; +} + +bool LazyEmf::SaveTo(base::File* file) const { + Emf emf; + return LoadEmf(&emf) && emf.SaveTo(file); +} + +void LazyEmf::Close() const { + file_.reset(); + temp_dir_ = NULL; +} + +bool LazyEmf::LoadEmf(Emf* emf) const { + file_->Seek(base::File::FROM_BEGIN, 0); + int64 size = file_->GetLength(); + if (size <= 0) + return false; + std::vector data(size); + if (file_->ReadAtCurrentPos(data.data(), data.size()) != size) + return false; + return emf->InitFromData(data.data(), data.size()); +} + +PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( + base::WeakPtr converter, + const PdfRenderSettings& settings) + : converter_(converter), settings_(settings) { +} + +PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { +} + +void PdfToEmfUtilityProcessHostClient::Start( + const scoped_refptr& data, + const PdfToEmfConverter::StartCallback& start_callback) { + if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { + BrowserThread::PostTask(BrowserThread::IO, + FROM_HERE, + base::Bind(&PdfToEmfUtilityProcessHostClient::Start, + this, + data, + start_callback)); + return; + } + data_ = data; + + // Store callback before any OnFailed() call to make it called on failure. + start_callback_ = start_callback; + + // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load + // gdiplus.dll, change how rendering happens, and not be able to correctly + // generate when sent to a metafile DC. + utility_process_host_ = + content::UtilityProcessHost::Create( + this, base::MessageLoop::current()->message_loop_proxy()) + ->AsWeakPtr(); + if (!utility_process_host_) + return OnFailed(); + // Should reply with OnProcessStarted(). + Send(new ChromeUtilityMsg_StartupPing); +} + +void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!utility_process_host_) + return OnFailed(); + + scoped_refptr data = data_; + data_ = NULL; + BrowserThread::PostTaskAndReplyWithResult( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&CreateTempPdfFile, data, &temp_dir_), + base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this)); +} + +void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!utility_process_host_) + return OnFailed(); + base::ProcessHandle process = utility_process_host_->GetData().handle; + // Should reply with OnPageCount(). + Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles( + IPC::GetFileHandleForProcess(pdf->GetPlatformFile(), process, false), + settings_)); +} + +void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (start_callback_.is_null()) + return OnFailed(); + BrowserThread::PostTask(BrowserThread::UI, + FROM_HERE, + base::Bind(&PdfToEmfConverterImpl::RunCallback, + converter_, + base::Bind(start_callback_, page_count))); + start_callback_.Reset(); +} + +void PdfToEmfUtilityProcessHostClient::GetPage( + int page_number, + const PdfToEmfConverter::GetPageCallback& get_page_callback) { + if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&PdfToEmfUtilityProcessHostClient::GetPage, + this, + page_number, + get_page_callback)); + return; + } + + // Store callback before any OnFailed() call to make it called on failure. + get_page_callbacks_.push(GetPageCallbackData(page_number, get_page_callback)); + + if (!utility_process_host_) + return OnFailed(); + + BrowserThread::PostTaskAndReplyWithResult( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&CreateTempFile, &temp_dir_), + base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempEmfReady, + this, + &get_page_callbacks_.back())); +} + +void PdfToEmfUtilityProcessHostClient::OnTempEmfReady( + GetPageCallbackData* callback_data, + ScopedTempFile emf) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!utility_process_host_) + return OnFailed(); + base::ProcessHandle process = utility_process_host_->GetData().handle; + IPC::PlatformFileForTransit transit = + IPC::GetFileHandleForProcess(emf->GetPlatformFile(), process, false); + callback_data->set_emf(emf.Pass()); + // Should reply with OnPageDone(). + Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage( + callback_data->page_number(), transit)); +} + +void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success, + float scale_factor) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (get_page_callbacks_.empty()) + return OnFailed(); + scoped_ptr emf; + GetPageCallbackData& data = get_page_callbacks_.front(); + if (success) + emf.reset(new LazyEmf(temp_dir_, data.emf().Pass())); + BrowserThread::PostTask(BrowserThread::UI, + FROM_HERE, + base::Bind(&PdfToEmfConverterImpl::RunCallback, + converter_, + base::Bind(data.callback(), + data.page_number(), + scale_factor, + base::Passed(&emf)))); + get_page_callbacks_.pop(); +} + +void PdfToEmfUtilityProcessHostClient::Stop() { + if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&PdfToEmfUtilityProcessHostClient::Stop, this)); + return; + } + Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop()); +} + +void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { + OnFailed(); +} + +void PdfToEmfUtilityProcessHostClient::OnProcessLaunchFailed() { + OnFailed(); +} + +bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message) + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) + IPC_MESSAGE_HANDLER( + ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount) + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, + OnPageDone) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool PdfToEmfUtilityProcessHostClient::Send(IPC::Message* msg) { + if (utility_process_host_) + return utility_process_host_->Send(msg); + delete msg; + return false; +} + +void PdfToEmfUtilityProcessHostClient::OnFailed() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!start_callback_.is_null()) + OnPageCount(0); + while (!get_page_callbacks_.empty()) + OnPageDone(false, 0.0f); + utility_process_host_.reset(); +} + +PdfToEmfConverterImpl::PdfToEmfConverterImpl() : weak_ptr_factory_(this) { +} + +PdfToEmfConverterImpl::~PdfToEmfConverterImpl() { + if (utility_client_.get()) + utility_client_->Stop(); +} + +void PdfToEmfConverterImpl::Start( + const scoped_refptr& data, + const PdfRenderSettings& conversion_settings, + const StartCallback& start_callback) { + DCHECK(!utility_client_.get()); + utility_client_ = new PdfToEmfUtilityProcessHostClient( + weak_ptr_factory_.GetWeakPtr(), conversion_settings); + utility_client_->Start(data, start_callback); +} + +void PdfToEmfConverterImpl::GetPage(int page_number, + const GetPageCallback& get_page_callback) { + utility_client_->GetPage(page_number, get_page_callback); +} + +void PdfToEmfConverterImpl::RunCallback(const base::Closure& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + callback.Run(); +} + +} // namespace + +PdfToEmfConverter::~PdfToEmfConverter() { +} + +// static +scoped_ptr PdfToEmfConverter::CreateDefault() { + return scoped_ptr(new PdfToEmfConverterImpl()); +} + +} // namespace printing diff --git a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h new file mode 100644 index 000000000000..60fdbc4b7e4e --- /dev/null +++ b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h @@ -0,0 +1,48 @@ +// 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 file. + +#ifndef CHROME_BROWSER_PRINTING_PDF_TO_EMF_CONVERTER_H_ +#define CHROME_BROWSER_PRINTING_PDF_TO_EMF_CONVERTER_H_ + +#include "base/callback.h" +#include "base/memory/ref_counted_memory.h" +#include "base/memory/scoped_ptr.h" + +namespace base { +class FilePath; +} + +namespace printing { + +class MetafilePlayer; +class PdfRenderSettings; + +class PdfToEmfConverter { + public: + typedef base::Callback StartCallback; + typedef base::Callback emf)> GetPageCallback; + + virtual ~PdfToEmfConverter(); + + static scoped_ptr CreateDefault(); + + // Starts conversion of PDF provided as |data|. Calls |start_callback| + // with positive |page_count|. |page_count| is 0 if initialization failed. + virtual void Start(const scoped_refptr& data, + const PdfRenderSettings& conversion_settings, + const StartCallback& start_callback) = 0; + + // Requests conversion of the page. |page_number| is 0-base page number in + // PDF provided in Start() call. + // Calls |get_page_callback| after conversion. |emf| of callback in not NULL + // if conversion succeeded. + virtual void GetPage(int page_number, + const GetPageCallback& get_page_callback) = 0; +}; + +} // namespace printing + +#endif // CHROME_BROWSER_PRINTING_PDF_TO_EMF_CONVERTER_H_ diff --git a/chromium_src/chrome/browser/printing/print_job.cc b/chromium_src/chrome/browser/printing/print_job.cc index 25cf0ad79033..6bcc58322124 100644 --- a/chromium_src/chrome/browser/printing/print_job.cc +++ b/chromium_src/chrome/browser/printing/print_job.cc @@ -17,6 +17,12 @@ #include "printing/printed_document.h" #include "printing/printed_page.h" +#if defined(OS_WIN) +#include "chrome/browser/printing/pdf_to_emf_converter.h" +#include "printing/pdf_render_settings.h" +#endif + + using base::TimeDelta; namespace { @@ -272,6 +278,103 @@ void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) { } } +#if defined(OS_WIN) + +class PrintJob::PdfToEmfState { + public: + PdfToEmfState(const gfx::Size& page_size, const gfx::Rect& content_area) + : page_count_(0), + current_page_(0), + pages_in_progress_(0), + page_size_(page_size), + content_area_(content_area), + converter_(PdfToEmfConverter::CreateDefault()) {} + + void Start(const scoped_refptr& data, + const PdfRenderSettings& conversion_settings, + const PdfToEmfConverter::StartCallback& start_callback) { + converter_->Start(data, conversion_settings, start_callback); + } + + void GetMorePages( + const PdfToEmfConverter::GetPageCallback& get_page_callback) { + const int kMaxNumberOfTempFilesPerDocument = 3; + while (pages_in_progress_ < kMaxNumberOfTempFilesPerDocument && + current_page_ < page_count_) { + ++pages_in_progress_; + converter_->GetPage(current_page_++, get_page_callback); + } + } + + void OnPageProcessed( + const PdfToEmfConverter::GetPageCallback& get_page_callback) { + --pages_in_progress_; + GetMorePages(get_page_callback); + // Release converter if we don't need this any more. + if (!pages_in_progress_ && current_page_ >= page_count_) + converter_.reset(); + } + + void set_page_count(int page_count) { page_count_ = page_count; } + gfx::Size page_size() const { return page_size_; } + gfx::Rect content_area() const { return content_area_; } + + private: + int page_count_; + int current_page_; + int pages_in_progress_; + gfx::Size page_size_; + gfx::Rect content_area_; + scoped_ptr converter_; +}; + +void PrintJob::StartPdfToEmfConversion( + const scoped_refptr& bytes, + const gfx::Size& page_size, + const gfx::Rect& content_area) { + DCHECK(!ptd_to_emf_state_.get()); + ptd_to_emf_state_.reset(new PdfToEmfState(page_size, content_area)); + const int kPrinterDpi = settings().dpi(); + ptd_to_emf_state_->Start( + bytes, + printing::PdfRenderSettings(content_area, kPrinterDpi, true), + base::Bind(&PrintJob::OnPdfToEmfStarted, this)); +} + +void PrintJob::OnPdfToEmfStarted(int page_count) { + if (page_count <= 0) { + ptd_to_emf_state_.reset(); + Cancel(); + return; + } + ptd_to_emf_state_->set_page_count(page_count); + ptd_to_emf_state_->GetMorePages( + base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); +} + +void PrintJob::OnPdfToEmfPageConverted(int page_number, + float scale_factor, + scoped_ptr emf) { + DCHECK(ptd_to_emf_state_); + if (!document_.get() || !emf) { + ptd_to_emf_state_.reset(); + Cancel(); + return; + } + + // Update the rendered document. It will send notifications to the listener. + document_->SetPage(page_number, + emf.Pass(), + scale_factor, + ptd_to_emf_state_->page_size(), + ptd_to_emf_state_->content_area()); + + ptd_to_emf_state_->GetMorePages( + base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); +} + +#endif // OS_WIN + void PrintJob::OnDocumentDone() { // Be sure to live long enough. The instance could be destroyed by the // JOB_DONE broadcast. diff --git a/chromium_src/chrome/browser/printing/print_job.h b/chromium_src/chrome/browser/printing/print_job.h index a0f844a27c2d..48daaa6cb971 100644 --- a/chromium_src/chrome/browser/printing/print_job.h +++ b/chromium_src/chrome/browser/printing/print_job.h @@ -90,6 +90,19 @@ class PrintJob : public PrintJobWorkerOwner, // Access the current printed document. Warning: may be NULL. PrintedDocument* document() const; +#if defined(OS_WIN) + void StartPdfToEmfConversion( + const scoped_refptr& bytes, + const gfx::Size& page_size, + const gfx::Rect& content_area); + + void OnPdfToEmfStarted(int page_count); + void OnPdfToEmfPageConverted(int page_number, + float scale_factor, + scoped_ptr emf); + +#endif // OS_WIN + protected: virtual ~PrintJob(); @@ -137,6 +150,11 @@ class PrintJob : public PrintJobWorkerOwner, // the notified calls Cancel() again. bool is_canceling_; +#if defined(OS_WIN) + class PdfToEmfState; + scoped_ptr ptd_to_emf_state_; +#endif // OS_WIN + // Used at shutdown so that we can quit a nested message loop. base::WeakPtrFactory quit_factory_; diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.cc b/chromium_src/chrome/browser/printing/print_view_manager_base.cc index 3aec7a14d546..35c62fbc5327 100644 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.cc +++ b/chromium_src/chrome/browser/printing/print_view_manager_base.cc @@ -156,6 +156,8 @@ void PrintViewManagerBase::OnDidPrintPage( params.data_size); document->DebugDumpData(bytes.get(), FILE_PATH_LITERAL(".pdf")); + print_job_->StartPdfToEmfConversion( + bytes, params.page_size, params.content_area); } #endif // !OS_WIN } diff --git a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc new file mode 100644 index 000000000000..c2992abcc11d --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc @@ -0,0 +1,89 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h" + +#include "build/build_config.h" +#include "chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h" +#include "chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h" +#include "chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h" +#include "chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h" +#include "content/public/browser/browser_ppapi_host.h" +#include "ppapi/host/message_filter_host.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_permissions.h" + +using ppapi::host::MessageFilterHost; +using ppapi::host::ResourceHost; +using ppapi::host::ResourceMessageFilter; + +namespace chrome { + +ChromeBrowserPepperHostFactory::ChromeBrowserPepperHostFactory( + content::BrowserPpapiHost* host) + : host_(host) {} + +ChromeBrowserPepperHostFactory::~ChromeBrowserPepperHostFactory() {} + +scoped_ptr ChromeBrowserPepperHostFactory::CreateResourceHost( + ppapi::host::PpapiHost* host, + PP_Resource resource, + PP_Instance instance, + const IPC::Message& message) { + DCHECK(host == host_->GetPpapiHost()); + + // Make sure the plugin is giving us a valid instance for this resource. + if (!host_->IsValidInstance(instance)) + return scoped_ptr(); + + // Private interfaces. + if (host_->GetPpapiHost()->permissions().HasPermission( + ppapi::PERMISSION_PRIVATE)) { + switch (message.type()) { + case PpapiHostMsg_Broker_Create::ID: { + scoped_refptr broker_filter( + new PepperBrokerMessageFilter(instance, host_)); + return scoped_ptr(new MessageFilterHost( + host_->GetPpapiHost(), instance, resource, broker_filter)); + } + } + } + + // Flash interfaces. + if (host_->GetPpapiHost()->permissions().HasPermission( + ppapi::PERMISSION_FLASH)) { + switch (message.type()) { + case PpapiHostMsg_Flash_Create::ID: + return scoped_ptr( + new PepperFlashBrowserHost(host_, instance, resource)); + case PpapiHostMsg_FlashClipboard_Create::ID: { + scoped_refptr clipboard_filter( + new PepperFlashClipboardMessageFilter); + return scoped_ptr(new MessageFilterHost( + host_->GetPpapiHost(), instance, resource, clipboard_filter)); + } + } + } + + // Permissions for the following interfaces will be checked at the + // time of the corresponding instance's methods calls (because + // permission check can be performed only on the UI + // thread). Currently these interfaces are available only for + // whitelisted apps which may not have access to the other private + // interfaces. + if (message.type() == PpapiHostMsg_IsolatedFileSystem_Create::ID) { + PepperIsolatedFileSystemMessageFilter* isolated_fs_filter = + PepperIsolatedFileSystemMessageFilter::Create(instance, host_); + if (!isolated_fs_filter) + return scoped_ptr(); + return scoped_ptr( + new MessageFilterHost(host, instance, resource, isolated_fs_filter)); + } + + return scoped_ptr(); +} + +} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h new file mode 100644 index 000000000000..b817953b54dc --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h @@ -0,0 +1,38 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_BROWSER_RENDERER_HOST_PEPPER_CHROME_BROWSER_PEPPER_HOST_FACTORY_H_ +#define CHROME_BROWSER_RENDERER_HOST_PEPPER_CHROME_BROWSER_PEPPER_HOST_FACTORY_H_ + +#include "base/compiler_specific.h" +#include "ppapi/host/host_factory.h" + +namespace content { +class BrowserPpapiHost; +} // namespace content + +namespace chrome { + +class ChromeBrowserPepperHostFactory : public ppapi::host::HostFactory { + public: + // Non-owning pointer to the filter must outlive this class. + explicit ChromeBrowserPepperHostFactory(content::BrowserPpapiHost* host); + ~ChromeBrowserPepperHostFactory() override; + + scoped_ptr CreateResourceHost( + ppapi::host::PpapiHost* host, + PP_Resource resource, + PP_Instance instance, + const IPC::Message& message) override; + + private: + // Non-owning pointer. + content::BrowserPpapiHost* host_; + + DISALLOW_COPY_AND_ASSIGN(ChromeBrowserPepperHostFactory); +}; + +} // namespace chrome + +#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_CHROME_BROWSER_PEPPER_HOST_FACTORY_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc new file mode 100644 index 000000000000..224b55d4cac5 --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h" + +#include + +#include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "ipc/ipc_message_macros.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "url/gurl.h" + +using content::BrowserPpapiHost; +using content::BrowserThread; +using content::RenderProcessHost; + +namespace chrome { + +PepperBrokerMessageFilter::PepperBrokerMessageFilter(PP_Instance instance, + BrowserPpapiHost* host) + : document_url_(host->GetDocumentURLForInstance(instance)) { + int unused; + host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused); +} + +PepperBrokerMessageFilter::~PepperBrokerMessageFilter() {} + +scoped_refptr +PepperBrokerMessageFilter::OverrideTaskRunnerForMessage( + const IPC::Message& message) { + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); +} + +int32_t PepperBrokerMessageFilter::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperBrokerMessageFilter, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Broker_IsAllowed, + OnIsAllowed) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperBrokerMessageFilter::OnIsAllowed( + ppapi::host::HostMessageContext* context) { + return PP_OK; +} + +} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h new file mode 100644 index 000000000000..44627c6a3556 --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h @@ -0,0 +1,51 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_BROKER_MESSAGE_FILTER_H_ +#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_BROKER_MESSAGE_FILTER_H_ + +#include "base/compiler_specific.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/host/resource_message_filter.h" +#include "url/gurl.h" + +namespace content { +class BrowserPpapiHost; +} + +namespace ppapi { +namespace host { +struct HostMessageContext; +} +} + +namespace chrome { + +// This filter handles messages for the PepperBrokerHost on the UI thread. +class PepperBrokerMessageFilter : public ppapi::host::ResourceMessageFilter { + public: + PepperBrokerMessageFilter(PP_Instance instance, + content::BrowserPpapiHost* host); + + private: + ~PepperBrokerMessageFilter() override; + + // ppapi::host::ResourceMessageFilter overrides. + scoped_refptr OverrideTaskRunnerForMessage( + const IPC::Message& message) override; + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + int32_t OnIsAllowed(ppapi::host::HostMessageContext* context); + + int render_process_id_; + GURL document_url_; + + DISALLOW_COPY_AND_ASSIGN(PepperBrokerMessageFilter); +}; + +} // namespace chrome + +#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_BROKER_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc new file mode 100644 index 000000000000..43179c68d485 --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc @@ -0,0 +1,114 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h" + +#include "base/time/time.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "ipc/ipc_message_macros.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_flash.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/time_conversion.h" +#include "url/gurl.h" + +#if defined(OS_WIN) +#include +#elif defined(OS_MACOSX) +#include +#endif + +using content::BrowserPpapiHost; +using content::BrowserThread; +using content::RenderProcessHost; + +namespace chrome { + +PepperFlashBrowserHost::PepperFlashBrowserHost(BrowserPpapiHost* host, + PP_Instance instance, + PP_Resource resource) + : ResourceHost(host->GetPpapiHost(), instance, resource), + host_(host), + weak_factory_(this) { + int unused; + host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused); +} + +PepperFlashBrowserHost::~PepperFlashBrowserHost() {} + +int32_t PepperFlashBrowserHost::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperFlashBrowserHost, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Flash_UpdateActivity, + OnUpdateActivity) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_GetLocalTimeZoneOffset, + OnGetLocalTimeZoneOffset) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( + PpapiHostMsg_Flash_GetLocalDataRestrictions, OnGetLocalDataRestrictions) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperFlashBrowserHost::OnUpdateActivity( + ppapi::host::HostMessageContext* host_context) { +#if defined(OS_WIN) + // Reading then writing back the same value to the screensaver timeout system + // setting resets the countdown which prevents the screensaver from turning + // on "for a while". As long as the plugin pings us with this message faster + // than the screensaver timeout, it won't go on. + int value = 0; + if (SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &value, 0)) + SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, value, NULL, 0); +#elif defined(OS_MACOSX) +// UpdateSystemActivity(OverallAct); +#else +// TODO(brettw) implement this for other platforms. +#endif + return PP_OK; +} + +int32_t PepperFlashBrowserHost::OnGetLocalTimeZoneOffset( + ppapi::host::HostMessageContext* host_context, + const base::Time& t) { + // The reason for this processing being in the browser process is that on + // Linux, the localtime calls require filesystem access prohibited by the + // sandbox. + host_context->reply_msg = PpapiPluginMsg_Flash_GetLocalTimeZoneOffsetReply( + ppapi::PPGetLocalTimeZoneOffset(t)); + return PP_OK; +} + +int32_t PepperFlashBrowserHost::OnGetLocalDataRestrictions( + ppapi::host::HostMessageContext* context) { + // Getting the Flash LSO settings requires using the CookieSettings which + // belong to the profile which lives on the UI thread. We lazily initialize + // |cookie_settings_| by grabbing the reference from the UI thread and then + // call |GetLocalDataRestrictions| with it. + GURL document_url = host_->GetDocumentURLForInstance(pp_instance()); + GURL plugin_url = host_->GetPluginURLForInstance(pp_instance()); + GetLocalDataRestrictions(context->MakeReplyMessageContext(), + document_url, + plugin_url); + return PP_OK_COMPLETIONPENDING; +} + +void PepperFlashBrowserHost::GetLocalDataRestrictions( + ppapi::host::ReplyMessageContext reply_context, + const GURL& document_url, + const GURL& plugin_url) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + PP_FlashLSORestrictions restrictions = PP_FLASHLSORESTRICTIONS_NONE; + SendReply(reply_context, + PpapiPluginMsg_Flash_GetLocalDataRestrictionsReply( + static_cast(restrictions))); +} + +} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h new file mode 100644 index 000000000000..6fb4aced1819 --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h @@ -0,0 +1,60 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_BROWSER_HOST_H_ +#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_BROWSER_HOST_H_ + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/resource_host.h" + +namespace base { +class Time; +} + +namespace content { +class BrowserPpapiHost; +class ResourceContext; +} + +class GURL; + +namespace chrome { + +class PepperFlashBrowserHost : public ppapi::host::ResourceHost { + public: + PepperFlashBrowserHost(content::BrowserPpapiHost* host, + PP_Instance instance, + PP_Resource resource); + ~PepperFlashBrowserHost() override; + + // ppapi::host::ResourceHost override. + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + private: + int32_t OnUpdateActivity(ppapi::host::HostMessageContext* host_context); + int32_t OnGetLocalTimeZoneOffset( + ppapi::host::HostMessageContext* host_context, + const base::Time& t); + int32_t OnGetLocalDataRestrictions(ppapi::host::HostMessageContext* context); + + void GetLocalDataRestrictions(ppapi::host::ReplyMessageContext reply_context, + const GURL& document_url, + const GURL& plugin_url); + + content::BrowserPpapiHost* host_; + int render_process_id_; + // For fetching the Flash LSO settings. + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PepperFlashBrowserHost); +}; + +} // namespace chrome + +#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_BROWSER_HOST_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc new file mode 100644 index 000000000000..4499b21aefe3 --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc @@ -0,0 +1,376 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h" + +#include "base/pickle.h" +#include "base/strings/utf_string_conversions.h" +#include "content/public/browser/browser_thread.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_macros.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_flash_clipboard.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ui/base/clipboard/scoped_clipboard_writer.h" + +using content::BrowserThread; + +namespace chrome { + +namespace { + +const size_t kMaxClipboardWriteSize = 1000000; + +ui::ClipboardType ConvertClipboardType(uint32_t type) { + switch (type) { + case PP_FLASH_CLIPBOARD_TYPE_STANDARD: + return ui::CLIPBOARD_TYPE_COPY_PASTE; + case PP_FLASH_CLIPBOARD_TYPE_SELECTION: + return ui::CLIPBOARD_TYPE_SELECTION; + } + NOTREACHED(); + return ui::CLIPBOARD_TYPE_COPY_PASTE; +} + +// Functions to pack/unpack custom data from a pickle. See the header file for +// more detail on custom formats in Pepper. +// TODO(raymes): Currently pepper custom formats are stored in their own +// native format type. However we should be able to store them in the same way +// as "Web Custom" formats are. This would allow clipboard data to be shared +// between pepper applications and web applications. However currently web apps +// assume all data that is placed on the clipboard is UTF16 and pepper allows +// arbitrary data so this change would require some reworking of the chrome +// clipboard interface for custom data. +bool JumpToFormatInPickle(const base::string16& format, PickleIterator* iter) { + size_t size = 0; + if (!iter->ReadSizeT(&size)) + return false; + for (size_t i = 0; i < size; ++i) { + base::string16 stored_format; + if (!iter->ReadString16(&stored_format)) + return false; + if (stored_format == format) + return true; + int skip_length; + if (!iter->ReadLength(&skip_length)) + return false; + if (!iter->SkipBytes(skip_length)) + return false; + } + return false; +} + +bool IsFormatAvailableInPickle(const base::string16& format, + const Pickle& pickle) { + PickleIterator iter(pickle); + return JumpToFormatInPickle(format, &iter); +} + +std::string ReadDataFromPickle(const base::string16& format, + const Pickle& pickle) { + std::string result; + PickleIterator iter(pickle); + if (!JumpToFormatInPickle(format, &iter) || !iter.ReadString(&result)) + return std::string(); + return result; +} + +bool WriteDataToPickle(const std::map& data, + Pickle* pickle) { + pickle->WriteSizeT(data.size()); + for (std::map::const_iterator it = data.begin(); + it != data.end(); + ++it) { + if (!pickle->WriteString16(it->first)) + return false; + if (!pickle->WriteString(it->second)) + return false; + } + return true; +} + +} // namespace + +PepperFlashClipboardMessageFilter::PepperFlashClipboardMessageFilter() {} + +PepperFlashClipboardMessageFilter::~PepperFlashClipboardMessageFilter() {} + +scoped_refptr +PepperFlashClipboardMessageFilter::OverrideTaskRunnerForMessage( + const IPC::Message& msg) { + // Clipboard writes should always occur on the UI thread due to the + // restrictions of various platform APIs. In general, the clipboard is not + // thread-safe, so all clipboard calls should be serviced from the UI thread. + if (msg.type() == PpapiHostMsg_FlashClipboard_WriteData::ID) + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); + +// Windows needs clipboard reads to be serviced from the IO thread because +// these are sync IPCs which can result in deadlocks with plugins if serviced +// from the UI thread. Note that Windows clipboard calls ARE thread-safe so it +// is ok for reads and writes to be serviced from different threads. +#if !defined(OS_WIN) + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); +#else + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); +#endif +} + +int32_t PepperFlashClipboardMessageFilter::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperFlashClipboardMessageFilter, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_FlashClipboard_RegisterCustomFormat, + OnMsgRegisterCustomFormat) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_FlashClipboard_IsFormatAvailable, OnMsgIsFormatAvailable) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_ReadData, + OnMsgReadData) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_WriteData, + OnMsgWriteData) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_FlashClipboard_GetSequenceNumber, OnMsgGetSequenceNumber) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperFlashClipboardMessageFilter::OnMsgRegisterCustomFormat( + ppapi::host::HostMessageContext* host_context, + const std::string& format_name) { + uint32_t format = custom_formats_.RegisterFormat(format_name); + if (format == PP_FLASH_CLIPBOARD_FORMAT_INVALID) + return PP_ERROR_FAILED; + host_context->reply_msg = + PpapiPluginMsg_FlashClipboard_RegisterCustomFormatReply(format); + return PP_OK; +} + +int32_t PepperFlashClipboardMessageFilter::OnMsgIsFormatAvailable( + ppapi::host::HostMessageContext* host_context, + uint32_t clipboard_type, + uint32_t format) { + if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) { + NOTIMPLEMENTED(); + return PP_ERROR_FAILED; + } + + ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); + ui::ClipboardType type = ConvertClipboardType(clipboard_type); + bool available = false; + switch (format) { + case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: { + bool plain = clipboard->IsFormatAvailable( + ui::Clipboard::GetPlainTextFormatType(), type); + bool plainw = clipboard->IsFormatAvailable( + ui::Clipboard::GetPlainTextWFormatType(), type); + available = plain || plainw; + break; + } + case PP_FLASH_CLIPBOARD_FORMAT_HTML: + available = clipboard->IsFormatAvailable( + ui::Clipboard::GetHtmlFormatType(), type); + break; + case PP_FLASH_CLIPBOARD_FORMAT_RTF: + available = + clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(), type); + break; + case PP_FLASH_CLIPBOARD_FORMAT_INVALID: + break; + default: + if (custom_formats_.IsFormatRegistered(format)) { + std::string format_name = custom_formats_.GetFormatName(format); + std::string clipboard_data; + clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(), + &clipboard_data); + Pickle pickle(clipboard_data.data(), clipboard_data.size()); + available = + IsFormatAvailableInPickle(base::UTF8ToUTF16(format_name), pickle); + } + break; + } + + return available ? PP_OK : PP_ERROR_FAILED; +} + +int32_t PepperFlashClipboardMessageFilter::OnMsgReadData( + ppapi::host::HostMessageContext* host_context, + uint32_t clipboard_type, + uint32_t format) { + if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) { + NOTIMPLEMENTED(); + return PP_ERROR_FAILED; + } + + ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); + ui::ClipboardType type = ConvertClipboardType(clipboard_type); + std::string clipboard_string; + int32_t result = PP_ERROR_FAILED; + switch (format) { + case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: { + if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(), + type)) { + base::string16 text; + clipboard->ReadText(type, &text); + if (!text.empty()) { + result = PP_OK; + clipboard_string = base::UTF16ToUTF8(text); + break; + } + } + // If the PlainTextW format isn't available or is empty, take the + // ASCII text format. + if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(), + type)) { + result = PP_OK; + clipboard->ReadAsciiText(type, &clipboard_string); + } + break; + } + case PP_FLASH_CLIPBOARD_FORMAT_HTML: { + if (!clipboard->IsFormatAvailable(ui::Clipboard::GetHtmlFormatType(), + type)) { + break; + } + + base::string16 html; + std::string url; + uint32 fragment_start; + uint32 fragment_end; + clipboard->ReadHTML(type, &html, &url, &fragment_start, &fragment_end); + result = PP_OK; + clipboard_string = base::UTF16ToUTF8( + html.substr(fragment_start, fragment_end - fragment_start)); + break; + } + case PP_FLASH_CLIPBOARD_FORMAT_RTF: { + if (!clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(), + type)) { + break; + } + result = PP_OK; + clipboard->ReadRTF(type, &clipboard_string); + break; + } + case PP_FLASH_CLIPBOARD_FORMAT_INVALID: + break; + default: { + if (custom_formats_.IsFormatRegistered(format)) { + base::string16 format_name = + base::UTF8ToUTF16(custom_formats_.GetFormatName(format)); + std::string clipboard_data; + clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(), + &clipboard_data); + Pickle pickle(clipboard_data.data(), clipboard_data.size()); + if (IsFormatAvailableInPickle(format_name, pickle)) { + result = PP_OK; + clipboard_string = ReadDataFromPickle(format_name, pickle); + } + } + break; + } + } + + if (result == PP_OK) { + host_context->reply_msg = + PpapiPluginMsg_FlashClipboard_ReadDataReply(clipboard_string); + } + return result; +} + +int32_t PepperFlashClipboardMessageFilter::OnMsgWriteData( + ppapi::host::HostMessageContext* host_context, + uint32_t clipboard_type, + const std::vector& formats, + const std::vector& data) { + if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) { + NOTIMPLEMENTED(); + return PP_ERROR_FAILED; + } + if (formats.size() != data.size()) + return PP_ERROR_FAILED; + + ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); + ui::ClipboardType type = ConvertClipboardType(clipboard_type); + // If no formats are passed in clear the clipboard. + if (formats.size() == 0) { + clipboard->Clear(type); + return PP_OK; + } + + ui::ScopedClipboardWriter scw(type); + std::map custom_data_map; + int32_t res = PP_OK; + for (uint32_t i = 0; i < formats.size(); ++i) { + if (data[i].length() > kMaxClipboardWriteSize) { + res = PP_ERROR_NOSPACE; + break; + } + + switch (formats[i]) { + case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: + scw.WriteText(base::UTF8ToUTF16(data[i])); + break; + case PP_FLASH_CLIPBOARD_FORMAT_HTML: + scw.WriteHTML(base::UTF8ToUTF16(data[i]), std::string()); + break; + case PP_FLASH_CLIPBOARD_FORMAT_RTF: + scw.WriteRTF(data[i]); + break; + case PP_FLASH_CLIPBOARD_FORMAT_INVALID: + res = PP_ERROR_BADARGUMENT; + break; + default: + if (custom_formats_.IsFormatRegistered(formats[i])) { + std::string format_name = custom_formats_.GetFormatName(formats[i]); + custom_data_map[base::UTF8ToUTF16(format_name)] = data[i]; + } else { + // Invalid format. + res = PP_ERROR_BADARGUMENT; + break; + } + } + + if (res != PP_OK) + break; + } + + if (custom_data_map.size() > 0) { + Pickle pickle; + if (WriteDataToPickle(custom_data_map, &pickle)) { + scw.WritePickledData(pickle, + ui::Clipboard::GetPepperCustomDataFormatType()); + } else { + res = PP_ERROR_BADARGUMENT; + } + } + + if (res != PP_OK) { + // Need to clear the objects so nothing is written. + scw.Reset(); + } + + return res; +} + +int32_t PepperFlashClipboardMessageFilter::OnMsgGetSequenceNumber( + ppapi::host::HostMessageContext* host_context, + uint32_t clipboard_type) { + if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) { + NOTIMPLEMENTED(); + return PP_ERROR_FAILED; + } + + ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); + ui::ClipboardType type = ConvertClipboardType(clipboard_type); + int64_t sequence_number = clipboard->GetSequenceNumber(type); + host_context->reply_msg = + PpapiPluginMsg_FlashClipboard_GetSequenceNumberReply(sequence_number); + return PP_OK; +} + +} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h new file mode 100644 index 000000000000..ff07eb73750c --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h @@ -0,0 +1,78 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_CLIPBOARD_MESSAGE_FILTER_H_ +#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_CLIPBOARD_MESSAGE_FILTER_H_ + +#include +#include + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/host/resource_message_filter.h" +#include "ppapi/shared_impl/flash_clipboard_format_registry.h" + +namespace ppapi { +namespace host { +struct HostMessageContext; +} +} + +namespace ui { +class ScopedClipboardWriter; +} + +namespace chrome { + +// Resource message filter for accessing the clipboard in Pepper. Pepper +// supports reading/writing custom formats from the clipboard. Currently, all +// custom formats that are read/written from the clipboard through pepper are +// stored in a single real clipboard format (in the same way the "web custom" +// clipboard formats are). This is done so that we don't have to have use real +// clipboard types for each custom clipboard format which may be a limited +// resource on a particular platform. +class PepperFlashClipboardMessageFilter + : public ppapi::host::ResourceMessageFilter { + public: + PepperFlashClipboardMessageFilter(); + + protected: + // ppapi::host::ResourceMessageFilter overrides. + scoped_refptr OverrideTaskRunnerForMessage( + const IPC::Message& msg) override; + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + private: + ~PepperFlashClipboardMessageFilter() override; + + int32_t OnMsgRegisterCustomFormat( + ppapi::host::HostMessageContext* host_context, + const std::string& format_name); + int32_t OnMsgIsFormatAvailable(ppapi::host::HostMessageContext* host_context, + uint32_t clipboard_type, + uint32_t format); + int32_t OnMsgReadData(ppapi::host::HostMessageContext* host_context, + uint32_t clipoard_type, + uint32_t format); + int32_t OnMsgWriteData(ppapi::host::HostMessageContext* host_context, + uint32_t clipboard_type, + const std::vector& formats, + const std::vector& data); + int32_t OnMsgGetSequenceNumber(ppapi::host::HostMessageContext* host_context, + uint32_t clipboard_type); + + int32_t WriteClipboardDataItem(uint32_t format, + const std::string& data, + ui::ScopedClipboardWriter* scw); + + ppapi::FlashClipboardFormatRegistry custom_formats_; + + DISALLOW_COPY_AND_ASSIGN(PepperFlashClipboardMessageFilter); +}; + +} // namespace chrome + +#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_CLIPBOARD_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc new file mode 100644 index 000000000000..10c07906af9b --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc @@ -0,0 +1,110 @@ +// Copyright 2013 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 file. + +#include "chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h" + +#include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_security_policy.h" +#include "content/public/browser/render_view_host.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/file_system_util.h" +#include "storage/browser/fileapi/isolated_context.h" + +namespace chrome { + +// static +PepperIsolatedFileSystemMessageFilter* +PepperIsolatedFileSystemMessageFilter::Create(PP_Instance instance, + content::BrowserPpapiHost* host) { + int render_process_id; + int unused_render_frame_id; + if (!host->GetRenderFrameIDsForInstance( + instance, &render_process_id, &unused_render_frame_id)) { + return NULL; + } + return new PepperIsolatedFileSystemMessageFilter( + render_process_id, + host->GetProfileDataDirectory(), + host->GetDocumentURLForInstance(instance), + host->GetPpapiHost()); +} + +PepperIsolatedFileSystemMessageFilter::PepperIsolatedFileSystemMessageFilter( + int render_process_id, + const base::FilePath& profile_directory, + const GURL& document_url, + ppapi::host::PpapiHost* ppapi_host) + : render_process_id_(render_process_id), + profile_directory_(profile_directory), + document_url_(document_url), + ppapi_host_(ppapi_host) { +} + +PepperIsolatedFileSystemMessageFilter:: + ~PepperIsolatedFileSystemMessageFilter() {} + +scoped_refptr +PepperIsolatedFileSystemMessageFilter::OverrideTaskRunnerForMessage( + const IPC::Message& msg) { + // In order to reach ExtensionSystem, we need to get ProfileManager first. + // ProfileManager lives in UI thread, so we need to do this in UI thread. + return content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::UI); +} + +int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperIsolatedFileSystemMessageFilter, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_IsolatedFileSystem_BrowserOpen, + OnOpenFileSystem) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem( + ppapi::host::HostMessageContext* context, + PP_IsolatedFileSystemType_Private type) { + switch (type) { + case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_INVALID: + case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_CRX: + break; + case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE: + return OpenPluginPrivateFileSystem(context); + } + NOTREACHED(); + context->reply_msg = + PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(std::string()); + return PP_ERROR_FAILED; +} + +int32_t PepperIsolatedFileSystemMessageFilter::OpenPluginPrivateFileSystem( + ppapi::host::HostMessageContext* context) { + DCHECK(ppapi_host_); + // Only plugins with private permission can open the filesystem. + if (!ppapi_host_->permissions().HasPermission(ppapi::PERMISSION_PRIVATE)) + return PP_ERROR_NOACCESS; + + const std::string& root_name = ppapi::IsolatedFileSystemTypeToRootName( + PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE); + const std::string& fsid = + storage::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath( + storage::kFileSystemTypePluginPrivate, root_name, base::FilePath()); + + // Grant full access of isolated filesystem to renderer process. + content::ChildProcessSecurityPolicy* policy = + content::ChildProcessSecurityPolicy::GetInstance(); + policy->GrantCreateReadWriteFileSystem(render_process_id_, fsid); + + context->reply_msg = PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(fsid); + return PP_OK; +} + +} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h new file mode 100644 index 000000000000..6a24feadd150 --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h @@ -0,0 +1,76 @@ +// Copyright 2013 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 file. + +#ifndef CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ +#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ + +#include +#include + +#include "base/files/file_path.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/private/ppb_isolated_file_system_private.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/host/resource_message_filter.h" +#include "url/gurl.h" + +class Profile; + +namespace content { +class BrowserPpapiHost; +} + +namespace ppapi { +namespace host { +struct HostMessageContext; +} // namespace host +} // namespace ppapi + +namespace chrome { + +class PepperIsolatedFileSystemMessageFilter + : public ppapi::host::ResourceMessageFilter { + public: + static PepperIsolatedFileSystemMessageFilter* Create( + PP_Instance instance, + content::BrowserPpapiHost* host); + + // ppapi::host::ResourceMessageFilter implementation. + scoped_refptr OverrideTaskRunnerForMessage( + const IPC::Message& msg) override; + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + private: + PepperIsolatedFileSystemMessageFilter(int render_process_id, + const base::FilePath& profile_directory, + const GURL& document_url, + ppapi::host::PpapiHost* ppapi_host_); + + ~PepperIsolatedFileSystemMessageFilter() override; + + // Returns filesystem id of isolated filesystem if valid, or empty string + // otherwise. This must run on the UI thread because ProfileManager only + // allows access on that thread. + + int32_t OnOpenFileSystem(ppapi::host::HostMessageContext* context, + PP_IsolatedFileSystemType_Private type); + int32_t OpenPluginPrivateFileSystem(ppapi::host::HostMessageContext* context); + + const int render_process_id_; + // Keep a copy from original thread. + const base::FilePath profile_directory_; + const GURL document_url_; + + // Not owned by this object. + ppapi::host::PpapiHost* ppapi_host_; + + DISALLOW_COPY_AND_ASSIGN(PepperIsolatedFileSystemMessageFilter); +}; + +} // namespace chrome + +#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/common/chrome_utility_messages.h b/chromium_src/chrome/common/chrome_utility_messages.h new file mode 100644 index 000000000000..1de0756c0d58 --- /dev/null +++ b/chromium_src/chrome/common/chrome_utility_messages.h @@ -0,0 +1,169 @@ +// Copyright (c) 2012 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 file. + +// Multiply-included message file, so no include guard. + +#if defined(OS_WIN) +#include +#endif // defined(OS_WIN) + +#include +#include + +#include "base/files/file_path.h" +#include "base/strings/string16.h" +#include "base/tuple.h" +#include "base/values.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_platform_file.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/ipc/gfx_param_traits.h" + +// Singly-included section for typedefs. +#ifndef CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ +#define CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ + +#if defined(OS_WIN) +// A vector of filters, each being a Tuple containing a display string (i.e. +// "Text Files") and a filter pattern (i.e. "*.txt"). +typedef std::vector> + GetOpenFileNameFilter; +#endif // OS_WIN + +#endif // CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ + +#define IPC_MESSAGE_START ChromeUtilityMsgStart + + +#if defined(OS_WIN) +IPC_STRUCT_BEGIN(ChromeUtilityMsg_GetSaveFileName_Params) + IPC_STRUCT_MEMBER(HWND, owner) + IPC_STRUCT_MEMBER(DWORD, flags) + IPC_STRUCT_MEMBER(GetOpenFileNameFilter, filters) + IPC_STRUCT_MEMBER(int, one_based_filter_index) + IPC_STRUCT_MEMBER(base::FilePath, suggested_filename) + IPC_STRUCT_MEMBER(base::FilePath, initial_directory) + IPC_STRUCT_MEMBER(base::string16, default_extension) +IPC_STRUCT_END() +#endif // OS_WIN + +//------------------------------------------------------------------------------ +// Utility process messages: +// These are messages from the browser to the utility process. + +// Tell the utility process to parse a JSON string into a Value object. +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_ParseJSON, + std::string /* JSON to parse */) + +// Tell the utility process to decode the given image data. +IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_DecodeImage, + std::vector /* encoded image contents */, + bool /* shrink image if needed for IPC msg limit */) + +// Tell the utility process to decode the given JPEG image data with a robust +// libjpeg codec. +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_RobustJPEGDecodeImage, + std::vector) // encoded image contents + +// Tell the utility process to patch the given |input_file| using |patch_file| +// and place the output in |output_file|. The patch should use the bsdiff +// algorithm (Courgette's version). +IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileBsdiff, + base::FilePath /* input_file */, + base::FilePath /* patch_file */, + base::FilePath /* output_file */) + +// Tell the utility process to patch the given |input_file| using |patch_file| +// and place the output in |output_file|. The patch should use the Courgette +// algorithm. +IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileCourgette, + base::FilePath /* input_file */, + base::FilePath /* patch_file */, + base::FilePath /* output_file */) + + +// Requests the utility process to respond with a +// ChromeUtilityHostMsg_ProcessStarted message once it has started. This may +// be used if the host process needs a handle to the running utility process. +IPC_MESSAGE_CONTROL0(ChromeUtilityMsg_StartupPing) + + +#if defined(OS_WIN) +// Invokes ui::base::win::OpenFileViaShell from the utility process. +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_OpenFileViaShell, + base::FilePath /* full_path */) + +// Invokes ui::base::win::OpenFolderViaShell from the utility process. +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_OpenFolderViaShell, + base::FilePath /* full_path */) + +// Instructs the utility process to invoke GetOpenFileName. |owner| is the +// parent of the modal dialog, |flags| are OFN_* flags. |filter| constrains the +// user's file choices. |initial_directory| and |filename| select the directory +// to be displayed and the file to be initially selected. +// +// Either ChromeUtilityHostMsg_GetOpenFileName_Failed or +// ChromeUtilityHostMsg_GetOpenFileName_Result will be returned when the +// operation completes whether due to error or user action. +IPC_MESSAGE_CONTROL5(ChromeUtilityMsg_GetOpenFileName, + HWND /* owner */, + DWORD /* flags */, + GetOpenFileNameFilter /* filter */, + base::FilePath /* initial_directory */, + base::FilePath /* filename */) +IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_GetSaveFileName, + ChromeUtilityMsg_GetSaveFileName_Params /* params */) +#endif // defined(OS_WIN) + + +//------------------------------------------------------------------------------ +// Utility process host messages: +// These are messages from the utility process to the browser. + +// Reply when the utility process successfully parsed a JSON string. +// +// WARNING: The result can be of any Value subclass type, but we can't easily +// pass indeterminate value types by const object reference with our IPC macros, +// so we put the result Value into a ListValue. Handlers should examine the +// first (and only) element of the ListValue for the actual result. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_ParseJSON_Succeeded, + base::ListValue) + +// Reply when the utility process failed in parsing a JSON string. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_ParseJSON_Failed, + std::string /* error message, if any*/) + +// Reply when the utility process has failed while unpacking and parsing a +// web resource. |error_message| is a user-readable explanation of what +// went wrong. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_UnpackWebResource_Failed, + std::string /* error_message, if any */) + +// Reply when the utility process has succeeded in decoding the image. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_DecodeImage_Succeeded, + SkBitmap) // decoded image + +// Reply when an error occurred decoding the image. +IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_DecodeImage_Failed) + +// Reply when a file has been patched. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_PatchFile_Finished, int /* result */) + + +// Reply when the utility process has started. +IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_ProcessStarted) + + +#if defined(OS_WIN) +IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_GetOpenFileName_Failed) +IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetOpenFileName_Result, + base::FilePath /* directory */, + std::vector /* filenames */) +IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_GetSaveFileName_Failed) +IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetSaveFileName_Result, + base::FilePath /* path */, + int /* one_based_filter_index */) +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_BuildDirectWriteFontCache, + base::FilePath /* cache file path */) +#endif // defined(OS_WIN) diff --git a/chromium_src/chrome/common/print_messages.h b/chromium_src/chrome/common/print_messages.h index 4ca8db82ae3d..4a54546b69d7 100644 --- a/chromium_src/chrome/common/print_messages.h +++ b/chromium_src/chrome/common/print_messages.h @@ -17,6 +17,13 @@ #include "ui/gfx/native_widget_types.h" #include "ui/gfx/geometry/rect.h" +#if defined(OS_WIN) +#include "ipc/ipc_platform_file.h" +#include "printing/backend/print_backend.h" +#include "printing/page_range.h" +#include "printing/pdf_render_settings.h" +#endif + #ifndef CHROME_COMMON_PRINT_MESSAGES_H_ #define CHROME_COMMON_PRINT_MESSAGES_H_ @@ -239,3 +246,31 @@ IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError) // Tell the browser printing failed. IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintingFailed, int /* document cookie */) + + +#if defined(OS_WIN) +// Tell the utility process to start rendering the given PDF into a metafile. +// Utility process would be alive until +// ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop message. +IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles, + IPC::PlatformFileForTransit, /* input_file */ + printing::PdfRenderSettings /* settings */) + +// Requests conversion of the next page. +IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage, + int /* page_number */, + IPC::PlatformFileForTransit /* output_file */) + +// Requests utility process to stop conversion and exit. +IPC_MESSAGE_CONTROL0(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop) + +// Reply when the utility process loaded PDF. |page_count| is 0, if loading +// failed. +IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, + int /* page_count */) + +// Reply when the utility process rendered the PDF page. +IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, + bool /* success */, + float /* scale_factor */) +#endif diff --git a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc new file mode 100644 index 000000000000..dd83b8191c06 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h" + +#include "base/logging.h" +#include "chrome/renderer/pepper/pepper_flash_font_file_host.h" +#include "chrome/renderer/pepper/pepper_flash_fullscreen_host.h" +#include "chrome/renderer/pepper/pepper_flash_menu_host.h" +#include "chrome/renderer/pepper/pepper_flash_renderer_host.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/proxy/ppapi_message_utils.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_permissions.h" + +using ppapi::host::ResourceHost; + +ChromeRendererPepperHostFactory::ChromeRendererPepperHostFactory( + content::RendererPpapiHost* host) + : host_(host) {} + +ChromeRendererPepperHostFactory::~ChromeRendererPepperHostFactory() {} + +scoped_ptr ChromeRendererPepperHostFactory::CreateResourceHost( + ppapi::host::PpapiHost* host, + PP_Resource resource, + PP_Instance instance, + const IPC::Message& message) { + DCHECK_EQ(host_->GetPpapiHost(), host); + + // Make sure the plugin is giving us a valid instance for this resource. + if (!host_->IsValidInstance(instance)) + return scoped_ptr(); + + if (host_->GetPpapiHost()->permissions().HasPermission( + ppapi::PERMISSION_FLASH)) { + switch (message.type()) { + case PpapiHostMsg_Flash_Create::ID: { + return scoped_ptr( + new PepperFlashRendererHost(host_, instance, resource)); + } + case PpapiHostMsg_FlashFullscreen_Create::ID: { + return scoped_ptr( + new PepperFlashFullscreenHost(host_, instance, resource)); + } + case PpapiHostMsg_FlashMenu_Create::ID: { + ppapi::proxy::SerializedFlashMenu serialized_menu; + if (ppapi::UnpackMessage( + message, &serialized_menu)) { + return scoped_ptr(new PepperFlashMenuHost( + host_, instance, resource, serialized_menu)); + } + break; + } + } + } + + // TODO(raymes): PDF also needs access to the FlashFontFileHost currently. + // We should either rename PPB_FlashFont_File to PPB_FontFile_Private or get + // rid of its use in PDF if possible. + if (host_->GetPpapiHost()->permissions().HasPermission( + ppapi::PERMISSION_FLASH) || + host_->GetPpapiHost()->permissions().HasPermission( + ppapi::PERMISSION_PRIVATE)) { + switch (message.type()) { + case PpapiHostMsg_FlashFontFile_Create::ID: { + ppapi::proxy::SerializedFontDescription description; + PP_PrivateFontCharset charset; + if (ppapi::UnpackMessage( + message, &description, &charset)) { + return scoped_ptr(new PepperFlashFontFileHost( + host_, instance, resource, description, charset)); + } + break; + } + } + } + + return scoped_ptr(); +} diff --git a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h new file mode 100644 index 000000000000..13ab2853a356 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h @@ -0,0 +1,35 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_ +#define CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/host/host_factory.h" + +namespace content { +class RendererPpapiHost; +} + +class ChromeRendererPepperHostFactory : public ppapi::host::HostFactory { + public: + explicit ChromeRendererPepperHostFactory(content::RendererPpapiHost* host); + ~ChromeRendererPepperHostFactory() override; + + // HostFactory. + scoped_ptr CreateResourceHost( + ppapi::host::PpapiHost* host, + PP_Resource resource, + PP_Instance instance, + const IPC::Message& message) override; + + private: + // Not owned by this object. + content::RendererPpapiHost* host_; + + DISALLOW_COPY_AND_ASSIGN(ChromeRendererPepperHostFactory); +}; + +#endif // CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.cc new file mode 100644 index 000000000000..305b6ec56c07 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/renderer/pepper/pepper_flash_font_file_host.h" + +#include "build/build_config.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_structs.h" + +#if defined(OS_LINUX) || defined(OS_OPENBSD) +#include "content/public/common/child_process_sandbox_support_linux.h" +#endif + +PepperFlashFontFileHost::PepperFlashFontFileHost( + content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource, + const ppapi::proxy::SerializedFontDescription& description, + PP_PrivateFontCharset charset) + : ResourceHost(host->GetPpapiHost(), instance, resource) { +#if defined(OS_LINUX) || defined(OS_OPENBSD) + fd_.reset(content::MatchFontWithFallback( + description.face.c_str(), + description.weight >= PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD, + description.italic, + charset, + PP_BROWSERFONT_TRUSTED_FAMILY_DEFAULT)); +#endif // defined(OS_LINUX) || defined(OS_OPENBSD) +} + +PepperFlashFontFileHost::~PepperFlashFontFileHost() {} + +int32_t PepperFlashFontFileHost::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperFlashFontFileHost, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFontFile_GetFontTable, + OnGetFontTable) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperFlashFontFileHost::OnGetFontTable( + ppapi::host::HostMessageContext* context, + uint32_t table) { + std::string contents; + int32_t result = PP_ERROR_FAILED; +#if defined(OS_LINUX) || defined(OS_OPENBSD) + int fd = fd_.get(); + if (fd != -1) { + size_t length = 0; + if (content::GetFontTable(fd, table, 0 /* offset */, NULL, &length)) { + contents.resize(length); + uint8_t* contents_ptr = + reinterpret_cast(const_cast(contents.c_str())); + if (content::GetFontTable( + fd, table, 0 /* offset */, contents_ptr, &length)) { + result = PP_OK; + } else { + contents.clear(); + } + } + } +#endif // defined(OS_LINUX) || defined(OS_OPENBSD) + + context->reply_msg = PpapiPluginMsg_FlashFontFile_GetFontTableReply(contents); + return result; +} diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.h b/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.h new file mode 100644 index 000000000000..02bb30f315fd --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.h @@ -0,0 +1,52 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_RENDERER_PEPPER_PEPPER_FLASH_FONT_FILE_HOST_H_ +#define CHROME_RENDERER_PEPPER_PEPPER_FLASH_FONT_FILE_HOST_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/c/private/pp_private_font_charset.h" +#include "ppapi/host/resource_host.h" + +#if defined(OS_LINUX) || defined(OS_OPENBSD) +#include "base/files/scoped_file.h" +#endif + +namespace content { +class RendererPpapiHost; +} + +namespace ppapi { +namespace proxy { +struct SerializedFontDescription; +} +} + +class PepperFlashFontFileHost : public ppapi::host::ResourceHost { + public: + PepperFlashFontFileHost( + content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource, + const ppapi::proxy::SerializedFontDescription& description, + PP_PrivateFontCharset charset); + ~PepperFlashFontFileHost() override; + + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + private: + int32_t OnGetFontTable(ppapi::host::HostMessageContext* context, + uint32_t table); + +#if defined(OS_LINUX) || defined(OS_OPENBSD) + base::ScopedFD fd_; +#endif + + DISALLOW_COPY_AND_ASSIGN(PepperFlashFontFileHost); +}; + +#endif // CHROME_RENDERER_PEPPER_PEPPER_FLASH_FONT_FILE_HOST_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc new file mode 100644 index 000000000000..d590cde3a4a5 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc @@ -0,0 +1,43 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/renderer/pepper/pepper_flash_fullscreen_host.h" + +#include "content/public/renderer/pepper_plugin_instance.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" + +PepperFlashFullscreenHost::PepperFlashFullscreenHost( + content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource) + : ResourceHost(host->GetPpapiHost(), instance, resource), + renderer_ppapi_host_(host) {} + +PepperFlashFullscreenHost::~PepperFlashFullscreenHost() {} + +int32_t PepperFlashFullscreenHost::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperFlashFullscreenHost, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_FlashFullscreen_SetFullscreen, + OnSetFullscreen) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperFlashFullscreenHost::OnSetFullscreen( + ppapi::host::HostMessageContext* context, + bool fullscreen) { + content::PepperPluginInstance* plugin_instance = + renderer_ppapi_host_->GetPluginInstance(pp_instance()); + if (plugin_instance && plugin_instance->FlashSetFullscreen(fullscreen, true)) + return PP_OK; + return PP_ERROR_FAILED; +} diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.h b/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.h new file mode 100644 index 000000000000..3550ea136631 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_RENDERER_PEPPER_PEPPER_FLASH_FULLSCREEN_HOST_H_ +#define CHROME_RENDERER_PEPPER_PEPPER_FLASH_FULLSCREEN_HOST_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/host/resource_host.h" + +namespace content { +class RendererPpapiHost; +} + +class PepperFlashFullscreenHost : public ppapi::host::ResourceHost { + public: + PepperFlashFullscreenHost(content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource); + ~PepperFlashFullscreenHost() override; + + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + private: + int32_t OnSetFullscreen(ppapi::host::HostMessageContext* context, + bool fullscreen); + + // Non-owning pointer. + content::RendererPpapiHost* renderer_ppapi_host_; + + DISALLOW_COPY_AND_ASSIGN(PepperFlashFullscreenHost); +}; + +#endif // CHROME_RENDERER_PEPPER_PEPPER_FLASH_FULLSCREEN_HOST_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.cc new file mode 100644 index 000000000000..3b7a438f7220 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.cc @@ -0,0 +1,202 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/renderer/pepper/pepper_flash_menu_host.h" + +#include "base/strings/utf_string_conversions.h" +#include "content/public/common/context_menu_params.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/private/ppb_flash_menu.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_flash_menu.h" +#include "ui/gfx/geometry/point.h" + +namespace { + +// Maximum depth of submenus allowed (e.g., 1 indicates that submenus are +// allowed, but not sub-submenus). +const size_t kMaxMenuDepth = 2; + +// Maximum number of entries in any single menu (including separators). +const size_t kMaxMenuEntries = 50; + +// Maximum total number of entries in the |menu_id_map| (see below). +// (Limit to 500 real entries; reserve the 0 action as an invalid entry.) +const size_t kMaxMenuIdMapEntries = 501; + +// Converts menu data from one form to another. +// - |depth| is the current nested depth (call it starting with 0). +// - |menu_id_map| is such that |menu_id_map[output_item.action] == +// input_item.id| (where |action| is what a |MenuItem| has, |id| is what a +// |PP_Flash_MenuItem| has). +bool ConvertMenuData(const PP_Flash_Menu* in_menu, + size_t depth, + std::vector* out_menu, + std::vector* menu_id_map) { + if (depth > kMaxMenuDepth || !in_menu) + return false; + + // Clear the output, just in case. + out_menu->clear(); + + if (!in_menu->count) + return true; // Nothing else to do. + + if (!in_menu->items || in_menu->count > kMaxMenuEntries) + return false; + for (uint32_t i = 0; i < in_menu->count; i++) { + content::MenuItem item; + + PP_Flash_MenuItem_Type type = in_menu->items[i].type; + switch (type) { + case PP_FLASH_MENUITEM_TYPE_NORMAL: + item.type = content::MenuItem::OPTION; + break; + case PP_FLASH_MENUITEM_TYPE_CHECKBOX: + item.type = content::MenuItem::CHECKABLE_OPTION; + break; + case PP_FLASH_MENUITEM_TYPE_SEPARATOR: + item.type = content::MenuItem::SEPARATOR; + break; + case PP_FLASH_MENUITEM_TYPE_SUBMENU: + item.type = content::MenuItem::SUBMENU; + break; + default: + return false; + } + if (in_menu->items[i].name) + item.label = base::UTF8ToUTF16(in_menu->items[i].name); + if (menu_id_map->size() >= kMaxMenuIdMapEntries) + return false; + item.action = static_cast(menu_id_map->size()); + // This sets |(*menu_id_map)[item.action] = in_menu->items[i].id|. + menu_id_map->push_back(in_menu->items[i].id); + item.enabled = PP_ToBool(in_menu->items[i].enabled); + item.checked = PP_ToBool(in_menu->items[i].checked); + if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) { + if (!ConvertMenuData( + in_menu->items[i].submenu, depth + 1, &item.submenu, menu_id_map)) + return false; + } + + out_menu->push_back(item); + } + + return true; +} + +} // namespace + +PepperFlashMenuHost::PepperFlashMenuHost( + content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource, + const ppapi::proxy::SerializedFlashMenu& serial_menu) + : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource), + renderer_ppapi_host_(host), + showing_context_menu_(false), + context_menu_request_id_(0), + has_saved_context_menu_action_(false), + saved_context_menu_action_(0) { + menu_id_map_.push_back(0); // Reserve |menu_id_map_[0]|. + if (!ConvertMenuData(serial_menu.pp_menu(), 0, &menu_data_, &menu_id_map_)) { + menu_data_.clear(); + menu_id_map_.clear(); + } +} + +PepperFlashMenuHost::~PepperFlashMenuHost() { + if (showing_context_menu_) { + content::RenderFrame* render_frame = + renderer_ppapi_host_->GetRenderFrameForInstance(pp_instance()); + if (render_frame) + render_frame->CancelContextMenu(context_menu_request_id_); + } +} + +int32_t PepperFlashMenuHost::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperFlashMenuHost, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashMenu_Show, + OnHostMsgShow) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperFlashMenuHost::OnHostMsgShow( + ppapi::host::HostMessageContext* context, + const PP_Point& location) { + // Note that all early returns must do a SendMenuReply. The sync result for + // this message isn't used, so to forward the error to the plugin, we need to + // additionally call SendMenuReply explicitly. + if (menu_data_.empty()) { + SendMenuReply(PP_ERROR_FAILED, -1); + return PP_ERROR_FAILED; + } + if (showing_context_menu_) { + SendMenuReply(PP_ERROR_INPROGRESS, -1); + return PP_ERROR_INPROGRESS; + } + + content::RenderFrame* render_frame = + renderer_ppapi_host_->GetRenderFrameForInstance(pp_instance()); + + content::ContextMenuParams params; + params.x = location.x; + params.y = location.y; + params.custom_context.is_pepper_menu = true; + params.custom_context.render_widget_id = + renderer_ppapi_host_->GetRoutingIDForWidget(pp_instance()); + params.custom_items = menu_data_; + + // Transform the position to be in render frame's coordinates. + gfx::Point render_frame_pt = renderer_ppapi_host_->PluginPointToRenderFrame( + pp_instance(), gfx::Point(location.x, location.y)); + params.x = render_frame_pt.x(); + params.y = render_frame_pt.y(); + + showing_context_menu_ = true; + context_menu_request_id_ = render_frame->ShowContextMenu(this, params); + + // Note: the show message is sync so this OK is for the sync reply which we + // don't actually use (see the comment in the resource file for this). The + // async message containing the context menu action will be sent in the + // future. + return PP_OK; +} + +void PepperFlashMenuHost::OnMenuAction(int request_id, unsigned action) { + // Just save the action. + DCHECK(!has_saved_context_menu_action_); + has_saved_context_menu_action_ = true; + saved_context_menu_action_ = action; +} + +void PepperFlashMenuHost::OnMenuClosed(int request_id) { + if (has_saved_context_menu_action_ && + saved_context_menu_action_ < menu_id_map_.size()) { + SendMenuReply(PP_OK, menu_id_map_[saved_context_menu_action_]); + has_saved_context_menu_action_ = false; + saved_context_menu_action_ = 0; + } else { + SendMenuReply(PP_ERROR_USERCANCEL, -1); + } + + showing_context_menu_ = false; + context_menu_request_id_ = 0; +} + +void PepperFlashMenuHost::SendMenuReply(int32_t result, int action) { + ppapi::host::ReplyMessageContext reply_context( + ppapi::proxy::ResourceMessageReplyParams(pp_resource(), 0), + NULL, + MSG_ROUTING_NONE); + reply_context.params.set_result(result); + host()->SendReply(reply_context, PpapiPluginMsg_FlashMenu_ShowReply(action)); +} diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.h b/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.h new file mode 100644 index 000000000000..3aa730a6afc3 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.h @@ -0,0 +1,69 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_RENDERER_PEPPER_PEPPER_FLASH_MENU_HOST_H_ +#define CHROME_RENDERER_PEPPER_PEPPER_FLASH_MENU_HOST_H_ + +#include + +#include "base/compiler_specific.h" +#include "content/public/renderer/context_menu_client.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/resource_host.h" + +namespace content { +class RendererPpapiHost; +struct MenuItem; +} + +namespace ppapi { +namespace proxy { +class SerializedFlashMenu; +} +} + +class PepperFlashMenuHost : public ppapi::host::ResourceHost, + public content::ContextMenuClient { + public: + PepperFlashMenuHost(content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource, + const ppapi::proxy::SerializedFlashMenu& serial_menu); + ~PepperFlashMenuHost() override; + + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + private: + int32_t OnHostMsgShow(ppapi::host::HostMessageContext* context, + const PP_Point& location); + + // ContextMenuClient implementation. + void OnMenuAction(int request_id, unsigned action) override; + void OnMenuClosed(int request_id) override; + + void SendMenuReply(int32_t result, int action); + + content::RendererPpapiHost* renderer_ppapi_host_; + + bool showing_context_menu_; + int context_menu_request_id_; + + std::vector menu_data_; + + // We send |MenuItem|s, which have an |unsigned| "action" field instead of + // an |int32_t| ID. (CONTENT also limits the range of valid values for + // actions.) This maps actions to IDs. + std::vector menu_id_map_; + + // Used to send a single context menu "completion" upon menu close. + bool has_saved_context_menu_action_; + unsigned saved_context_menu_action_; + + DISALLOW_COPY_AND_ASSIGN(PepperFlashMenuHost); +}; + +#endif // CHROME_RENDERER_PEPPER_PEPPER_FLASH_MENU_HOST_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc new file mode 100644 index 000000000000..fe5e28ebbeb8 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc @@ -0,0 +1,373 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/renderer/pepper/pepper_flash_renderer_host.h" + +#include +#include + +#include "base/lazy_instance.h" +#include "base/metrics/histogram.h" +#include "base/strings/string_util.h" +#include "content/public/renderer/pepper_plugin_instance.h" +#include "content/public/renderer/render_thread.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ipc/ipc_message_macros.h" +#include "net/http/http_util.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/trusted/ppb_browser_font_trusted.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_image_data_api.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPoint.h" +#include "third_party/skia/include/core/SkTemplates.h" +#include "third_party/skia/include/core/SkTypeface.h" +#include "ui/gfx/geometry/rect.h" +#include "url/gurl.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_ImageData_API; + +namespace { + +// Some non-simple HTTP request headers that Flash may set. +// (Please see http://www.w3.org/TR/cors/#simple-header for the definition of +// simple headers.) +// +// The list and the enum defined below are used to collect data about request +// headers used in PPB_Flash.Navigate() calls, in order to understand the impact +// of rejecting PPB_Flash.Navigate() requests with non-simple headers. +// +// TODO(yzshen): We should be able to remove the histogram recording code once +// we get the answer. +const char* const kRejectedHttpRequestHeaders[] = { + "authorization", // + "cache-control", // + "content-encoding", // + "content-md5", // + "content-type", // If the media type is not one of those covered by the + // simple header definition. + "expires", // + "from", // + "if-match", // + "if-none-match", // + "if-range", // + "if-unmodified-since", // + "pragma", // + "referer" // +}; + +// Please note that new entries should be added right above +// FLASH_NAVIGATE_USAGE_ENUM_COUNT, and existing entries shouldn't be re-ordered +// or removed, since this ordering is used in a histogram. +enum FlashNavigateUsage { + // This section must be in the same order as kRejectedHttpRequestHeaders. + REJECT_AUTHORIZATION = 0, + REJECT_CACHE_CONTROL, + REJECT_CONTENT_ENCODING, + REJECT_CONTENT_MD5, + REJECT_CONTENT_TYPE, + REJECT_EXPIRES, + REJECT_FROM, + REJECT_IF_MATCH, + REJECT_IF_NONE_MATCH, + REJECT_IF_RANGE, + REJECT_IF_UNMODIFIED_SINCE, + REJECT_PRAGMA, + REJECT_REFERER, + + // The navigate request is rejected because of headers not listed above + // (e.g., custom headers). + REJECT_OTHER_HEADERS, + + // Total number of rejected navigate requests. + TOTAL_REJECTED_NAVIGATE_REQUESTS, + + // Total number of navigate requests. + TOTAL_NAVIGATE_REQUESTS, + FLASH_NAVIGATE_USAGE_ENUM_COUNT +}; + +static base::LazyInstance > + g_rejected_headers = LAZY_INSTANCE_INITIALIZER; + +bool IsSimpleHeader(const std::string& lower_case_header_name, + const std::string& header_value) { + if (lower_case_header_name == "accept" || + lower_case_header_name == "accept-language" || + lower_case_header_name == "content-language") { + return true; + } + + if (lower_case_header_name == "content-type") { + std::string lower_case_mime_type; + std::string lower_case_charset; + bool had_charset = false; + net::HttpUtil::ParseContentType(header_value, + &lower_case_mime_type, + &lower_case_charset, + &had_charset, + NULL); + return lower_case_mime_type == "application/x-www-form-urlencoded" || + lower_case_mime_type == "multipart/form-data" || + lower_case_mime_type == "text/plain"; + } + + return false; +} + +void RecordFlashNavigateUsage(FlashNavigateUsage usage) { + DCHECK_NE(FLASH_NAVIGATE_USAGE_ENUM_COUNT, usage); + UMA_HISTOGRAM_ENUMERATION( + "Plugin.FlashNavigateUsage", usage, FLASH_NAVIGATE_USAGE_ENUM_COUNT); +} + +} // namespace + +PepperFlashRendererHost::PepperFlashRendererHost( + content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource) + : ResourceHost(host->GetPpapiHost(), instance, resource), + host_(host), + weak_factory_(this) {} + +PepperFlashRendererHost::~PepperFlashRendererHost() { + // This object may be destroyed in the middle of a sync message. If that is + // the case, make sure we respond to all the pending navigate calls. + std::vector::reverse_iterator it; + for (it = navigate_replies_.rbegin(); it != navigate_replies_.rend(); ++it) + SendReply(*it, IPC::Message()); +} + +int32_t PepperFlashRendererHost::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperFlashRendererHost, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_GetProxyForURL, + OnGetProxyForURL) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_SetInstanceAlwaysOnTop, + OnSetInstanceAlwaysOnTop) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_DrawGlyphs, + OnDrawGlyphs) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_Navigate, OnNavigate) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_IsRectTopmost, + OnIsRectTopmost) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperFlashRendererHost::OnGetProxyForURL( + ppapi::host::HostMessageContext* host_context, + const std::string& url) { + GURL gurl(url); + if (!gurl.is_valid()) + return PP_ERROR_FAILED; + std::string proxy; + bool result = content::RenderThread::Get()->ResolveProxy(gurl, &proxy); + if (!result) + return PP_ERROR_FAILED; + host_context->reply_msg = PpapiPluginMsg_Flash_GetProxyForURLReply(proxy); + return PP_OK; +} + +int32_t PepperFlashRendererHost::OnSetInstanceAlwaysOnTop( + ppapi::host::HostMessageContext* host_context, + bool on_top) { + content::PepperPluginInstance* plugin_instance = + host_->GetPluginInstance(pp_instance()); + if (plugin_instance) + plugin_instance->SetAlwaysOnTop(on_top); + // Since no reply is sent for this message, it doesn't make sense to return an + // error. + return PP_OK; +} + +int32_t PepperFlashRendererHost::OnDrawGlyphs( + ppapi::host::HostMessageContext* host_context, + ppapi::proxy::PPBFlash_DrawGlyphs_Params params) { + if (params.glyph_indices.size() != params.glyph_advances.size() || + params.glyph_indices.empty()) + return PP_ERROR_FAILED; + + // Set up the typeface. + int style = SkTypeface::kNormal; + if (static_cast(params.font_desc.weight) >= + PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD) + style |= SkTypeface::kBold; + if (params.font_desc.italic) + style |= SkTypeface::kItalic; + skia::RefPtr typeface = skia::AdoptRef(SkTypeface::CreateFromName( + params.font_desc.face.c_str(), static_cast(style))); + if (!typeface) + return PP_ERROR_FAILED; + + EnterResourceNoLock enter( + params.image_data.host_resource(), true); + if (enter.failed()) + return PP_ERROR_FAILED; + + // Set up the canvas. + PPB_ImageData_API* image = static_cast(enter.object()); + SkCanvas* canvas = image->GetCanvas(); + bool needs_unmapping = false; + if (!canvas) { + needs_unmapping = true; + image->Map(); + canvas = image->GetCanvas(); + if (!canvas) + return PP_ERROR_FAILED; // Failure mapping. + } + + SkAutoCanvasRestore acr(canvas, true); + + // Clip is applied in pixels before the transform. + SkRect clip_rect = { + SkIntToScalar(params.clip.point.x), SkIntToScalar(params.clip.point.y), + SkIntToScalar(params.clip.point.x + params.clip.size.width), + SkIntToScalar(params.clip.point.y + params.clip.size.height)}; + canvas->clipRect(clip_rect); + + // Convert & set the matrix. + SkMatrix matrix; + matrix.set(SkMatrix::kMScaleX, SkFloatToScalar(params.transformation[0][0])); + matrix.set(SkMatrix::kMSkewX, SkFloatToScalar(params.transformation[0][1])); + matrix.set(SkMatrix::kMTransX, SkFloatToScalar(params.transformation[0][2])); + matrix.set(SkMatrix::kMSkewY, SkFloatToScalar(params.transformation[1][0])); + matrix.set(SkMatrix::kMScaleY, SkFloatToScalar(params.transformation[1][1])); + matrix.set(SkMatrix::kMTransY, SkFloatToScalar(params.transformation[1][2])); + matrix.set(SkMatrix::kMPersp0, SkFloatToScalar(params.transformation[2][0])); + matrix.set(SkMatrix::kMPersp1, SkFloatToScalar(params.transformation[2][1])); + matrix.set(SkMatrix::kMPersp2, SkFloatToScalar(params.transformation[2][2])); + canvas->concat(matrix); + + SkPaint paint; + paint.setColor(params.color); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + paint.setAntiAlias(true); + paint.setHinting(SkPaint::kFull_Hinting); + paint.setTextSize(SkIntToScalar(params.font_desc.size)); + paint.setTypeface(typeface.get()); // Takes a ref and manages lifetime. + if (params.allow_subpixel_aa) { + paint.setSubpixelText(true); + paint.setLCDRenderText(true); + } + + SkScalar x = SkIntToScalar(params.position.x); + SkScalar y = SkIntToScalar(params.position.y); + + // Build up the skia advances. + size_t glyph_count = params.glyph_indices.size(); + if (glyph_count) { + std::vector storage; + storage.resize(glyph_count); + SkPoint* sk_positions = &storage[0]; + for (uint32_t i = 0; i < glyph_count; i++) { + sk_positions[i].set(x, y); + x += SkFloatToScalar(params.glyph_advances[i].x); + y += SkFloatToScalar(params.glyph_advances[i].y); + } + + canvas->drawPosText( + ¶ms.glyph_indices[0], glyph_count * 2, sk_positions, paint); + } + + if (needs_unmapping) + image->Unmap(); + + return PP_OK; +} + +// CAUTION: This code is subtle because Navigate is a sync call which may +// cause re-entrancy or cause the instance to be destroyed. If the instance +// is destroyed we need to ensure that we respond to all outstanding sync +// messages so that the plugin process does not remain blocked. +int32_t PepperFlashRendererHost::OnNavigate( + ppapi::host::HostMessageContext* host_context, + const ppapi::URLRequestInfoData& data, + const std::string& target, + bool from_user_action) { + // If our PepperPluginInstance is already destroyed, just return a failure. + content::PepperPluginInstance* plugin_instance = + host_->GetPluginInstance(pp_instance()); + if (!plugin_instance) + return PP_ERROR_FAILED; + + std::map& rejected_headers = + g_rejected_headers.Get(); + if (rejected_headers.empty()) { + for (size_t i = 0; i < arraysize(kRejectedHttpRequestHeaders); ++i) + rejected_headers[kRejectedHttpRequestHeaders[i]] = + static_cast(i); + } + + net::HttpUtil::HeadersIterator header_iter( + data.headers.begin(), data.headers.end(), "\n\r"); + bool rejected = false; + while (header_iter.GetNext()) { + std::string lower_case_header_name = + base::StringToLowerASCII(header_iter.name()); + if (!IsSimpleHeader(lower_case_header_name, header_iter.values())) { + rejected = true; + + std::map::const_iterator iter = + rejected_headers.find(lower_case_header_name); + FlashNavigateUsage usage = + iter != rejected_headers.end() ? iter->second : REJECT_OTHER_HEADERS; + RecordFlashNavigateUsage(usage); + } + } + + RecordFlashNavigateUsage(TOTAL_NAVIGATE_REQUESTS); + if (rejected) { + RecordFlashNavigateUsage(TOTAL_REJECTED_NAVIGATE_REQUESTS); + return PP_ERROR_NOACCESS; + } + + // Navigate may call into Javascript (e.g. with a "javascript:" URL), + // or do things like navigate away from the page, either one of which will + // need to re-enter into the plugin. It is safe, because it is essentially + // equivalent to NPN_GetURL, where Flash would expect re-entrancy. + ppapi::proxy::HostDispatcher* host_dispatcher = + ppapi::proxy::HostDispatcher::GetForInstance(pp_instance()); + host_dispatcher->set_allow_plugin_reentrancy(); + + // Grab a weak pointer to ourselves on the stack so we can check if we are + // still alive. + base::WeakPtr weak_ptr = weak_factory_.GetWeakPtr(); + // Keep track of reply contexts in case we are destroyed during a Navigate + // call. Even if we are destroyed, we still need to send these replies to + // unblock the plugin process. + navigate_replies_.push_back(host_context->MakeReplyMessageContext()); + plugin_instance->Navigate(data, target.c_str(), from_user_action); + // This object might have been destroyed by this point. If it is destroyed + // the reply will be sent in the destructor. Otherwise send the reply here. + if (weak_ptr.get()) { + SendReply(navigate_replies_.back(), IPC::Message()); + navigate_replies_.pop_back(); + } + + // Return PP_OK_COMPLETIONPENDING so that no reply is automatically sent. + return PP_OK_COMPLETIONPENDING; +} + +int32_t PepperFlashRendererHost::OnIsRectTopmost( + ppapi::host::HostMessageContext* host_context, + const PP_Rect& rect) { + content::PepperPluginInstance* plugin_instance = + host_->GetPluginInstance(pp_instance()); + if (plugin_instance && + plugin_instance->IsRectTopmost(gfx::Rect( + rect.point.x, rect.point.y, rect.size.width, rect.size.height))) + return PP_OK; + return PP_ERROR_FAILED; +} diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.h b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.h new file mode 100644 index 000000000000..de22f46045a5 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.h @@ -0,0 +1,69 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_RENDERER_PEPPER_PEPPER_FLASH_RENDERER_HOST_H_ +#define CHROME_RENDERER_PEPPER_PEPPER_FLASH_RENDERER_HOST_H_ + +#include +#include + +#include "base/basictypes.h" +#include "base/memory/weak_ptr.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/resource_host.h" + +struct PP_Rect; + +namespace ppapi { +struct URLRequestInfoData; +} + +namespace ppapi { +namespace proxy { +struct PPBFlash_DrawGlyphs_Params; +} +} + +namespace content { +class RendererPpapiHost; +} + +class PepperFlashRendererHost : public ppapi::host::ResourceHost { + public: + PepperFlashRendererHost(content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource); + ~PepperFlashRendererHost() override; + + // ppapi::host::ResourceHost override. + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + private: + int32_t OnGetProxyForURL(ppapi::host::HostMessageContext* host_context, + const std::string& url); + int32_t OnSetInstanceAlwaysOnTop( + ppapi::host::HostMessageContext* host_context, + bool on_top); + int32_t OnDrawGlyphs(ppapi::host::HostMessageContext* host_context, + ppapi::proxy::PPBFlash_DrawGlyphs_Params params); + int32_t OnNavigate(ppapi::host::HostMessageContext* host_context, + const ppapi::URLRequestInfoData& data, + const std::string& target, + bool from_user_action); + int32_t OnIsRectTopmost(ppapi::host::HostMessageContext* host_context, + const PP_Rect& rect); + + // A stack of ReplyMessageContexts to track Navigate() calls which have not + // yet been replied to. + std::vector navigate_replies_; + + content::RendererPpapiHost* host_; + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PepperFlashRendererHost); +}; + +#endif // CHROME_RENDERER_PEPPER_PEPPER_FLASH_RENDERER_HOST_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_helper.cc b/chromium_src/chrome/renderer/pepper/pepper_helper.cc new file mode 100644 index 000000000000..a610a30dfff5 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_helper.cc @@ -0,0 +1,26 @@ +// Copyright (c) 2012 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 file. + +#include "chrome/renderer/pepper/pepper_helper.h" + +#include "chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h" +#include "chrome/renderer/pepper/pepper_shared_memory_message_filter.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ppapi/host/ppapi_host.h" + +PepperHelper::PepperHelper(content::RenderFrame* render_frame) + : RenderFrameObserver(render_frame) {} + +PepperHelper::~PepperHelper() {} + +void PepperHelper::DidCreatePepperPlugin(content::RendererPpapiHost* host) { + // TODO(brettw) figure out how to hook up the host factory. It needs some + // kind of filter-like system to allow dynamic additions. + host->GetPpapiHost()->AddHostFactoryFilter( + scoped_ptr( + new ChromeRendererPepperHostFactory(host))); + host->GetPpapiHost()->AddInstanceMessageFilter( + scoped_ptr( + new PepperSharedMemoryMessageFilter(host))); +} diff --git a/chromium_src/chrome/renderer/pepper/pepper_helper.h b/chromium_src/chrome/renderer/pepper/pepper_helper.h new file mode 100644 index 000000000000..b3e850b2481b --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_helper.h @@ -0,0 +1,25 @@ +// Copyright (c) 2012 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 file. + +#ifndef CHROME_RENDERER_PEPPER_PEPPER_HELPER_H_ +#define CHROME_RENDERER_PEPPER_PEPPER_HELPER_H_ + +#include "base/compiler_specific.h" +#include "content/public/renderer/render_frame_observer.h" + +// This class listens for Pepper creation events from the RenderFrame and +// attaches the parts required for Chrome-specific plugin support. +class PepperHelper : public content::RenderFrameObserver { + public: + explicit PepperHelper(content::RenderFrame* render_frame); + ~PepperHelper() override; + + // RenderFrameObserver. + void DidCreatePepperPlugin(content::RendererPpapiHost* host) override; + + private: + DISALLOW_COPY_AND_ASSIGN(PepperHelper); +}; + +#endif // CHROME_RENDERER_PEPPER_PEPPER_HELPER_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc b/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc new file mode 100644 index 000000000000..e01aea741fc8 --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2013 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 file. + +#include "chrome/renderer/pepper/pepper_shared_memory_message_filter.h" + +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" +#include "base/process/process_handle.h" +#include "content/public/common/content_client.h" +#include "content/public/renderer/pepper_plugin_instance.h" +#include "content/public/renderer/render_thread.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/var_tracker.h" + +PepperSharedMemoryMessageFilter::PepperSharedMemoryMessageFilter( + content::RendererPpapiHost* host) + : InstanceMessageFilter(host->GetPpapiHost()), host_(host) {} + +PepperSharedMemoryMessageFilter::~PepperSharedMemoryMessageFilter() {} + +bool PepperSharedMemoryMessageFilter::OnInstanceMessageReceived( + const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PepperSharedMemoryMessageFilter, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_SharedMemory_CreateSharedMemory, + OnHostMsgCreateSharedMemory) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool PepperSharedMemoryMessageFilter::Send(IPC::Message* msg) { + return host_->GetPpapiHost()->Send(msg); +} + +void PepperSharedMemoryMessageFilter::OnHostMsgCreateSharedMemory( + PP_Instance instance, + uint32_t size, + int* host_handle_id, + ppapi::proxy::SerializedHandle* plugin_handle) { + plugin_handle->set_null_shmem(); + *host_handle_id = -1; + scoped_ptr shm(content::RenderThread::Get() + ->HostAllocateSharedMemoryBuffer(size) + .Pass()); + if (!shm.get()) + return; + + base::SharedMemoryHandle host_shm_handle; + shm->ShareToProcess(base::GetCurrentProcessHandle(), &host_shm_handle); + *host_handle_id = + content::PepperPluginInstance::Get(instance) + ->GetVarTracker() + ->TrackSharedMemoryHandle(instance, host_shm_handle, size); + + base::PlatformFile host_handle = +#if defined(OS_WIN) + host_shm_handle; +#elif defined(OS_POSIX) + host_shm_handle.fd; +#else +#error Not implemented. +#endif + // We set auto_close to false since we need our file descriptor to + // actually be duplicated on linux. The shared memory destructor will + // close the original handle for us. + plugin_handle->set_shmem(host_->ShareHandleWithRemote(host_handle, false), + size); +} diff --git a/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.h b/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.h new file mode 100644 index 000000000000..d7e0934cd6ec --- /dev/null +++ b/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.h @@ -0,0 +1,48 @@ +// Copyright (c) 2013 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 file. + +#ifndef CHROME_RENDERER_PEPPER_PEPPER_SHARED_MEMORY_MESSAGE_FILTER_H_ +#define CHROME_RENDERER_PEPPER_PEPPER_SHARED_MEMORY_MESSAGE_FILTER_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/host/instance_message_filter.h" + +namespace content { +class RendererPpapiHost; +} + +namespace ppapi { +namespace proxy { +class SerializedHandle; +} +} + +// Implements the backend for shared memory messages from a plugin process. +class PepperSharedMemoryMessageFilter + : public ppapi::host::InstanceMessageFilter { + public: + explicit PepperSharedMemoryMessageFilter(content::RendererPpapiHost* host); + ~PepperSharedMemoryMessageFilter() override; + + // InstanceMessageFilter: + bool OnInstanceMessageReceived(const IPC::Message& msg) override; + + bool Send(IPC::Message* msg); + + private: + // Message handlers. + void OnHostMsgCreateSharedMemory( + PP_Instance instance, + uint32_t size, + int* host_shm_handle_id, + ppapi::proxy::SerializedHandle* plugin_shm_handle); + + content::RendererPpapiHost* host_; + + DISALLOW_COPY_AND_ASSIGN(PepperSharedMemoryMessageFilter); +}; + +#endif // CHROME_RENDERER_PEPPER_PEPPER_SHARED_MEMORY_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc index 46718a0c546a..60158f6c1d4c 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc @@ -425,8 +425,10 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient, virtual void didStopLoading(); // blink::WebFrameClient override: - virtual blink::WebFrame* createChildFrame(blink::WebLocalFrame* parent, - const blink::WebString& name); + virtual blink::WebFrame* createChildFrame( + blink::WebLocalFrame* parent, + const blink::WebString& name, + blink::WebSandboxFlags sandboxFlags); virtual void frameDetached(blink::WebFrame* frame); private: @@ -571,7 +573,8 @@ void PrepareFrameAndViewForPrint::didStopLoading() { blink::WebFrame* PrepareFrameAndViewForPrint::createChildFrame( blink::WebLocalFrame* parent, - const blink::WebString& name) { + const blink::WebString& name, + blink::WebSandboxFlags sandboxFlags) { blink::WebFrame* frame = blink::WebLocalFrame::create(this); parent->appendChild(frame); return frame; diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc index 1fb3b260e0be..38bd9114d244 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc @@ -12,7 +12,6 @@ #include "printing/page_size_margins.h" #include "printing/pdf_metafile_skia.h" #include "skia/ext/platform_device.h" -#include "skia/ext/vector_canvas.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm b/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm index e2ad3da5bc85..93fd06464b37 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm @@ -13,7 +13,6 @@ #include "printing/metafile_skia_wrapper.h" #include "printing/page_size_margins.h" #include "skia/ext/platform_device.h" -#include "skia/ext/vector_canvas.h" #include "third_party/WebKit/public/platform/WebCanvas.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc index c4bd9648905b..f98ee5097cca 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc @@ -14,7 +14,6 @@ #include "printing/pdf_metafile_skia.h" #include "printing/units.h" #include "skia/ext/platform_device.h" -#include "skia/ext/vector_canvas.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" diff --git a/chromium_src/chrome/utility/printing_handler.cc b/chromium_src/chrome/utility/printing_handler.cc new file mode 100644 index 000000000000..db6d9533cf51 --- /dev/null +++ b/chromium_src/chrome/utility/printing_handler.cc @@ -0,0 +1,144 @@ +// 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 file. + +#include "chrome/utility/printing_handler.h" + +#include "base/files/file_util.h" +#include "base/lazy_instance.h" +#include "base/path_service.h" +#include "base/scoped_native_library.h" +#include "chrome/common/print_messages.h" +#include "content/public/utility/utility_thread.h" +#include "pdf/pdf.h" +#include "printing/page_range.h" +#include "printing/pdf_render_settings.h" + +#if defined(OS_WIN) +#include "printing/emf_win.h" +#include "ui/gfx/gdi_util.h" +#endif + + +namespace { + +bool Send(IPC::Message* message) { + return content::UtilityThread::Get()->Send(message); +} + +void ReleaseProcessIfNeeded() { + content::UtilityThread::Get()->ReleaseProcessIfNeeded(); +} + +} // namespace + +PrintingHandler::PrintingHandler() {} + +PrintingHandler::~PrintingHandler() {} + +bool PrintingHandler::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PrintingHandler, message) +#if defined(OS_WIN) + IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles, + OnRenderPDFPagesToMetafile) + IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage, + OnRenderPDFPagesToMetafileGetPage) + IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop, + OnRenderPDFPagesToMetafileStop) +#endif // OS_WIN + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +#if defined(OS_WIN) +void PrintingHandler::OnRenderPDFPagesToMetafile( + IPC::PlatformFileForTransit pdf_transit, + const printing::PdfRenderSettings& settings) { + pdf_rendering_settings_ = settings; + base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit); + int page_count = LoadPDF(pdf_file.Pass()); + //int page_count = 1; + Send( + new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount(page_count)); +} + +void PrintingHandler::OnRenderPDFPagesToMetafileGetPage( + int page_number, + IPC::PlatformFileForTransit output_file) { + base::File emf_file = IPC::PlatformFileForTransitToFile(output_file); + float scale_factor = 1.0f; + bool success = + RenderPdfPageToMetafile(page_number, emf_file.Pass(), &scale_factor); + Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone( + success, scale_factor)); +} + +void PrintingHandler::OnRenderPDFPagesToMetafileStop() { + ReleaseProcessIfNeeded(); +} + +int PrintingHandler::LoadPDF(base::File pdf_file) { + int64 length64 = pdf_file.GetLength(); + if (length64 <= 0 || length64 > std::numeric_limits::max()) + return 0; + int length = static_cast(length64); + + pdf_data_.resize(length); + if (length != pdf_file.Read(0, pdf_data_.data(), pdf_data_.size())) + return 0; + + int total_page_count = 0; + if (!chrome_pdf::GetPDFDocInfo( + &pdf_data_.front(), pdf_data_.size(), &total_page_count, NULL)) { + return 0; + } + return total_page_count; +} + +bool PrintingHandler::RenderPdfPageToMetafile(int page_number, + base::File output_file, + float* scale_factor) { + printing::Emf metafile; + metafile.Init(); + + // We need to scale down DC to fit an entire page into DC available area. + // Current metafile is based on screen DC and have current screen size. + // Writing outside of those boundaries will result in the cut-off output. + // On metafiles (this is the case here), scaling down will still record + // original coordinates and we'll be able to print in full resolution. + // Before playback we'll need to counter the scaling up that will happen + // in the service (print_system_win.cc). + *scale_factor = + gfx::CalculatePageScale(metafile.context(), + pdf_rendering_settings_.area().right(), + pdf_rendering_settings_.area().bottom()); + gfx::ScaleDC(metafile.context(), *scale_factor); + + // The underlying metafile is of type Emf and ignores the arguments passed + // to StartPage. + metafile.StartPage(gfx::Size(), gfx::Rect(), 1); + if (!chrome_pdf::RenderPDFPageToDC( + &pdf_data_.front(), + pdf_data_.size(), + page_number, + metafile.context(), + pdf_rendering_settings_.dpi(), + pdf_rendering_settings_.area().x(), + pdf_rendering_settings_.area().y(), + pdf_rendering_settings_.area().width(), + pdf_rendering_settings_.area().height(), + true, + false, + true, + true, + pdf_rendering_settings_.autorotate())) { + return false; + } + metafile.FinishPage(); + metafile.FinishDocument(); + return metafile.SaveTo(&output_file); +} + +#endif // OS_WIN diff --git a/chromium_src/chrome/utility/printing_handler.h b/chromium_src/chrome/utility/printing_handler.h new file mode 100644 index 000000000000..b1f09acb9cc9 --- /dev/null +++ b/chromium_src/chrome/utility/printing_handler.h @@ -0,0 +1,59 @@ +// 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 file. + +#ifndef CHROME_UTILITY_PRINTING_HANDLER_H_ +#define CHROME_UTILITY_PRINTING_HANDLER_H_ + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "chrome/utility/utility_message_handler.h" +#include "ipc/ipc_platform_file.h" +#include "printing/pdf_render_settings.h" + +#if !defined(ENABLE_PRINT_PREVIEW) && !defined(OS_WIN) +#error "Windows or full printing must be enabled" +#endif + +namespace printing { +class PdfRenderSettings; +struct PwgRasterSettings; +struct PageRange; +} + +// Dispatches IPCs for printing. +class PrintingHandler : public UtilityMessageHandler { + public: + PrintingHandler(); + ~PrintingHandler() override; + + // IPC::Listener: + bool OnMessageReceived(const IPC::Message& message) override; + + private: + // IPC message handlers. +#if defined(OS_WIN) + void OnRenderPDFPagesToMetafile(IPC::PlatformFileForTransit pdf_transit, + const printing::PdfRenderSettings& settings); + void OnRenderPDFPagesToMetafileGetPage( + int page_number, + IPC::PlatformFileForTransit output_file); + void OnRenderPDFPagesToMetafileStop(); +#endif // OS_WIN + +#if defined(OS_WIN) + int LoadPDF(base::File pdf_file); + bool RenderPdfPageToMetafile(int page_number, + base::File output_file, + float* scale_factor); +#endif // OS_WIN + +#if defined(OS_WIN) + std::vector pdf_data_; + printing::PdfRenderSettings pdf_rendering_settings_; +#endif + + DISALLOW_COPY_AND_ASSIGN(PrintingHandler); +}; + +#endif // CHROME_UTILITY_PRINTING_HANDLER_H_ diff --git a/chromium_src/chrome/utility/utility_message_handler.h b/chromium_src/chrome/utility/utility_message_handler.h new file mode 100644 index 000000000000..3ccff1a0fbed --- /dev/null +++ b/chromium_src/chrome/utility/utility_message_handler.h @@ -0,0 +1,21 @@ +// Copyright 2013 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 file. + +#ifndef CHROME_UTILITY_UTILITY_MESSAGE_HANDLER_H_ +#define CHROME_UTILITY_UTILITY_MESSAGE_HANDLER_H_ + +namespace IPC { +class Message; +} + +class UtilityMessageHandler { + public: + virtual ~UtilityMessageHandler() {} + + // Called when a message is received. Returns true iff the message was + // handled. + virtual bool OnMessageReceived(const IPC::Message& message) = 0; +}; + +#endif // CHROME_UTILITY_UTILITY_MESSAGE_HANDLER_H_ diff --git a/common.gypi b/common.gypi index 4ae5e9e77c00..c6f3320c0a5b 100644 --- a/common.gypi +++ b/common.gypi @@ -115,28 +115,29 @@ 'conditions': [ ['target_arch=="ia32"', { 'reference_symbols': [ - '_u_errorName_52', - '_ubidi_setPara_52', - '_ucsdet_getName_52', - '_ulocdata_close_52', - '_uregex_matches_52', - '_uscript_getCode_52', - '_usearch_setPattern_52', - '?createInstance@Transliterator@icu_52@@SAPAV12@ABVUnicodeString@2@W4UTransDirection@@AAW4UErrorCode@@@Z', - '?nameToUnicodeUTF8@IDNA@icu_52@@UBEXABVStringPiece@2@AAVByteSink@2@AAVIDNAInfo@2@AAW4UErrorCode@@@Z', - '?kLineOffsetNotFound@Function@v8@@2HB', + '_u_errorName_54', + '_ubidi_setPara_54', + '_ucsdet_getName_54', + '_uidna_openUTS46_54', + '_ulocdata_close_54', + '_unorm_normalize_54', + '_uregex_matches_54', + '_uscript_getCode_54', + '_usearch_setPattern_54', + '?createInstance@Transliterator@icu_54@@SAPAV12@ABVUnicodeString@2@W4UTransDirection@@AAW4UErrorCode@@@Z', ], }, { 'reference_symbols': [ - 'u_errorName_52', - 'ubidi_setPara_52', - 'ucsdet_getName_52', - 'uidna_openUTS46_52', - 'ulocdata_close_52', - 'uregex_matches_52', - 'uscript_getCode_52', - 'usearch_setPattern_52', - '?createInstance@Transliterator@icu_52@@SAPEAV12@AEBVUnicodeString@2@W4UTransDirection@@AEAW4UErrorCode@@@Z' + 'u_errorName_54', + 'ubidi_setPara_54', + 'ucsdet_getName_54', + 'uidna_openUTS46_54', + 'ulocdata_close_54', + 'unorm_normalize_54', + 'uregex_matches_54', + 'uscript_getCode_54', + 'usearch_setPattern_54', + '?createInstance@Transliterator@icu_54@@SAPEAV12@AEBVUnicodeString@2@W4UTransDirection@@AEAW4UErrorCode@@@Z', ], }], ], diff --git a/docs/api/accelerator.md b/docs/api/accelerator.md index 58c57d4590a1..a9755ed653b0 100644 --- a/docs/api/accelerator.md +++ b/docs/api/accelerator.md @@ -14,6 +14,9 @@ On Linux and Windows, the `Command` key would not have any effect, you can use `CommandOrControl` which represents `Command` on OS X and `Control` on Linux and Windows to define some accelerators. +The `Super` key is mapped to the `Windows` key on Windows and Linux and +`Cmd` on OS X. + ## Available modifiers * `Command` (or `Cmd` for short) @@ -21,6 +24,7 @@ Linux and Windows to define some accelerators. * `CommandOrControl` (or `CmdOrCtrl` for short) * `Alt` * `Shift` +* `Super` ## Available key codes diff --git a/docs/api/app.md b/docs/api/app.md index 09ffb66c0b06..31fa1c616101 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -94,11 +94,6 @@ This method guarantees all `beforeunload` and `unload` handlers are correctly executed. It is possible that a window cancels the quitting by returning `false` in `beforeunload` handler. -## app.terminate() - -Quit the application directly, it will not try to close all windows so cleanup -code will not run. - ## app.getPath(name) * `name` String diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index cb6f9076c793..f8ff8e7b9e0c 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -54,9 +54,10 @@ You can also create a window without chrome by using * `frame` Boolean - Specify `false` to create a [Frameless Window](frameless-window.md) * `node-integration` Boolean - Whether node integration is enabled, default - is `true` + is `true` * `accept-first-mouse` Boolean - Whether the web view accepts a single - mouse-down event that simultaneously activates the window + mouse-down event that simultaneously activates the window + * `disable-auto-hide-cursor` Boolean - Do not hide cursor when typing * `auto-hide-menu-bar` Boolean - Auto hide the menu bar unless the `Alt` key is pressed. * `enable-larger-than-screen` Boolean - Enable the window to be resized larger @@ -71,6 +72,8 @@ You can also create a window without chrome by using * `type` String - Specifies the type of the window, possible types are `desktop`, `dock`, `toolbar`, `splash`, `notification`. This only works on Linux. + * `standard-window` Boolean - Uses the OS X's standard window instead of the + textured window. Defaults to `true`. * `web-preferences` Object - Settings of web page's features * `javascript` Boolean * `web-security` Boolean @@ -315,6 +318,20 @@ Sets whether the window should be in fullscreen mode. Returns whether the window is in fullscreen mode. +### BrowserWindow.setBounds(options) + +* `options` Object + * `x` Integer + * `y` Integer + * `width` Integer + * `height` Integer + +Resizes and moves the window to `width`, `height`, `x`, `y`. + +### BrowserWindow.getBounds() + +Returns an object that contains window's width, height, x and y values. + ### BrowserWindow.setSize(width, height) * `width` Integer @@ -662,6 +679,19 @@ Emitted when details regarding a requested resource is available. Emitted when a redirect was received while requesting a resource. +### Event: 'dom-ready' + +* `event` Event + +Emitted when document in the given frame is loaded. + +### Event: 'page-favicon-updated' + +* `event` Event +* `favicons` Array - Array of Urls + +Emitted when page receives favicon urls. + ### Event: 'new-window' * `event` Event @@ -834,6 +864,21 @@ Executes editing command `replace` in page. Executes editing command `replaceMisspelling` in page. +### WebContents.hasServiceWorker(callback) + +* `callback` Function + +Checks if any serviceworker is registered and returns boolean as +response to `callback`. + +### WebContents.unregisterServiceWorker(callback) + +* `callback` Function + +Unregisters any serviceworker if present and returns boolean as +response to `callback` when the JS promise is fullfilled or false +when the JS promise is rejected. + ### WebContents.send(channel[, args...]) * `channel` String diff --git a/docs/api/chrome-command-line-switches.md b/docs/api/chrome-command-line-switches.md index de124ac8ceba..fe22bd2c08ab 100644 --- a/docs/api/chrome-command-line-switches.md +++ b/docs/api/chrome-command-line-switches.md @@ -62,6 +62,14 @@ Like `--host-rules` but these `rules` only apply to the host resolver. Ignore certificate related errors. +## --ppapi-flash-path + +Set path to pepper flash plugin for use. + +## --ppapi-flash-version + +Set the pepper flash version. + ## --v=`log_level` Gives the default maximal active V-logging level; 0 is the default. Normally diff --git a/docs/api/power-monitor.md b/docs/api/power-monitor.md index 5ead769aa34c..4643110f35bb 100644 --- a/docs/api/power-monitor.md +++ b/docs/api/power-monitor.md @@ -1,13 +1,18 @@ # power-monitor The `power-monitor` module is used to monitor the power state change. You can -only use it on the main process. +only use it on the main process. You should not use this module until the `ready` +event of `app` module gets emitted. An example is: ```javascript -require('power-monitor').on('suspend', function() { - console.log('The system is going to sleep'); +var app = require('app'); + +app.on('ready', function() { + require('power-monitor').on('suspend', function() { + console.log('The system is going to sleep'); + }); }); ``` @@ -18,3 +23,11 @@ Emitted when the system is suspending. ## Event: resume Emitted when system is resuming. + +## Event: on-ac + +Emitted when the system changes to AC power. + +## Event: on-battery + +Emitted when system changes to battery power. diff --git a/docs/api/protocol.md b/docs/api/protocol.md index e554dbf5ebaa..65554e052105 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -82,4 +82,25 @@ Create a request job which sends a string as response. * `encoding` String - Default is `UTF-8` * `data` Buffer -Create a request job which accepts a buffer and sends a string as response. +Create a request job which sends a buffer as response. + +## Class: protocol.RequestErrorJob(code) + +* `code` Integer + +Create a request job which sets appropriate network error message to console. +Default message is `net::ERR_NOT_IMPLEMENTED`. Code should be in the following +range. + +* Ranges: + * 0- 99 System related errors + * 100-199 Connection related errors + * 200-299 Certificate errors + * 300-399 HTTP errors + * 400-499 Cache errors + * 500-599 ? + * 600-699 FTP errors + * 700-799 Certificate manager errors + * 800-899 DNS resolver errors + +Check the [network error list](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) for code and message relations. diff --git a/docs/api/remote.md b/docs/api/remote.md index 6145bc181b65..89bbc1f0606f 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -49,7 +49,7 @@ Primary value types like strings and numbers, however, are sent by copy. ## Passing callbacks to the main process -Some APIs in the main process accept callbacks, and it would be attempting to +Some APIs in the main process accept callbacks, and it would be tempting to pass callbacks when calling a remote function. The `remote` module does support doing this, but you should also be extremely careful with this. @@ -138,6 +138,10 @@ Returns the object returned by `require(module)` in the main process. Returns the [BrowserWindow](browser-window.md) object which this web page belongs to. +## remote.getCurrentWebContent() + +Returns the WebContents object of this web page. + ## remote.getGlobal(name) * `name` String diff --git a/docs/api/tray.md b/docs/api/tray.md index 6d16e3b50703..0562a6180e46 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -46,8 +46,17 @@ Creates a new tray icon associated with the `image`. ### Event: 'clicked' +* `event` +* `bounds` Object - the bounds of tray icon + * `x` Integer + * `y` Integer + * `width` Integer + * `height` Integer + Emitted when the tray icon is clicked. +__NOte:__ The `bounds` payload is only implemented on OS X. + ### Event: 'double-clicked' Emitted when the tray icon is double clicked. @@ -101,7 +110,7 @@ Sets the hover text for this tray icon. Sets the title displayed aside of the tray icon in the status bar. -This is only implemented on OS X. +__Note:__ This is only implemented on OS X. ### Tray.setHighlightMode(highlight) @@ -109,7 +118,7 @@ This is only implemented on OS X. Sets whether the tray icon is highlighted when it is clicked. -This is only implmented on OS X. +__Note:__ This is only implemented on OS X. ### Tray.displayBalloon(options) @@ -118,10 +127,14 @@ This is only implmented on OS X. * `title` String * `content` String +Displays a tray balloon. + +__Note:__ This is only implemented on Windows. + ### Tray.setContextMenu(menu) * `menu` Menu -Set the context menu for this icon. +Sets the context menu for this icon. [event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index f8e5cf86f717..89ae678b3c46 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -219,6 +219,13 @@ Closes the devtools window of guest page. Returns whether guest page has a devtools window attached. +### ``.inspectElement(x, y) + +* `x` Integer +* `y` Integer + +Starts inspecting element at position (`x`, `y`) of guest page. + ### ``.undo() Executes editing command `undo` in page. @@ -322,6 +329,10 @@ Fired when details regarding a requested resource is available. Fired when a redirect was received while requesting a resource. +### dom-ready + +Fired when document in the given frame is loaded. + ### page-title-set * `title` String @@ -330,6 +341,12 @@ Fired when a redirect was received while requesting a resource. Fired when page title is set during navigation. `explicitSet` is false when title is synthesised from file url. +### page-favicon-updated + +* `favicons` Array - Array of Urls + +Fired when page receives favicon urls. + ### console-message * `level` Integer diff --git a/docs/development/atom-shell-vs-node-webkit.md b/docs/development/atom-shell-vs-node-webkit.md index 6844df3556e9..ab8f6ab6dbdc 100644 --- a/docs/development/atom-shell-vs-node-webkit.md +++ b/docs/development/atom-shell-vs-node-webkit.md @@ -3,7 +3,7 @@ __Note: Electron was previously named Atom Shell.__ Like NW.js, Electron provides a platform to write desktop applications -with JavaScript and HTML, and has Node integration to grant access to low level +with JavaScript and HTML and has Node integration to grant access to low level system in web pages. But there are also fundamental differences between the two projects that make @@ -11,39 +11,38 @@ Electron a completely separate product from NW.js: __1. Entry of application__ -In NW.js, the main entry of an application is a web page, you specify a -main page in the `package.json` and it would be opened in a browser window as +In NW.js, the main entry of an application is a web page. You specify a +main page in the `package.json` and it is opened in a browser window as the application's main window. -While in Electron, the entry point is a JavaScript script, instead of -providing a URL directly, you need to manually create a browser window and load -html file in it with corresponding API. You also need to listen to window events +In Electron, the entry point is a JavaScript script. Instead of +providing a URL directly, you manually create a browser window and load +an HTML file using the API. You also need to listen to window events to decide when to quit the application. -So Electron works more like the Node.js runtime, and APIs are more low level, -you can also use Electron for web testing purpose like -[phantomjs](http://phantomjs.org/). +Electron works more like the Node.js runtime. Electron's APIs are lower level +so you can use it for browser testing in place of [PhantomJS](http://phantomjs.org/). __2. Build system__ In order to avoid the complexity of building the whole Chromium, Electron uses [libchromiumcontent](https://github.com/brightray/libchromiumcontent) to access -Chromium's Content API, libchromiumcontent is a single, shared library that -includes the Chromium Content module and all its dependencies. So users don't +Chromium's Content API. libchromiumcontent is a single, shared library that +includes the Chromium Content module and all its dependencies. Users don't need a powerful machine to build Electron. __3. Node integration__ In NW.js, the Node integration in web pages requires patching Chromium to -work, while in Electron we chose a different way to integrate libuv loop to -each platform's message loop to avoid hacking Chromium, see the +work, while in Electron we chose a different way to integrate libuv loop with +each platform's message loop to avoid hacking Chromium. See the [`node_bindings`](../../atom/common/) code for how that was done. __4. Multi-context__ If you are an experienced NW.js user, you should be familiar with the -concept of Node context and web context, these concepts were invented because -of how the NW.js was implemented. +concept of Node context and web context. These concepts were invented because +of how NW.js was implemented. By using the [multi-context](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/) feature of Node, Electron doesn't introduce a new JavaScript context in web diff --git a/docs/development/coding-style.md b/docs/development/coding-style.md index cc697a219dbe..df7f42e4a74e 100644 --- a/docs/development/coding-style.md +++ b/docs/development/coding-style.md @@ -18,7 +18,7 @@ Guide](https://github.com/styleguide/javascript), and also following rules: * File names should be concatenated with `-` instead of `_`, e.g. `file-name.coffee` rather than `file_name.coffee`, because in [github/atom](https://github.com/github/atom) module names are usually in - the `module-name` form, this rule only apply to `.coffee` files. + the `module-name` form, this rule only applies to `.coffee` files. ## API Names diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index 716f5c42c312..3f65df234dfe 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -118,8 +118,8 @@ app.setUserTasks([ arguments: '--new-window', iconPath: process.execPath, iconIndex: 0, - title: 'New Window' - description: 'Create a new winodw', + title: 'New Window', + description: 'Create a new window', } ]); ``` @@ -165,7 +165,7 @@ To set the progress bar for a Window, you can use the ```javascript var window = new BrowserWindow({...}); -window.setProgresssBar(0.5); +window.setProgressBar(0.5); ``` ## Represented file of window (OS X) diff --git a/docs/tutorial/quick-start.md b/docs/tutorial/quick-start.md index 0e643d9422a7..d9f6504eb1fa 100644 --- a/docs/tutorial/quick-start.md +++ b/docs/tutorial/quick-start.md @@ -2,41 +2,35 @@ ## Introduction -Generally, atom-shell enables you to create desktop applications with pure -JavaScript by providing a runtime with rich native APIs. You could see it as -a variant of the io.js runtime which is focused on desktop applications -instead of web servers. +Electron enables you to create desktop applications with pure JavaScript by providing a runtime with rich native APIs. You could see it as a variant of the io.js runtime which is focused on desktop applications instead of web servers. -It doesn't mean atom-shell is a JavaScript binding to GUI libraries. Instead, -atom-shell uses web pages as its GUI, so you could also see it as a minimal +It doesn't mean Electron is a JavaScript binding to GUI libraries. Instead, +Electron uses web pages as its GUI, so you could also see it as a minimal Chromium browser, controlled by JavaScript. -### The main process +### Main process -In atom-shell the process that runs `package.json`'s `main` script is called -__the main process__. The script runs in the main process can display GUI by +In Electron, the process that runs `package.json`'s `main` script is called +__the main process__. The script that runs in the main process, can display GUI by creating web pages. -### The renderer process +### Renderer process -Since atom-shell uses Chromium for displaying web pages, Chromium's -multi-processes architecture is also used. Each web page in atom-shell runs in +Since Electron uses Chromium for displaying web pages, Chromium's +multi-processes architecture is also used. Each web page in Electron runs in its own process, which is called __the renderer process__. -In normal browsers web pages are usually running in sandboxed environment and -not allowed to access native resources. In atom-shell users are given the power -to use io.js APIs in web pages, so it would be possible to interactive with -low level operating system in web pages with JavaScript. +In normal browsers web pages usually run in a sandboxed environment and are not +allowed access to native resources. Electron users however, have the power to use +io.js APIs in web pages allowing lower level operating system interactions. ### Differences between main process and renderer process -The main process creates web pages by creating `BrowserWindow` instances, and -each `BrowserWindow` instance runs the web page in its own renderer process, -when a `BrowserWindow` instance is destroyed, the corresponding renderer process +The main process creates web pages by creating `BrowserWindow` instances. Each `BrowserWindow` instance runs the web page in its own renderer process. When a `BrowserWindow` instance is destroyed, the corresponding renderer process would also be terminated. -So the main process manages all web pages and their corresponding renderer -processes, and each renderer process is separated from each other and only care +The main process manages all web pages and their corresponding renderer +processes, each renderer process is isolated and only cares about the web page running in it. In web pages, it is not allowed to call native GUI related APIs because managing @@ -44,14 +38,13 @@ native GUI resources in web pages is very dangerous and easy to leak resources. If you want to do GUI operations in web pages, you have to communicate with the main process to do it there. -In atom-shell, we have provided the [ipc](../api/ipc-renderer.md) module for +In Electron, we have provided the [ipc](../api/ipc-renderer.md) module for communication between main process and renderer process. And there is also a [remote](../api/remote.md) module for RPC style communication. -## Write your first atom-shell app +## Write your first Electron app -Generally, an atom-shell app would be structured like this (see the -[hello-atom](https://github.com/dougnukem/hello-atom) repo for reference): +Generally, an Electron app would be structured like this: ```text your-app/ @@ -93,7 +86,7 @@ app.on('window-all-closed', function() { app.quit(); }); -// This method will be called when atom-shell has done everything +// This method will be called when Electron has done everything // initialization and ready for creating browser windows. app.on('ready', function() { // Create the browser window. @@ -122,8 +115,8 @@ Finally the `index.html` is the web page you want to show:

Hello World!

- We are using node.js - and atom-shell . + We are using io.js + and Electron . ``` @@ -133,25 +126,25 @@ Finally the `index.html` is the web page you want to show: After you're done writing your app, you can create a distribution by following the [Application distribution](./application-distribution.md) guide and then execute the packaged app. You can also just use the downloaded -atom-shell binary to execute your app directly. +Electron binary to execute your app directly. On Windows: ```cmd -$ .\atom-shell\atom.exe your-app\ +$ .\electron\electron.exe your-app\ ``` On Linux: ```bash -$ ./atom-shell/atom your-app/ +$ ./electron/electron your-app/ ``` On OS X: ```bash -$ ./Electron.app/Contents/MacOS/Atom your-app/ +$ ./Electron.app/Contents/MacOS/Electron your-app/ ``` -`Electron.app` here is part of the atom-shell's release package, you can download +`Electron.app` here is part of the Electron's release package, you can download it from [here](https://github.com/atom/electron/releases). diff --git a/docs/tutorial/using-native-node-modules.md b/docs/tutorial/using-native-node-modules.md index b03fea134e39..643b4915b7ed 100644 --- a/docs/tutorial/using-native-node-modules.md +++ b/docs/tutorial/using-native-node-modules.md @@ -18,6 +18,19 @@ For old modules that only support Node v0.10.x, you should use the ## How to install native modules +### The Easy Way + +The most straightforward way to rebuild native modules is via the +[`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild) package, +which handles the manual steps of downloading headers and building native modules: + +```sh +npm install --save-dev electron-rebuild + +# Every time you run npm install, run this too +./node_modules/.bin/electron-rebuild +``` + ### The node-gyp way To build Node modules with headers of Electron, you need to tell `node-gyp` @@ -25,13 +38,13 @@ where to download headers and which version to use: ```bash $ cd /path-to-module/ -$ HOME=~/.electron-gyp node-gyp rebuild --target=0.16.0 --arch=ia32 --dist-url=https://atom.io/download/atom-shell +$ HOME=~/.electron-gyp node-gyp rebuild --target=0.25.0 --arch=ia64 --dist-url=https://atom.io/download/atom-shell ``` The `HOME=~/.electron-gyp` changes where to find development headers. The -`--target=0.16.0` is version of Electron. The `--dist-url=...` specifies -where to download the headers. The `--arch=ia32` says the module is built for -32bit system. +`--target=0.25.0` is version of Electron. The `--dist-url=...` specifies +where to download the headers. The `--arch=ia64` says the module is built for +64bit system. ### The npm way @@ -40,7 +53,7 @@ Node modules, except that you need to setup some environment variables: ```bash export npm_config_disturl=https://atom.io/download/atom-shell -export npm_config_target=0.23.0 +export npm_config_target=0.25.0 export npm_config_arch=x64 HOME=~/.electron-gyp npm install module-name ``` diff --git a/filenames.gypi b/filenames.gypi index d14c935ab728..ebd1fb41aaf2 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -18,6 +18,7 @@ 'atom/browser/api/lib/ipc.coffee', 'atom/browser/api/lib/menu.coffee', 'atom/browser/api/lib/menu-item.coffee', + 'atom/browser/api/lib/navigation-controller.coffee', 'atom/browser/api/lib/power-monitor.coffee', 'atom/browser/api/lib/protocol.coffee', 'atom/browser/api/lib/screen.coffee', @@ -148,8 +149,6 @@ 'atom/browser/net/url_request_string_job.h', 'atom/browser/net/url_request_buffer_job.cc', 'atom/browser/net/url_request_buffer_job.h', - 'atom/browser/node_debugger.cc', - 'atom/browser/node_debugger.h', 'atom/browser/ui/accelerator_util.cc', 'atom/browser/ui/accelerator_util.h', 'atom/browser/ui/accelerator_util_mac.mm', @@ -282,6 +281,8 @@ 'atom/renderer/atom_renderer_client.h', 'atom/renderer/guest_view_container.cc', 'atom/renderer/guest_view_container.h', + 'atom/utility/atom_content_utility_client.cc', + 'atom/utility/atom_content_utility_client.h', 'chromium_src/chrome/browser/browser_process.cc', 'chromium_src/chrome/browser/browser_process.h', 'chromium_src/chrome/browser/chrome_notification_types.h', @@ -310,6 +311,16 @@ 'chromium_src/chrome/browser/printing/printer_query.h', 'chromium_src/chrome/browser/printing/printing_message_filter.cc', 'chromium_src/chrome/browser/printing/printing_message_filter.h', + 'chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc', + 'chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h', 'chromium_src/chrome/browser/speech/tts_controller.h', 'chromium_src/chrome/browser/speech/tts_controller_impl.cc', 'chromium_src/chrome/browser/speech/tts_controller_impl.h', @@ -326,11 +337,26 @@ 'chromium_src/chrome/browser/ui/views/color_chooser_aura.h', 'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc', 'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h', + 'chromium_src/chrome/common/chrome_utility_messages.h', 'chromium_src/chrome/common/print_messages.cc', 'chromium_src/chrome/common/print_messages.h', 'chromium_src/chrome/common/tts_messages.h', 'chromium_src/chrome/common/tts_utterance_request.cc', 'chromium_src/chrome/common/tts_utterance_request.h', + 'chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc', + 'chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h', + 'chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.cc', + 'chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.h', + 'chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc', + 'chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.h', + 'chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.cc', + 'chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.h', + 'chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc', + 'chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.h', + 'chromium_src/chrome/renderer/pepper/pepper_helper.cc', + 'chromium_src/chrome/renderer/pepper/pepper_helper.h', + 'chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc', + 'chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.h', 'chromium_src/chrome/renderer/printing/print_web_view_helper.cc', 'chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc', 'chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm', @@ -340,6 +366,7 @@ 'chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h', 'chromium_src/chrome/renderer/tts_dispatcher.cc', 'chromium_src/chrome/renderer/tts_dispatcher.h', + 'chromium_src/chrome/utility/utility_message_handler.h', 'chromium_src/library_loaders/libspeechd_loader.cc', 'chromium_src/library_loaders/libspeechd.h', '<@(native_mate_files)', @@ -349,6 +376,10 @@ 'chromium_src/chrome/browser/ui/views/color_chooser_dialog.cc', 'chromium_src/chrome/browser/ui/views/color_chooser_dialog.h', 'chromium_src/chrome/browser/ui/views/color_chooser_win.cc', + 'chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc', + 'chromium_src/chrome/browser/printing/pdf_to_emf_converter.h', + 'chromium_src/chrome/utility/printing_handler.cc', + 'chromium_src/chrome/utility/printing_handler.h', ], 'framework_sources': [ 'atom/app/atom_library_main.h', diff --git a/package.json b/package.json index 07e87364f978..1942bcbc9a04 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "electron", "devDependencies": { - "asar": "0.2.2", - "coffee-script": "~1.7.1", - "coffeelint": "~1.3.0", + "asar": "0.5.0", + "coffee-script": "^1.9.2", + "coffeelint": "^1.9.4", "request": "*", "runas": "^2.0.0" }, diff --git a/script/bump-version.py b/script/bump-version.py index 59ff0a73306f..f910ae3ef95f 100755 --- a/script/bump-version.py +++ b/script/bump-version.py @@ -114,7 +114,6 @@ def update_info_plist(version): def tag_version(version): execute(['git', 'commit', '-a', '-m', 'Bump v{0}'.format(version)]) - execute(['git', 'tag', 'v{0}'.format(version)]) if __name__ == '__main__': diff --git a/script/create-dist.py b/script/create-dist.py index 3703e960ae03..6a6fa0d1a34b 100755 --- a/script/create-dist.py +++ b/script/create-dist.py @@ -35,12 +35,15 @@ TARGET_BINARIES = { 'icudtl.dat', 'libEGL.dll', 'libGLESv2.dll', + 'msvcp120.dll', + 'msvcr120.dll', 'node.dll', 'content_resources_200_percent.pak', 'ui_resources_200_percent.pak', 'xinput1_3.dll', 'natives_blob.bin', 'snapshot_blob.bin', + 'vccorlib120.dll', ], 'linux': [ PROJECT_NAME, # 'electron' @@ -79,7 +82,8 @@ def main(): force_build() create_symbols() copy_binaries() - copy_chromedriver() + copy_chrome_binary('chromedriver') + copy_chrome_binary('mksnapshot') copy_license() if PLATFORM == 'linux': @@ -88,7 +92,8 @@ def main(): create_version() create_dist_zip() - create_chromedriver_zip() + create_chrome_binary_zip('chromedriver', get_chromedriver_version()) + create_chrome_binary_zip('mksnapshot', ATOM_SHELL_VERSION) create_symbols_zip() @@ -107,13 +112,11 @@ def copy_binaries(): symlinks=True) -def copy_chromedriver(): +def copy_chrome_binary(binary): if PLATFORM == 'win32': - chromedriver = 'chromedriver.exe' - else: - chromedriver = 'chromedriver' - src = os.path.join(CHROMIUM_DIR, chromedriver) - dest = os.path.join(DIST_DIR, chromedriver) + binary += '.exe' + src = os.path.join(CHROMIUM_DIR, binary) + dest = os.path.join(DIST_DIR, binary) # Copy file and keep the executable bit. shutil.copyfile(src, dest) @@ -170,17 +173,17 @@ def create_dist_zip(): make_zip(zip_file, files, dirs) -def create_chromedriver_zip(): - dist_name = 'chromedriver-{0}-{1}-{2}.zip'.format(get_chromedriver_version(), - PLATFORM, get_target_arch()) +def create_chrome_binary_zip(binary, version): + dist_name = '{0}-{1}-{2}-{3}.zip'.format(binary, version, PLATFORM, + get_target_arch()) zip_file = os.path.join(SOURCE_ROOT, 'dist', dist_name) with scoped_cwd(DIST_DIR): files = ['LICENSE'] if PLATFORM == 'win32': - files += ['chromedriver.exe'] + files += [binary + '.exe'] else: - files += ['chromedriver'] + files += [binary] make_zip(zip_file, files, []) diff --git a/script/lib/config.py b/script/lib/config.py index 7fb314ac9a27..eb17cc92c4fd 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -7,7 +7,7 @@ import sys BASE_URL = 'http://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = 'f1ad1412461ba3345a27cfe935ffc872dba0ac5b' +LIBCHROMIUMCONTENT_COMMIT = '90a5b9c3792645067ad9517e60cf5eb99730e0f9' PLATFORM = { 'cygwin': 'win32', diff --git a/script/update-external-binaries.py b/script/update-external-binaries.py index a95a30f4a549..49e73435ab51 100755 --- a/script/update-external-binaries.py +++ b/script/update-external-binaries.py @@ -4,10 +4,11 @@ import errno import sys import os +from lib.config import get_target_arch from lib.util import safe_mkdir, rm_rf, extract_zip, tempdir, download -VERSION = 'v0.5.0' +VERSION = 'v0.7.0' SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) FRAMEWORKS_URL = 'http://github.com/atom/atom-shell-frameworks/releases' \ '/download/' + VERSION @@ -28,7 +29,8 @@ def main(): download_and_unzip('ReactiveCocoa') download_and_unzip('Squirrel') elif sys.platform in ['cygwin', 'win32']: - download_and_unzip('directxsdk') + download_and_unzip('directxsdk-' + get_target_arch()) + download_and_unzip('vs2012-crt-' + get_target_arch()) with open(version_file, 'w') as f: f.write(VERSION) diff --git a/script/upload-checksums.py b/script/upload-checksums.py index 4c1cfe9e8779..c71425126363 100755 --- a/script/upload-checksums.py +++ b/script/upload-checksums.py @@ -39,8 +39,11 @@ def parse_args(): def get_files_list(version): return [ 'node-{0}.tar.gz'.format(version), + 'iojs-{0}.tar.gz'.format(version), 'node.lib', 'x64/node.lib', + 'win-x86/iojs.lib', + 'win-x64/iojs.lib', ] diff --git a/script/upload-node-headers.py b/script/upload-node-headers.py index 86335b2b63db..38cb2f7e16f5 100755 --- a/script/upload-node-headers.py +++ b/script/upload-node-headers.py @@ -38,10 +38,13 @@ def main(): safe_mkdir(DIST_DIR) args = parse_args() - dist_headers_dir = os.path.join(DIST_DIR, 'node-{0}'.format(args.version)) + node_headers_dir = os.path.join(DIST_DIR, 'node-{0}'.format(args.version)) + iojs_headers_dir = os.path.join(DIST_DIR, 'iojs-{0}'.format(args.version)) - copy_headers(dist_headers_dir) - create_header_tarball(dist_headers_dir) + copy_headers(node_headers_dir) + create_header_tarball(node_headers_dir) + copy_headers(iojs_headers_dir) + create_header_tarball(iojs_headers_dir) # Upload node's headers to S3. bucket, access_key, secret_key = s3_config() @@ -103,22 +106,32 @@ def upload_node(bucket, access_key, secret_key, version): with scoped_cwd(DIST_DIR): s3put(bucket, access_key, secret_key, DIST_DIR, 'atom-shell/dist/{0}'.format(version), glob.glob('node-*.tar.gz')) + s3put(bucket, access_key, secret_key, DIST_DIR, + 'atom-shell/dist/{0}'.format(version), glob.glob('iojs-*.tar.gz')) if PLATFORM == 'win32': if get_target_arch() == 'ia32': node_lib = os.path.join(DIST_DIR, 'node.lib') + iojs_lib = os.path.join(DIST_DIR, 'win-x86', 'iojs.lib') else: node_lib = os.path.join(DIST_DIR, 'x64', 'node.lib') - safe_mkdir(os.path.dirname(node_lib)) + iojs_lib = os.path.join(DIST_DIR, 'win-x64', 'iojs.lib') + safe_mkdir(os.path.dirname(node_lib)) + safe_mkdir(os.path.dirname(iojs_lib)) - # Copy atom.lib to node.lib + # Copy atom.lib to node.lib and iojs.lib. atom_lib = os.path.join(OUT_DIR, 'node.dll.lib') shutil.copy2(atom_lib, node_lib) + shutil.copy2(atom_lib, iojs_lib) # Upload the node.lib. s3put(bucket, access_key, secret_key, DIST_DIR, 'atom-shell/dist/{0}'.format(version), [node_lib]) + # Upload the iojs.lib. + s3put(bucket, access_key, secret_key, DIST_DIR, + 'atom-shell/dist/{0}'.format(version), [iojs_lib]) + if __name__ == '__main__': sys.exit(main()) diff --git a/script/upload.py b/script/upload.py index 040d1650110b..281300554ef3 100755 --- a/script/upload.py +++ b/script/upload.py @@ -34,6 +34,9 @@ SYMBOLS_NAME = '{0}-{1}-{2}-{3}-symbols.zip'.format(PROJECT_NAME, CHROMEDRIVER_NAME = 'chromedriver-{0}-{1}-{2}.zip'.format(CHROMEDRIVER_VERSION, PLATFORM, get_target_arch()) +MKSNAPSHOT_NAME = 'mksnapshot-{0}-{1}-{2}.zip'.format(ATOM_SHELL_VERSION, + PLATFORM, + get_target_arch()) def main(): @@ -74,10 +77,12 @@ def main(): upload_atom_shell(github, release_id, os.path.join(DIST_DIR, DIST_NAME)) upload_atom_shell(github, release_id, os.path.join(DIST_DIR, SYMBOLS_NAME)) - # Upload chromedriver for minor version update. + # Upload chromedriver and mksnapshot for minor version update. if parse_version(args.version)[2] == '0': upload_atom_shell(github, release_id, os.path.join(DIST_DIR, CHROMEDRIVER_NAME)) + upload_atom_shell(github, release_id, + os.path.join(DIST_DIR, MKSNAPSHOT_NAME)) if PLATFORM == 'win32': # Upload PDBs to Windows symbol server. diff --git a/spec/api-app-spec.coffee b/spec/api-app-spec.coffee index 1c88c0277b30..4e6bda2ac1fe 100644 --- a/spec/api-app-spec.coffee +++ b/spec/api-app-spec.coffee @@ -22,4 +22,4 @@ describe 'app module', -> assert.equal app.getName(), 'Electron Test' app.setName 'test-name' assert.equal app.getName(), 'test-name' - app.setName 'Electron Test App' + app.setName 'Electron Test' diff --git a/spec/api-browser-window-spec.coffee b/spec/api-browser-window-spec.coffee index c723246d94fc..958bd7295803 100644 --- a/spec/api-browser-window-spec.coffee +++ b/spec/api-browser-window-spec.coffee @@ -2,6 +2,9 @@ assert = require 'assert' fs = require 'fs' path = require 'path' remote = require 'remote' +http = require 'http' +url = require 'url' +auth = require 'basic-auth' BrowserWindow = remote.require 'browser-window' @@ -216,8 +219,53 @@ describe 'browser-window module', -> describe 'will-navigate event', -> it 'emits when user starts a navigation', (done) -> + @timeout 10000 w.webContents.on 'will-navigate', (event, url) -> event.preventDefault() assert.equal url, 'https://www.github.com/' done() w.loadUrl "file://#{fixtures}/pages/will-navigate.html" + + describe 'dom-ready event', -> + it 'emits when document is loaded', (done) -> + ipc = remote.require 'ipc' + server = http.createServer (req, res) -> + action = url.parse(req.url, true).pathname + if action == '/logo.png' + img = fs.readFileSync(path.join(fixtures, 'assets', 'logo.png')) + res.writeHead(200, {'Content-Type': 'image/png'}) + setTimeout -> + res.end(img, 'binary') + , 2000 + server.close() + server.listen 62542, '127.0.0.1' + ipc.on 'dom-ready', (e, state) -> + ipc.removeAllListeners 'dom-ready' + assert.equal state, 'interactive' + done() + w.webContents.on 'did-finish-load', -> + w.close() + w.loadUrl "file://#{fixtures}/pages/f.html" + + describe 'basic auth', -> + it 'should authenticate with correct credentials', (done) -> + ipc = remote.require 'ipc' + server = http.createServer (req, res) -> + action = url.parse(req.url, true).pathname + if action == '/' + credentials = auth(req) + if credentials.name == 'test' and credentials.pass == 'test' + res.end('Authenticated') + server.close() + else if action == '/jquery.js' + js = fs.readFileSync(path.join(__dirname, 'static', 'jquery-2.0.3.min.js')) + res.writeHead(200, {'Content-Type': 'text/javascript'}) + res.end(js, 'utf-8') + server.listen 62342, '127.0.0.1' + ipc.on 'console-message', (e, message) -> + ipc.removeAllListeners 'console-message' + assert.equal message, 'Authenticated' + done() + w.webContents.on 'did-finish-load', -> + w.close() + w.loadUrl "file://#{fixtures}/pages/basic-auth.html" diff --git a/spec/api-ipc-spec.coffee b/spec/api-ipc-spec.coffee index c63997af7e78..d7f77b14ce2e 100644 --- a/spec/api-ipc-spec.coffee +++ b/spec/api-ipc-spec.coffee @@ -66,6 +66,7 @@ describe 'ipc module', -> assert.equal msg, 'test' it 'does not crash when reply is not sent and browser is destroyed', (done) -> + @timeout 10000 w = new BrowserWindow(show: false) remote.require('ipc').once 'send-sync-message', (event) -> event.returnValue = null diff --git a/spec/api-protocol-spec.coffee b/spec/api-protocol-spec.coffee index 0b6c62c02754..69506156089f 100644 --- a/spec/api-protocol-spec.coffee +++ b/spec/api-protocol-spec.coffee @@ -58,6 +58,21 @@ describe 'protocol module', -> assert false, 'Got error: ' + errorType + ' ' + error protocol.unregisterProtocol 'atom-string-job' + it 'returns RequestErrorJob should send error', (done) -> + data = 'valar morghulis' + job = new protocol.RequestErrorJob(-6) + handler = remote.createFunctionWithReturnValue job + protocol.registerProtocol 'atom-error-job', handler + + $.ajax + url: 'atom-error-job://fake-host' + success: (response) -> + assert false, 'should not reach here' + error: (xhr, errorType, error) -> + assert errorType, 'error' + protocol.unregisterProtocol 'atom-error-job' + done() + it 'returns RequestBufferJob should send buffer', (done) -> data = new Buffer("hello") job = new protocol.RequestBufferJob(data: data) diff --git a/spec/asar-spec.coffee b/spec/asar-spec.coffee index 625f2693bb35..d78ab4360618 100644 --- a/spec/asar-spec.coffee +++ b/spec/asar-spec.coffee @@ -36,6 +36,14 @@ describe 'asar package', -> throws = -> fs.readFileSync p assert.throws throws, /ENOENT/ + it 'passes ENOENT error to callback when can not find file', -> + p = path.join fixtures, 'asar', 'a.asar', 'not-exist' + async = false + fs.readFile p, (e) -> + assert async + assert /ENOENT/.test e + async = true + describe 'fs.readFile', -> it 'reads a normal file', (done) -> p = path.join fixtures, 'asar', 'a.asar', 'file1' diff --git a/spec/fixtures/pages/a.html b/spec/fixtures/pages/a.html index a471ad292d87..568973aed1cf 100644 --- a/spec/fixtures/pages/a.html +++ b/spec/fixtures/pages/a.html @@ -1,4 +1,6 @@ + + + + + diff --git a/spec/fixtures/pages/beforeunload-false.html b/spec/fixtures/pages/beforeunload-false.html new file mode 100644 index 000000000000..7ae4edf4ce29 --- /dev/null +++ b/spec/fixtures/pages/beforeunload-false.html @@ -0,0 +1,13 @@ + + + + + diff --git a/spec/fixtures/pages/f.html b/spec/fixtures/pages/f.html new file mode 100644 index 000000000000..e2003a3ab0d8 --- /dev/null +++ b/spec/fixtures/pages/f.html @@ -0,0 +1,11 @@ + + + + + + diff --git a/spec/fixtures/pages/native-module.html b/spec/fixtures/pages/native-module.html new file mode 100644 index 000000000000..a0ae0fe7592d --- /dev/null +++ b/spec/fixtures/pages/native-module.html @@ -0,0 +1,9 @@ + + + + + + diff --git a/spec/package.json b/spec/package.json index d91398382d9a..6e9489e601d8 100644 --- a/spec/package.json +++ b/spec/package.json @@ -4,6 +4,7 @@ "main": "static/main.js", "version": "0.1.0", "devDependencies": { + "basic-auth": "^1.0.0", "formidable": "1.0.16", "graceful-fs": "3.0.5", "mocha": "2.1.0", diff --git a/spec/webview-spec.coffee b/spec/webview-spec.coffee index 55ca8dc9ec78..54bc2e78817f 100644 --- a/spec/webview-spec.coffee +++ b/spec/webview-spec.coffee @@ -47,6 +47,19 @@ describe ' tag', -> webview.src = "file://#{fixtures}/pages/d.html" document.body.appendChild webview + it 'loads native modules when navigation happens', (done) -> + listener = (e) -> + webview.removeEventListener 'did-finish-load', listener + listener2 = (e) -> + assert.equal e.message, 'function' + done() + webview.addEventListener 'console-message', listener2 + webview.src = "file://#{fixtures}/pages/native-module.html" + webview.addEventListener 'did-finish-load', listener + webview.setAttribute 'nodeintegration', 'on' + webview.src = "file://#{fixtures}/pages/native-module.html" + document.body.appendChild webview + describe 'preload attribute', -> it 'loads the script before other scripts in window', (done) -> listener = (e) -> @@ -151,3 +164,32 @@ describe ' tag', -> done() webview.src = "file://#{fixtures}/pages/a.html" document.body.appendChild webview + + describe 'page-favicon-updated event', -> + it 'emits when favicon urls are received', (done) -> + webview.addEventListener 'page-favicon-updated', (e) -> + assert.equal e.favicons.length, 2 + url = + if process.platform is 'win32' + 'file:///C:/favicon.png' + else + 'file:///favicon.png' + assert.equal e.favicons[0], url + done() + webview.src = "file://#{fixtures}/pages/a.html" + document.body.appendChild webview + + describe '.reload()', -> + it 'should emit beforeunload handler', (done) -> + listener = (e) -> + assert.equal e.channel, 'onbeforeunload' + webview.removeEventListener 'ipc-message', listener + done() + listener2 = (e) -> + webview.reload() + webview.removeEventListener 'did-finish-load', listener2 + webview.addEventListener 'ipc-message', listener + webview.addEventListener 'did-finish-load', listener2 + webview.setAttribute 'nodeintegration', 'on' + webview.src = "file://#{fixtures}/pages/beforeunload-false.html" + document.body.appendChild webview diff --git a/vendor/brightray b/vendor/brightray index ec0a660b0b70..a929d7582927 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit ec0a660b0b70e6ea5a4ee760a753b8fac31a5de2 +Subproject commit a929d75829270def615e342c79ea17634e8c5989 diff --git a/vendor/native_mate b/vendor/native_mate index 40da835cbb7a..047a8de9342a 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit 40da835cbb7a5f76aacebf9d3ee4b66a62cece71 +Subproject commit 047a8de9342a3217a8d8316f77b9276e8eb7a649 diff --git a/vendor/node b/vendor/node index 9f7ab575d78f..e5aaa1ad33b3 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit 9f7ab575d78fa4c50cc5529f15646c8a37eb3258 +Subproject commit e5aaa1ad33b3479dbb29df797beca5873e7490dc