Compare commits

...

71 Commits

Author SHA1 Message Date
Cheng Zhao
25a7bcef82 Bump v0.28.2 2015-06-18 13:15:13 +08:00
Cheng Zhao
c8eaaaea83 mac: Use NSFileManager::resultingItemURL for moving file to trash
This allows the deleted file to be restored, fixes #2001.
2015-06-18 13:09:02 +08:00
Cheng Zhao
beb2853bbf Update how to rebrand from source, close #1999 2015-06-18 12:59:13 +08:00
Cheng Zhao
f76b60f295 Update brightray 2015-06-18 12:42:02 +08:00
Cheng Zhao
db8ffe1dc7 Handle ".." in asar path, fix #1982 2015-06-17 15:52:49 +08:00
Cheng Zhao
ad59393641 Update brightray, close #1025 2015-06-17 12:38:36 +08:00
Cheng Zhao
a751f4c689 Merge pull request #1835 from hokein/pdf-api
Add `BrowserWindow.printToPDF` API Implementation
2015-06-17 12:22:56 +08:00
Cheng Zhao
b3e9d35667 Merge pull request #1995 from atom/request-http-job
Implement protocol.RequestHttpJob
2015-06-17 12:00:26 +08:00
Cheng Zhao
c2aa7d538f Fix cpplint warnings 2015-06-17 11:34:47 +08:00
Cheng Zhao
1d41903779 docs: protocol.RequestHttpJob 2015-06-17 11:32:39 +08:00
Cheng Zhao
92f3371118 Use |request|'s headers if possible 2015-06-17 11:30:31 +08:00
Cheng Zhao
543c4d5597 Allow setting referrer 2015-06-17 11:22:02 +08:00
Cheng Zhao
e07f5cd53f Use |request|'s method if |method| is not specified 2015-06-17 11:11:13 +08:00
Cheng Zhao
66c4c7e77b Clear pending_buffer_ at correct time 2015-06-17 11:04:15 +08:00
Cheng Zhao
274854876c Allow setting method for RequestHttpJob 2015-06-17 10:57:26 +08:00
Cheng Zhao
81db8e098e Don't need buffer for piping data 2015-06-17 10:19:58 +08:00
Cheng Zhao
af05f26a5f Make URLRequestFetchJob actually work 2015-06-17 09:31:33 +08:00
Paul Betts
0b35d97821 Merge pull request #1994 from atom/paulcbetts-patch-1
Note that setPressedImage only has an effect on OS X
2015-06-16 18:18:14 -07:00
Paul Betts
8a56ab3947 Note that setPressedImage only has an effect on OS X 2015-06-16 18:17:51 -07:00
Haojian Wu
82b1607c1e 📝 Add missing printToPDF API in webview. 2015-06-16 20:17:58 +08:00
Haojian Wu
16348fc895 Copy pdf data on IO thread to avoid causing main process hangs. 2015-06-16 20:08:30 +08:00
Haojian Wu
1eba552a8d Also Expose printToPDF to BrowserWindow. 2015-06-16 20:08:30 +08:00
Haojian Wu
47eac062f6 Expose Print API to webContents and webView.
Also move the print implementation from window to webContents.
2015-06-16 20:08:30 +08:00
Haojian Wu
57580e00f9 Fix code style. 2015-06-16 20:07:45 +08:00
Haojian Wu
93bbc6c810 Simplify the pdf-data handled code. 2015-06-16 20:07:45 +08:00
Haojian Wu
894f9c0cb0 Don't use duprecated node buffer api, fix build error on OS X. 2015-06-16 20:07:44 +08:00
Haojian Wu
f22662ffb2 📝 Update docs. 2015-06-16 20:07:44 +08:00
Haojian Wu
559eb20e7f Fixing type: printBackgrounds => printBackground 2015-06-16 20:07:44 +08:00
Haojian Wu
ccbe554ec0 Make callback aligns node.js style. 2015-06-16 20:07:44 +08:00
Haojian Wu
93243ef223 Remove some unused IPC messages. 2015-06-16 20:07:44 +08:00
Haojian Wu
47439cd77c Fix a type error. 2015-06-16 20:07:44 +08:00
Haojian Wu
ac62871645 Return node::Buffer as a printToPDF callback result. 2015-06-16 20:07:44 +08:00
Haojian Wu
ab40da3f31 Add silent and savePath options. 2015-06-16 20:07:43 +08:00
Haojian Wu
6e099af5fe Move PDF printing setting in JS part. 2015-06-16 20:07:43 +08:00
Haojian Wu
c0a6cb69bf Move printToPDF API to WebContents.
Also expose in webview.
2015-06-16 20:06:52 +08:00
Haojian Wu
2597ded985 Cleanup. 2015-06-16 20:02:25 +08:00
Haojian Wu
10da361db1 Fix a type error in checking function options. 2015-06-16 20:02:25 +08:00
Haojian Wu
36fa4da252 Fix Linux compilation error. 2015-06-16 20:02:25 +08:00
Haojian Wu
68005f9ad4 Fix OS X compilation error. 2015-06-16 20:02:25 +08:00
Haojian Wu
bf5d448e37 📝 Add BrowserWindow.printToPDF API docs. 2015-06-16 20:02:24 +08:00
Haojian Wu
600077996c Fix a landscape option error. 2015-06-16 20:02:24 +08:00
Haojian Wu
cef177abc4 Add preview failed error. 2015-06-16 20:02:24 +08:00
Haojian Wu
8572ccb807 Add callback function in printToPDF API. 2015-06-16 20:02:24 +08:00
Haojian Wu
ce8bbb689c Add options to custom print settings in printToPDF API. 2015-06-16 20:02:24 +08:00
Haojian Wu
9cf9229308 Write PDF file in FILE thread. 2015-06-16 20:02:23 +08:00
Haojian Wu
7ffa7042b1 Add printToPDF Implementation. 2015-06-16 20:02:23 +08:00
Haojian Wu
b360f7d86a Add printToPDF API skeleton. 2015-06-16 20:02:23 +08:00
Cheng Zhao
44f8bfc550 Don't leak URLFetcher 2015-06-16 17:09:25 +08:00
Cheng Zhao
bd704dd8aa Merge pull request #1979 from deepak1556/remote_args_patch
remote: handle circular reference in wrapArgs
2015-06-16 16:40:06 +08:00
Cheng Zhao
7b3fc14023 docs: --ignore-connections-limit 2015-06-16 16:13:46 +08:00
deepak1556
193f95a888 remote: handle circular reference in wrapArgs 2015-06-16 13:43:30 +05:30
Cheng Zhao
b03f44df10 Update brightray for #1960 2015-06-16 16:04:03 +08:00
Cheng Zhao
bf9af4d45b Merge pull request #1980 from magicae/set-audio-mute
webContents: add setAudioMuted to webContents
2015-06-16 14:46:31 +08:00
Cheng Zhao
8181e9a0ef Update brightray for #1941 2015-06-16 13:38:21 +08:00
Cheng Zhao
d9db657b43 Merge pull request #1967 from j13z/patch-1
Add minor grammar fixes
2015-06-16 10:30:06 +08:00
Cheng Zhao
e96119fc32 s/liste/listen 2015-06-16 10:08:32 +08:00
Magica
8aa559fe51 Add setAudioMuted to webContents 2015-06-15 21:40:49 +08:00
deepak1556
a5e2f8e79e protocol: adding requestHttpJob method 2015-06-15 03:20:45 +05:30
Johannes Schmitz
2b3a80ecda Add minor grammar fixes 2015-06-13 16:58:18 +02:00
Benjamin Pasero
7da3e84369 Update app.md to document how open-file is emitted
On Mac, open-file is also emitted when the application is not yet running.
2015-06-12 12:37:53 +02:00
Cheng Zhao
8b8a6aea74 Bump v0.28.1 2015-06-12 16:26:51 +08:00
Cheng Zhao
16e224bb86 Don't set browser_handles_all_top_level_requests
POST requests currently can not be handled on browser side.

Fix #1945.
2015-06-12 16:26:04 +08:00
Cheng Zhao
459d389e03 Merge pull request #1951 from sotayamashita/translate/quick-start-jp.md
Translate quick-start.md into Japanese.
2015-06-12 15:49:21 +08:00
Cheng Zhao
8e4581a3c0 Merge pull request #1932 from samueleaton/master
adds example for "before using methods"
2015-06-12 15:07:17 +08:00
Cheng Zhao
c97c3fb9a1 Use LSGetApplicationForURL to search for app
It costs less.
2015-06-12 13:54:42 +08:00
Cheng Zhao
7ce8156691 Merge branch 'master' of https://github.com/mattotodd/electron into mattotodd-master 2015-06-12 13:49:51 +08:00
Sota Yamashita
0e6a70c556 Tranlsate quick-start-jp.md: status first
Translate: quick-start-jp.md

Fix bug

Tranlsate the world web

Change the method

Translate tutorial/quick-start-jp.md

Translate docs

Translate

Translate quick-start
2015-06-12 14:44:47 +09:00
Sam Eaton
b68d559329 Merge branch 'master' of https://github.com/atom/electron 2015-06-11 07:13:45 -06:00
eaton11
d367af3fa4 Merge branch 'master' of https://github.com/atom/electron 2015-06-10 19:28:14 -06:00
Sam Eaton
549ec51bce adds 'before using methods' example
The document does not inform that the webview element has to be loaded
before using the element's methods. It is not clear.
2015-06-10 19:24:36 -06:00
msullivan
b4674923c9 return bool on shell.openExternal 2015-06-10 11:06:22 -04:00
48 changed files with 1722 additions and 147 deletions

View File

@@ -4,7 +4,7 @@
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '0.28.0',
'version%': '0.28.2',
'atom_source_root': '<!(["python", "tools/atom_source_root.py"])',
},

View File

@@ -8,6 +8,7 @@
#include "atom/browser/net/adapter_request_job.h"
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "content/public/browser/browser_thread.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
@@ -115,14 +116,24 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
GetWeakPtr(), path));
return;
} else if (name == "RequestErrorJob") {
// Default value net::ERR_NOT_IMPLEMENTED
int error = -11;
int error = net::ERR_NOT_IMPLEMENTED;
dict.Get("error", &error);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
GetWeakPtr(), error));
return;
} else if (name == "RequestHttpJob") {
GURL url;
std::string method, referrer;
dict.Get("url", &url);
dict.Get("method", &method);
dict.Get("referrer", &referrer);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&AdapterRequestJob::CreateHttpJobAndStart,
GetWeakPtr(), url, method, referrer));
return;
}
}

View File

@@ -18,6 +18,8 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "chrome/browser/printing/print_preview_message_handler.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/guest_host.h"
#include "content/public/browser/navigation_details.h"
@@ -40,6 +42,15 @@
#include "atom/common/node_includes.h"
namespace {
struct PrintSettings {
bool silent;
bool print_background;
};
} // namespace
namespace mate {
template<>
@@ -64,6 +75,19 @@ struct Converter<atom::api::SetSizeParams> {
}
};
template<>
struct Converter<PrintSettings> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
PrintSettings* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("silent", &(out->silent));
dict.Get("printBackground", &(out->print_background));
return true;
}
};
} // namespace mate
@@ -580,6 +604,31 @@ void WebContents::UnregisterServiceWorker(
callback);
}
void WebContents::SetAudioMuted(bool muted) {
web_contents()->SetAudioMuted(muted);
}
bool WebContents::IsAudioMuted() {
return web_contents()->IsAudioMuted();
}
void WebContents::Print(mate::Arguments* args) {
PrintSettings settings = { false, false };
if (args->Length() == 1 && !args->GetNext(&settings)) {
args->ThrowError();
return;
}
printing::PrintViewManagerBasic::FromWebContents(web_contents())->
PrintNow(settings.silent, settings.print_background);
}
void WebContents::PrintToPDF(const base::DictionaryValue& setting,
const PrintToPDFCallback& callback) {
printing::PrintPreviewMessageHandler::FromWebContents(web_contents())->
PrintToPDF(setting, callback);
}
void WebContents::Undo() {
web_contents()->Undo();
}
@@ -731,6 +780,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
.SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
.SetMethod("inspectElement", &WebContents::InspectElement)
.SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
.SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
.SetMethod("undo", &WebContents::Undo)
.SetMethod("redo", &WebContents::Redo)
.SetMethod("cut", &WebContents::Cut)
@@ -750,6 +801,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("unregisterServiceWorker",
&WebContents::UnregisterServiceWorker)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
.Build());
return mate::ObjectTemplateBuilder(

View File

@@ -52,6 +52,10 @@ class WebContents : public mate::EventEmitter,
public content::WebContentsObserver,
public content::GpuDataManagerObserver {
public:
// For node.js callback function type: function(error, buffer)
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
PrintToPDFCallback;
// Create from an existing WebContents.
static mate::Handle<WebContents> CreateFrom(
v8::Isolate* isolate, brightray::InspectableWebContents* web_contents);
@@ -87,6 +91,13 @@ class WebContents : public mate::EventEmitter,
void InspectServiceWorker();
void HasServiceWorker(const base::Callback<void(bool)>&);
void UnregisterServiceWorker(const base::Callback<void(bool)>&);
void SetAudioMuted(bool muted);
bool IsAudioMuted();
void Print(mate::Arguments* args);
// Print current page as PDF.
void PrintToPDF(const base::DictionaryValue& setting,
const PrintToPDFCallback& callback);
// Editing commands.
void Undo();

View File

@@ -20,32 +20,6 @@
#include "atom/common/node_includes.h"
namespace {
struct PrintSettings {
bool silent;
bool print_background;
};
} // namespace
namespace mate {
template<>
struct Converter<PrintSettings> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
PrintSettings* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("silent", &(out->silent));
dict.Get("printBackground", &(out->print_background));
return true;
}
};
} // namespace mate
namespace atom {
namespace api {
@@ -420,16 +394,6 @@ void Window::CapturePage(mate::Arguments* args) {
rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
}
void Window::Print(mate::Arguments* args) {
PrintSettings settings = { false, false };;
if (args->Length() == 1 && !args->GetNext(&settings)) {
args->ThrowError();
return;
}
window_->Print(settings.silent, settings.print_background);
}
void Window::SetProgressBar(double progress) {
window_->SetProgressBar(progress);
}
@@ -541,7 +505,6 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("blurWebView", &Window::BlurWebView)
.SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
.SetMethod("capturePage", &Window::CapturePage)
.SetMethod("print", &Window::Print)
.SetMethod("setProgressBar", &Window::SetProgressBar)
.SetMethod("setOverlayIcon", &Window::SetOverlayIcon)
.SetMethod("_setMenu", &Window::SetMenu)

View File

@@ -131,7 +131,6 @@ class Window : public mate::EventEmitter,
void SetDocumentEdited(bool edited);
bool IsDocumentEdited();
void CapturePage(mate::Arguments* args);
void Print(mate::Arguments* args);
void SetProgressBar(double progress);
void SetOverlayIcon(const gfx::Image& overlay,
const std::string& description);

View File

@@ -83,5 +83,7 @@ BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened()
BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools()
BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments
BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker()
BrowserWindow::print = -> @webContents.print.apply @webContents, arguments
BrowserWindow::printToPDF = -> @webContents.printToPDF.apply @webContents, arguments
module.exports = BrowserWindow

View File

@@ -34,4 +34,8 @@ protocol.RequestErrorJob =
class RequestErrorJob
constructor: (@error) ->
protocol.RequestHttpJob =
class RequestHttpJob
constructor: ({@url, @method, @referrer}) ->
module.exports = protocol

View File

@@ -3,6 +3,9 @@ NavigationController = require './navigation-controller'
binding = process.atomBinding 'web_contents'
ipc = require 'ipc'
nextId = 0
getNextId = -> ++nextId
wrapWebContents = (webContents) ->
# webContents is an EventEmitter.
webContents.__proto__ = EventEmitter.prototype
@@ -58,6 +61,46 @@ wrapWebContents = (webContents) ->
Object.defineProperty event, 'sender', value: webContents
ipc.emit channel, event, args...
webContents.printToPDF = (options, callback) ->
printingSetting =
pageRage:[],
mediaSize:
height_microns:297000,
is_default:true,
name:"ISO_A4",
width_microns:210000,
custom_display_name:"A4",
landscape:false,
color:2,
headerFooterEnabled:false,
marginsType:0,
isFirstRequest:false,
requestID: getNextId(),
previewModifiable:true,
printToPDF:true,
printWithCloudPrint:false,
printWithPrivet:false,
printWithExtension:false,
deviceName:"Save as PDF",
generateDraftData:true,
fitToPageEnabled:false,
duplex:0,
copies:1,
collate:true,
shouldPrintBackgrounds:false,
shouldPrintSelectionOnly:false
if options.landscape
printingSetting.landscape = options.landscape
if options.marginsType
printingSetting.marginsType = options.marginsType
if options.printSelectionOnly
printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly
if options.printBackgrounds
printingSetting.shouldPrintBackgrounds = options.printBackground
webContents._printToPDF printingSetting, callback
webContents
binding._setWrapWebContents wrapWebContents

View File

@@ -12,11 +12,12 @@
#include "atom/browser/ui/file_dialog.h"
#include "atom/browser/web_dialog_helper.h"
#include "base/files/file_util.h"
#include "chrome/browser/printing/print_preview_message_handler.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/renderer_preferences.h"
#include "storage/browser/fileapi/isolated_context.h"
namespace atom {
@@ -103,11 +104,8 @@ void CommonWebContentsDelegate::InitWithWebContents(
owner_window_ = owner_window;
web_contents->SetDelegate(this);
// Tell renderer to handle all navigations in browser.
auto preferences = web_contents->GetMutableRendererPrefs();
preferences->browser_handles_non_local_top_level_requests = true;
preferences->browser_handles_all_top_level_requests = true;
web_contents->GetRenderViewHost()->SyncRendererPrefs();
printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents);
// Create InspectableWebContents.
web_contents_.reset(brightray::InspectableWebContents::Create(web_contents));

View File

@@ -27,7 +27,6 @@
#include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_details.h"
@@ -96,8 +95,6 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
has_dialog_attached_(false),
zoom_factor_(1.0),
weak_factory_(this) {
printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
InitWithWebContents(web_contents, this);
options.Get(switches::kFrame, &has_frame_);
@@ -257,11 +254,6 @@ bool NativeWindow::IsDocumentEdited() {
void NativeWindow::SetMenu(ui::MenuModel* menu) {
}
void NativeWindow::Print(bool silent, bool print_background) {
printing::PrintViewManagerBasic::FromWebContents(GetWebContents())->
PrintNow(silent, print_background);
}
void NativeWindow::ShowDefinitionForSelection() {
NOTIMPLEMENTED();
}

View File

@@ -154,9 +154,6 @@ class NativeWindow : public CommonWebContentsDelegate,
virtual void CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback);
// Print current page.
virtual void Print(bool silent, bool print_background);
// Show popup dictionary.
virtual void ShowDefinitionForSelection();

View File

@@ -4,8 +4,10 @@
#include "atom/browser/net/adapter_request_job.h"
#include "atom/browser/atom_browser_context.h"
#include "base/threading/sequenced_worker_pool.h"
#include "atom/browser/net/url_request_buffer_job.h"
#include "atom/browser/net/url_request_fetch_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"
@@ -66,6 +68,14 @@ bool AdapterRequestJob::GetCharset(std::string* charset) {
return real_job_->GetCharset(charset);
}
void AdapterRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
real_job_->GetResponseInfo(info);
}
int AdapterRequestJob::GetResponseCode() const {
return real_job_->GetResponseCode();
}
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
@@ -104,6 +114,19 @@ void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
real_job_->Start();
}
void AdapterRequestJob::CreateHttpJobAndStart(const GURL& url,
const std::string& method,
const std::string& referrer) {
if (!url.is_valid()) {
CreateErrorJobAndStart(net::ERR_INVALID_URL);
return;
}
real_job_ = new URLRequestFetchJob(request(), network_delegate(), url,
method, referrer);
real_job_->Start();
}
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
real_job_ = protocol_handler_->MaybeCreateJob(request(),
network_delegate());

View File

@@ -9,6 +9,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_factory.h"
#include "v8/include/v8.h"
@@ -40,6 +41,8 @@ class AdapterRequestJob : public net::URLRequestJob {
net::Filter* SetupFilter() const override;
bool GetMimeType(std::string* mime_type) const override;
bool GetCharset(std::string* charset) override;
void GetResponseInfo(net::HttpResponseInfo* info) override;
int GetResponseCode() const override;
base::WeakPtr<AdapterRequestJob> GetWeakPtr();
@@ -56,6 +59,9 @@ class AdapterRequestJob : public net::URLRequestJob {
const std::string& charset,
scoped_refptr<base::RefCountedBytes> data);
void CreateFileJobAndStart(const base::FilePath& path);
void CreateHttpJobAndStart(const GURL& url,
const std::string& method,
const std::string& referrer);
void CreateJobFromProtocolHandlerAndStart();
private:

View File

@@ -0,0 +1,184 @@
// 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/browser/net/url_request_fetch_job.h"
#include <algorithm>
#include <string>
#include "atom/browser/atom_browser_context.h"
#include "base/strings/string_util.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_response_writer.h"
#include "net/url_request/url_request_status.h"
namespace atom {
namespace {
// Convert string to RequestType.
net::URLFetcher::RequestType GetRequestType(const std::string& raw) {
std::string method = StringToUpperASCII(raw);
if (method.empty() || method == "GET")
return net::URLFetcher::GET;
else if (method == "POST")
return net::URLFetcher::POST;
else if (method == "HEAD")
return net::URLFetcher::HEAD;
else if (method == "DELETE")
return net::URLFetcher::DELETE_REQUEST;
else if (method == "PUT")
return net::URLFetcher::PUT;
else if (method == "PATCH")
return net::URLFetcher::PATCH;
else // Use "GET" as fallback.
return net::URLFetcher::GET;
}
// Pipe the response writer back to URLRequestFetchJob.
class ResponsePiper : public net::URLFetcherResponseWriter {
public:
explicit ResponsePiper(URLRequestFetchJob* job)
: first_write_(true), job_(job) {}
// net::URLFetcherResponseWriter:
int Initialize(const net::CompletionCallback& callback) override {
return net::OK;
}
int Write(net::IOBuffer* buffer,
int num_bytes,
const net::CompletionCallback& callback) override {
if (first_write_) {
// The URLFetcherResponseWriter doesn't have an event when headers have
// been read, so we have to emulate by hooking to first write event.
job_->HeadersCompleted();
first_write_ = false;
}
return job_->DataAvailable(buffer, num_bytes);
}
int Finish(const net::CompletionCallback& callback) override {
return net::OK;
}
private:
bool first_write_;
URLRequestFetchJob* job_;
DISALLOW_COPY_AND_ASSIGN(ResponsePiper);
};
} // namespace
URLRequestFetchJob::URLRequestFetchJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const GURL& url,
const std::string& method,
const std::string& referrer)
: net::URLRequestJob(request, network_delegate),
pending_buffer_size_(0) {
// Use |request|'s method if |method| is not specified.
net::URLFetcher::RequestType request_type;
if (method.empty())
request_type = GetRequestType(request->method());
else
request_type = GetRequestType(method);
fetcher_.reset(net::URLFetcher::Create(url, request_type, this));
auto context = AtomBrowserContext::Get()->url_request_context_getter();
fetcher_->SetRequestContext(context);
fetcher_->SaveResponseWithWriter(make_scoped_ptr(new ResponsePiper(this)));
// Use |request|'s referrer if |referrer| is not specified.
if (referrer.empty()) {
fetcher_->SetReferrer(request->referrer());
} else {
fetcher_->SetReferrer(referrer);
}
// Use |request|'s headers.
net::HttpRequestHeaders headers;
if (request->GetFullRequestHeaders(&headers)) {
fetcher_->SetExtraRequestHeaders(headers.ToString());
}
}
void URLRequestFetchJob::HeadersCompleted() {
response_info_.reset(new net::HttpResponseInfo);
response_info_->headers = fetcher_->GetResponseHeaders();
NotifyHeadersComplete();
}
int URLRequestFetchJob::DataAvailable(net::IOBuffer* buffer, int num_bytes) {
// Clear the IO_PENDING status.
SetStatus(net::URLRequestStatus());
// Do nothing if pending_buffer_ is empty, i.e. there's no ReadRawData()
// operation waiting for IO completion.
if (!pending_buffer_.get())
return net::ERR_IO_PENDING;
// pending_buffer_ is set to the IOBuffer instance provided to ReadRawData()
// by URLRequestJob.
int bytes_read = std::min(num_bytes, pending_buffer_size_);
memcpy(pending_buffer_->data(), buffer->data(), bytes_read);
// Clear the buffers before notifying the read is complete, so that it is
// safe for the observer to read.
pending_buffer_ = nullptr;
pending_buffer_size_ = 0;
NotifyReadComplete(bytes_read);
return bytes_read;
}
void URLRequestFetchJob::Start() {
fetcher_->Start();
}
void URLRequestFetchJob::Kill() {
URLRequestJob::Kill();
fetcher_.reset();
}
bool URLRequestFetchJob::ReadRawData(net::IOBuffer* dest,
int dest_size,
int* bytes_read) {
pending_buffer_ = dest;
pending_buffer_size_ = dest_size;
SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
return false;
}
bool URLRequestFetchJob::GetMimeType(std::string* mime_type) const {
if (!response_info_)
return false;
return response_info_->headers->GetMimeType(mime_type);
}
void URLRequestFetchJob::GetResponseInfo(net::HttpResponseInfo* info) {
if (response_info_)
*info = *response_info_;
}
int URLRequestFetchJob::GetResponseCode() const {
if (!response_info_)
return -1;
return response_info_->headers->response_code();
}
void URLRequestFetchJob::OnURLFetchComplete(const net::URLFetcher* source) {
pending_buffer_ = nullptr;
pending_buffer_size_ = 0;
NotifyDone(fetcher_->GetStatus());
if (fetcher_->GetStatus().is_success())
NotifyReadComplete(0);
}
} // namespace atom

View File

@@ -0,0 +1,51 @@
// 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_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_
#define ATOM_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_
#include <string>
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_job.h"
namespace atom {
class URLRequestFetchJob : public net::URLRequestJob,
public net::URLFetcherDelegate {
public:
URLRequestFetchJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const GURL& url,
const std::string& method,
const std::string& referrer);
void HeadersCompleted();
int DataAvailable(net::IOBuffer* buffer, int num_bytes);
// net::URLRequestJob:
void Start() override;
void Kill() override;
bool ReadRawData(net::IOBuffer* buf,
int buf_size,
int* bytes_read) override;
bool GetMimeType(std::string* mime_type) const override;
void GetResponseInfo(net::HttpResponseInfo* info) override;
int GetResponseCode() const override;
// net::URLFetcherDelegate:
void OnURLFetchComplete(const net::URLFetcher* source) override;
private:
scoped_ptr<net::URLFetcher> fetcher_;
scoped_refptr<net::IOBuffer> pending_buffer_;
int pending_buffer_size_;
scoped_ptr<net::HttpResponseInfo> response_info_;
DISALLOW_COPY_AND_ASSIGN(URLRequestFetchJob);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_

View File

@@ -17,7 +17,7 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.28.0</string>
<string>0.28.2</string>
<key>LSMinimumSystemVersion</key>
<string>10.8.0</string>
<key>NSMainNibFile</key>

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,28,0,0
PRODUCTVERSION 0,28,0,0
FILEVERSION 0,28,2,0
PRODUCTVERSION 0,28,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "0.28.0"
VALUE "FileVersion", "0.28.2"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "0.28.0"
VALUE "ProductVersion", "0.28.2"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 28
#define ATOM_PATCH_VERSION 0
#define ATOM_PATCH_VERSION 2
#define ATOM_VERSION_IS_RELEASE 1

View File

@@ -20,6 +20,7 @@ process.on 'exit', ->
splitPath = (p) ->
return [false] if typeof p isnt 'string'
return [true, p, ''] if p.substr(-5) is '.asar'
p = path.normalize p
index = p.lastIndexOf ".asar#{path.sep}"
return [false] if index is -1
[true, p.substr(0, index + 5), p.substr(index + 6)]

View File

@@ -23,7 +23,7 @@ void OpenItem(const base::FilePath& full_path);
// Open the given external protocol URL in the desktop's default manner.
// (For example, mailto: URLs in the default mail user agent.)
void OpenExternal(const GURL& url);
bool OpenExternal(const GURL& url);
// Move a file to trash.
bool MoveItemToTrash(const base::FilePath& full_path);

View File

@@ -37,12 +37,12 @@ bool XDGUtil(const std::string& util, const std::string& arg) {
return (exit_code == 0);
}
void XDGOpen(const std::string& path) {
XDGUtil("xdg-open", path);
bool XDGOpen(const std::string& path) {
return XDGUtil("xdg-open", path);
}
void XDGEmail(const std::string& email) {
XDGUtil("xdg-email", email);
bool XDGEmail(const std::string& email) {
return XDGUtil("xdg-email", email);
}
} // namespace
@@ -64,11 +64,11 @@ void OpenItem(const base::FilePath& full_path) {
XDGOpen(full_path.value());
}
void OpenExternal(const GURL& url) {
bool OpenExternal(const GURL& url) {
if (url.SchemeIs("mailto"))
XDGEmail(url.spec());
return XDGEmail(url.spec());
else
XDGOpen(url.spec());
return XDGOpen(url.spec());
}
bool MoveItemToTrash(const base::FilePath& full_path) {

View File

@@ -118,26 +118,34 @@ void OpenItem(const base::FilePath& full_path) {
}
}
void OpenExternal(const GURL& url) {
bool OpenExternal(const GURL& url) {
DCHECK([NSThread isMainThread]);
NSString* url_string = base::SysUTF8ToNSString(url.spec());
NSURL* ns_url = [NSURL URLWithString:url_string];
if (!ns_url || ![[NSWorkspace sharedWorkspace] openURL:ns_url])
LOG(WARNING) << "NSWorkspace failed to open URL " << url;
if (!ns_url) {
return false;
}
CFURLRef openingApp = NULL;
OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url,
kLSRolesAll,
NULL,
&openingApp);
if (status != noErr) {
return false;
}
CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us
return [[NSWorkspace sharedWorkspace] openURL:ns_url];
}
bool MoveItemToTrash(const base::FilePath& full_path) {
DCHECK([NSThread isMainThread]);
NSString* path_string = base::SysUTF8ToNSString(full_path.value());
NSArray* file_array =
[NSArray arrayWithObject:[path_string lastPathComponent]];
BOOL status = [[NSWorkspace sharedWorkspace]
performFileOperation:NSWorkspaceRecycleOperation
source:[path_string stringByDeletingLastPathComponent]
destination:@""
files:file_array
tag:nil];
if (!path_string || !file_array || !status)
BOOL status = [[NSFileManager defaultManager]
trashItemAtURL:[NSURL fileURLWithPath:path_string]
resultingItemURL:nil
error:nil];
if (!path_string || !status)
LOG(WARNING) << "NSWorkspace failed to move file " << full_path.value()
<< " to trash";
return status;

View File

@@ -135,7 +135,7 @@ void OpenItem(const base::FilePath& full_path) {
ui::win::OpenFileViaShell(full_path);
}
void OpenExternal(const GURL& url) {
bool OpenExternal(const GURL& url) {
// Quote the input scheme to be sure that the command does not have
// parameters unexpected by the external program. This url should already
// have been escaped.
@@ -150,12 +150,12 @@ void OpenExternal(const GURL& url) {
const size_t kMaxUrlLength = 2048;
if (escaped_url.length() > kMaxUrlLength) {
NOTREACHED();
return;
return false;
}
if (base::win::GetVersion() < base::win::VERSION_WIN7) {
if (!ValidateShellCommandForScheme(url.scheme()))
return;
return false;
}
if (reinterpret_cast<ULONG_PTR>(ShellExecuteA(NULL, "open",
@@ -164,8 +164,9 @@ void OpenExternal(const GURL& url) {
// We fail to execute the call. We could display a message to the user.
// TODO(nsylvain): we should also add a dialog to warn on errors. See
// bug 1136923.
return;
return false;
}
return true;
}
bool MoveItemToTrash(const base::FilePath& path) {

View File

@@ -5,18 +5,29 @@ CallbacksRegistry = require 'callbacks-registry'
callbacksRegistry = new CallbacksRegistry
# Check for circular reference.
isCircular = (field, visited) ->
if typeof field is 'object'
if field in visited
return true
visited.push field
return false
# Convert the arguments object into an array of meta data.
wrapArgs = (args) ->
wrapArgs = (args, visited=[]) ->
valueToMeta = (value) ->
if Array.isArray value
type: 'array', value: wrapArgs(value)
type: 'array', value: wrapArgs(value, visited)
else if Buffer.isBuffer value
type: 'buffer', value: Array::slice.call(value, 0)
else if value? and typeof value is 'object' and v8Util.getHiddenValue value, 'atomId'
type: 'remote-object', id: v8Util.getHiddenValue value, 'atomId'
else if value? and typeof value is 'object'
ret = type: 'object', name: value.constructor.name, members: []
ret.members.push(name: prop, value: valueToMeta(field)) for prop, field of value
for prop, field of value
ret.members.push
name: prop
value: valueToMeta(if isCircular(field, visited) then null else field)
ret
else if typeof value is 'function' and v8Util.getHiddenValue value, 'returnValue'
type: 'function-with-return-value', value: valueToMeta(value())

View File

@@ -275,6 +275,8 @@ registerWebViewElement = ->
"closeDevTools"
"isDevToolsOpened"
"inspectElement"
"setAudioMuted"
"isAudioMuted"
"undo"
"redo"
"cut"
@@ -289,6 +291,8 @@ registerWebViewElement = ->
"send"
"getId"
"inspectServiceWorker"
"print"
"printToPDF"
]
# Forward proto.foo* method calls to WebViewImpl.foo*.

View File

@@ -0,0 +1,140 @@
// 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/printing/print_preview_message_handler.h"
#include "base/bind.h"
#include "base/memory/shared_memory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/common/print_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "printing/page_size_margins.h"
#include "printing/print_job_constants.h"
#include "printing/pdf_metafile_skia.h"
#include "atom/common/node_includes.h"
using content::BrowserThread;
using content::WebContents;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintPreviewMessageHandler);
namespace {
void StopWorker(int document_cookie) {
if (document_cookie <= 0)
return;
scoped_refptr<printing::PrintQueriesQueue> queue =
g_browser_process->print_job_manager()->queue();
scoped_refptr<printing::PrinterQuery> printer_query =
queue->PopPrinterQuery(document_cookie);
if (printer_query.get()) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&printing::PrinterQuery::StopWorker,
printer_query));
}
}
char* CopyPDFDataOnIOThread(
const PrintHostMsg_DidPreviewDocument_Params& params) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_ptr<base::SharedMemory> shared_buf(
new base::SharedMemory(params.metafile_data_handle, true));
if (!shared_buf->Map(params.data_size))
return nullptr;
char* memory_pdf_data = static_cast<char*>(shared_buf->memory());
char* pdf_data = new char[params.data_size];
memcpy(pdf_data, memory_pdf_data, params.data_size);
return pdf_data;
}
} // namespace
namespace printing {
PrintPreviewMessageHandler::PrintPreviewMessageHandler(
WebContents* web_contents)
: content::WebContentsObserver(web_contents) {
DCHECK(web_contents);
}
PrintPreviewMessageHandler::~PrintPreviewMessageHandler() {
}
void PrintPreviewMessageHandler::OnMetafileReadyForPrinting(
const PrintHostMsg_DidPreviewDocument_Params& params) {
// Always try to stop the worker.
StopWorker(params.document_cookie);
if (params.expected_pages_count <= 0) {
NOTREACHED();
return;
}
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::IO,
FROM_HERE,
base::Bind(&CopyPDFDataOnIOThread, params),
base::Bind(&PrintPreviewMessageHandler::RunPrintToPDFCallback,
base::Unretained(this),
params.preview_request_id,
params.data_size));
}
void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie,
int request_id) {
StopWorker(document_cookie);
RunPrintToPDFCallback(request_id, 0, nullptr);
}
bool PrintPreviewMessageHandler::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintPreviewMessageHandler, message)
IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting,
OnMetafileReadyForPrinting)
IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewFailed,
OnPrintPreviewFailed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PrintPreviewMessageHandler::PrintToPDF(
const base::DictionaryValue& options,
const atom::api::WebContents::PrintToPDFCallback& callback) {
int request_id;
options.GetInteger(printing::kPreviewRequestID, &request_id);
print_to_pdf_callback_map_[request_id] = callback;
content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), options));
}
void PrintPreviewMessageHandler::RunPrintToPDFCallback(
int request_id, uint32 data_size, char* data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (data) {
v8::Local<v8::Value> buffer = node::Buffer::Use(isolate,
data, static_cast<size_t>(data_size));
print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate), buffer);
} else {
v8::Local<v8::String> error_message = v8::String::NewFromUtf8(isolate,
"Fail to generate PDF");
print_to_pdf_callback_map_[request_id].Run(
v8::Exception::Error(error_message), v8::Null(isolate));
}
print_to_pdf_callback_map_.erase(request_id);
}
} // namespace printing

View File

@@ -0,0 +1,59 @@
// 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_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_
#define CHROME_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_
#include <map>
#include "atom/browser/api/atom_api_web_contents.h"
#include "base/compiler_specific.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
struct PrintHostMsg_DidPreviewDocument_Params;
namespace content {
class WebContents;
}
namespace printing {
struct PageSizeMargins;
// Manages the print preview handling for a WebContents.
class PrintPreviewMessageHandler
: public content::WebContentsObserver,
public content::WebContentsUserData<PrintPreviewMessageHandler> {
public:
~PrintPreviewMessageHandler() override;
// content::WebContentsObserver implementation.
bool OnMessageReceived(const IPC::Message& message) override;
void PrintToPDF(const base::DictionaryValue& options,
const atom::api::WebContents::PrintToPDFCallback& callback);
private:
typedef std::map<int, atom::api::WebContents::PrintToPDFCallback>
PrintToPDFCallbackMap;
explicit PrintPreviewMessageHandler(content::WebContents* web_contents);
friend class content::WebContentsUserData<PrintPreviewMessageHandler>;
// Message handlers.
void OnMetafileReadyForPrinting(
const PrintHostMsg_DidPreviewDocument_Params& params);
void OnPrintPreviewFailed(int document_cookie, int request_id);
void RunPrintToPDFCallback(int request_id, uint32 data_size, char* data);
PrintToPDFCallbackMap print_to_pdf_callback_map_;
DISALLOW_COPY_AND_ASSIGN(PrintPreviewMessageHandler);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_

View File

@@ -128,6 +128,8 @@ bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings,
OnGetDefaultPrintSettings)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings,
OnUpdatePrintSettings)
#if defined(ENABLE_FULL_PRINTING)
IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel)
#endif
@@ -372,4 +374,57 @@ void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) {
}
#endif
void PrintingMessageFilter::OnUpdatePrintSettings(
int document_cookie, const base::DictionaryValue& job_settings,
IPC::Message* reply_msg) {
scoped_ptr<base::DictionaryValue> new_settings(job_settings.DeepCopy());
scoped_refptr<PrinterQuery> printer_query;
printer_query = queue_->PopPrinterQuery(document_cookie);
if (!printer_query.get()) {
int host_id = render_process_id_;
int routing_id = reply_msg->routing_id();
if (!new_settings->GetInteger(printing::kPreviewInitiatorHostId,
&host_id) ||
!new_settings->GetInteger(printing::kPreviewInitiatorRoutingId,
&routing_id)) {
host_id = content::ChildProcessHost::kInvalidUniqueID;
routing_id = content::ChildProcessHost::kInvalidUniqueID;
}
printer_query = queue_->CreatePrinterQuery(host_id, routing_id);
}
printer_query->SetSettings(
new_settings.Pass(),
base::Bind(&PrintingMessageFilter::OnUpdatePrintSettingsReply, this,
printer_query, reply_msg));
}
void PrintingMessageFilter::OnUpdatePrintSettingsReply(
scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg) {
PrintMsg_PrintPages_Params params;
if (!printer_query.get() ||
printer_query->last_status() != PrintingContext::OK) {
params.Reset();
} else {
RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
params.params.document_cookie = printer_query->cookie();
params.pages = PageRange::GetPages(printer_query->settings().ranges());
}
PrintHostMsg_UpdatePrintSettings::WriteReplyParams(
reply_msg,
params,
printer_query.get() &&
(printer_query->last_status() == printing::PrintingContext::CANCEL));
Send(reply_msg);
// If user hasn't cancelled.
if (printer_query.get()) {
if (printer_query->cookie() && printer_query->settings().dpi()) {
queue_->QueuePrinterQuery(printer_query.get());
} else {
printer_query->StopWorker();
}
}
}
} // namespace printing

View File

@@ -96,6 +96,15 @@ class PrintingMessageFilter : public content::BrowserMessageFilter {
void OnScriptedPrintReply(scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg);
// Modify the current print settings based on |job_settings|. The task is
// handled by the print worker thread and the UI thread. The reply occurs on
// the IO thread.
void OnUpdatePrintSettings(int document_cookie,
const base::DictionaryValue& job_settings,
IPC::Message* reply_msg);
void OnUpdatePrintSettingsReply(scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg);
#if defined(ENABLE_FULL_PRINTING)
// Check to see if print preview has been cancelled.
void OnCheckForCancel(int32 preview_ui_id,

View File

@@ -46,7 +46,9 @@ struct PrintMsg_Print_Params {
int document_cookie;
bool selection_only;
bool supports_alpha_blend;
int preview_request_id;
blink::WebPrintScalingOption print_scaling_option;
bool print_to_pdf;
base::string16 title;
base::string16 url;
bool should_print_backgrounds;
@@ -185,6 +187,27 @@ IPC_STRUCT_BEGIN(PrintHostMsg_ScriptedPrint_Params)
IPC_STRUCT_MEMBER(printing::MarginType, margin_type)
IPC_STRUCT_END()
// Parameters to describe a rendered document.
IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewDocument_Params)
// A shared memory handle to metafile data.
IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle)
// Size of metafile data.
IPC_STRUCT_MEMBER(uint32, data_size)
// Cookie for the document to ensure correctness.
IPC_STRUCT_MEMBER(int, document_cookie)
// Store the expected pages count.
IPC_STRUCT_MEMBER(int, expected_pages_count)
// Whether the preview can be modified.
IPC_STRUCT_MEMBER(bool, modifiable)
// The id of the preview request.
IPC_STRUCT_MEMBER(int, preview_request_id)
IPC_STRUCT_END()
// Messages sent from the browser to the renderer.
@@ -198,6 +221,12 @@ IPC_MESSAGE_ROUTED2(PrintMsg_PrintPages,
IPC_MESSAGE_ROUTED1(PrintMsg_PrintingDone,
bool /* success */)
// Tells the render view to switch the CSS to print media type, renders every
// requested pages for print preview using the given |settings|. This gets
// called multiple times as the user updates settings.
IPC_MESSAGE_ROUTED1(PrintMsg_PrintPreview,
base::DictionaryValue /* settings */)
// Messages sent from the renderer to the browser.
#if defined(OS_WIN)
@@ -231,6 +260,14 @@ IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPrintPage,
IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_GetDefaultPrintSettings,
PrintMsg_Print_Params /* default_settings */)
// The renderer wants to update the current print settings with new
// |job_settings|.
IPC_SYNC_MESSAGE_ROUTED2_2(PrintHostMsg_UpdatePrintSettings,
int /* document_cookie */,
base::DictionaryValue /* job_settings */,
PrintMsg_PrintPages_Params /* current_settings */,
bool /* canceled */)
// It's the renderer that controls the printing process when it is generated
// by javascript. This step is about showing UI to the user to select the
// final print settings. The output parameter is the same as
@@ -247,6 +284,15 @@ IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError)
IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintingFailed,
int /* document cookie */)
// Sends back to the browser the complete rendered document (non-draft mode,
// used for printing) that was requested by a PrintMsg_PrintPreview message.
// The memory handle in this message is already valid in the browser process.
IPC_MESSAGE_ROUTED1(PrintHostMsg_MetafileReadyForPrinting,
PrintHostMsg_DidPreviewDocument_Params /* params */)
IPC_MESSAGE_ROUTED2(PrintHostMsg_PrintPreviewFailed,
int /* document cookie */,
int /* request_id */);
#if defined(OS_WIN)
// Tell the utility process to start rendering the given PDF into a metafile.

View File

@@ -650,6 +650,7 @@ bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message)
IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages)
IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone, OnPrintingDone)
IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview, OnPrintPreview)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -712,6 +713,128 @@ void PrintWebViewHelper::OnPrintingDone(bool success) {
DidFinishPrinting(success ? OK : FAIL_PRINT);
}
void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) {
blink::WebLocalFrame* frame;
if (GetPrintFrame(&frame)) {
print_preview_context_.InitWithFrame(frame);
if (!print_preview_context_.source_frame()) {
DidFinishPrinting(FAIL_PREVIEW);
return;
}
if (!UpdatePrintSettings(print_preview_context_.source_frame(),
print_preview_context_.source_node(), settings)) {
DidFinishPrinting(FAIL_PREVIEW);
return;
}
is_print_ready_metafile_sent_ = false;
PrepareFrameForPreviewDocument();
}
}
void PrintWebViewHelper::PrepareFrameForPreviewDocument() {
reset_prep_frame_view_ = false;
if (!print_pages_params_) {
DidFinishPrinting(FAIL_PREVIEW);
return;
}
// Don't reset loading frame or WebKit will fail assert. Just retry when
// current selection is loaded.
if (prep_frame_view_ && prep_frame_view_->IsLoadingSelection()) {
reset_prep_frame_view_ = true;
return;
}
const PrintMsg_Print_Params& print_params = print_pages_params_->params;
prep_frame_view_.reset(new PrepareFrameAndViewForPrint(
print_params, print_preview_context_.source_frame(),
print_preview_context_.source_node(), ignore_css_margins_));
prep_frame_view_->CopySelectionIfNeeded(
render_view()->GetWebkitPreferences(),
base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument,
base::Unretained(this)));
}
void PrintWebViewHelper::OnFramePreparedForPreviewDocument() {
if (reset_prep_frame_view_) {
PrepareFrameForPreviewDocument();
return;
}
DidFinishPrinting(CreatePreviewDocument() ? OK : FAIL_PREVIEW);
}
bool PrintWebViewHelper::CreatePreviewDocument() {
if (!print_pages_params_)
return false;
const PrintMsg_Print_Params& print_params = print_pages_params_->params;
const std::vector<int>& pages = print_pages_params_->pages;
if (!print_preview_context_.CreatePreviewDocument(prep_frame_view_.release(),
pages)) {
return false;
}
while (!print_preview_context_.IsFinalPageRendered()) {
int page_number = print_preview_context_.GetNextPageNumber();
DCHECK_GE(page_number, 0);
if (!RenderPreviewPage(page_number, print_params))
return false;
// We must call PrepareFrameAndViewForPrint::FinishPrinting() (by way of
// print_preview_context_.AllPagesRendered()) before calling
// FinalizePrintReadyDocument() when printing a PDF because the plugin
// code does not generate output until we call FinishPrinting(). We do not
// generate draft pages for PDFs, so IsFinalPageRendered() and
// IsLastPageOfPrintReadyMetafile() will be true in the same iteration of
// the loop.
if (print_preview_context_.IsFinalPageRendered())
print_preview_context_.AllPagesRendered();
if (print_preview_context_.IsLastPageOfPrintReadyMetafile()) {
DCHECK(print_preview_context_.IsModifiable() ||
print_preview_context_.IsFinalPageRendered());
if (!FinalizePrintReadyDocument())
return false;
}
}
print_preview_context_.Finished();
return true;
}
bool PrintWebViewHelper::FinalizePrintReadyDocument() {
DCHECK(!is_print_ready_metafile_sent_);
print_preview_context_.FinalizePrintReadyDocument();
// Get the size of the resulting metafile.
PdfMetafileSkia* metafile = print_preview_context_.metafile();
uint32 buf_size = metafile->GetDataSize();
DCHECK_GT(buf_size, 0u);
PrintHostMsg_DidPreviewDocument_Params preview_params;
preview_params.data_size = buf_size;
preview_params.document_cookie = print_pages_params_->params.document_cookie;
preview_params.expected_pages_count =
print_preview_context_.total_page_count();
preview_params.modifiable = print_preview_context_.IsModifiable();
preview_params.preview_request_id =
print_pages_params_->params.preview_request_id;
// Ask the browser to create the shared memory for us.
if (!CopyMetafileDataToSharedMem(metafile,
&(preview_params.metafile_data_handle))) {
LOG(ERROR) << "CopyMetafileDataToSharedMem failed";
print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
return false;
}
is_print_ready_metafile_sent_ = true;
Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params));
return true;
}
void PrintWebViewHelper::PrintNode(const blink::WebNode& node) {
if (node.isNull() || !node.document().frame()) {
// This can occur when the context menu refers to an invalid WebNode.
@@ -786,6 +909,15 @@ void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) {
Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie));
}
break;
case FAIL_PREVIEW:
LOG(ERROR) << "PREVIEW FAILED.";
if (print_pages_params_) {
Send(new PrintHostMsg_PrintPreviewFailed(routing_id(),
print_pages_params_->params.document_cookie,
print_pages_params_->params.preview_request_id));
}
break;
}
prep_frame_view_.reset();
print_pages_params_.reset();
@@ -916,6 +1048,68 @@ bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame,
return true;
}
bool PrintWebViewHelper::UpdatePrintSettings(
blink::WebLocalFrame* frame,
const blink::WebNode& node,
const base::DictionaryValue& passed_job_settings) {
const base::DictionaryValue* job_settings = &passed_job_settings;
base::DictionaryValue modified_job_settings;
if (job_settings->empty()) {
if (!print_for_preview_)
print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
return false;
}
bool source_is_html = true;
if (print_for_preview_) {
if (!job_settings->GetBoolean(kSettingPreviewModifiable, &source_is_html)) {
NOTREACHED();
}
} else {
source_is_html = !PrintingNodeOrPdfFrame(frame, node);
}
if (print_for_preview_ || !source_is_html) {
modified_job_settings.MergeDictionary(job_settings);
modified_job_settings.SetBoolean(kSettingHeaderFooterEnabled, false);
modified_job_settings.SetInteger(kSettingMarginsType, NO_MARGINS);
job_settings = &modified_job_settings;
}
// Send the cookie so that UpdatePrintSettings can reuse PrinterQuery when
// possible.
int cookie =
print_pages_params_ ? print_pages_params_->params.document_cookie : 0;
PrintMsg_PrintPages_Params settings;
bool canceled = false;
Send(new PrintHostMsg_UpdatePrintSettings(routing_id(), cookie, *job_settings,
&settings, &canceled));
if (canceled) {
notify_browser_of_print_failure_ = false;
return false;
}
if (!print_for_preview_) {
job_settings->GetInteger(kPreviewRequestID,
&settings.params.preview_request_id);
settings.params.print_to_pdf = true;
UpdateFrameMarginsCssInfo(*job_settings);
settings.params.print_scaling_option =
blink::WebPrintScalingOptionSourceSize;
}
SetPrintPagesParams(settings);
if (!PrintMsg_Print_Params_IsValid(settings.params)) {
if (!print_for_preview_)
print_preview_context_.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS);
return false;
}
return true;
}
bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame* frame,
const blink::WebNode& node,
int expected_pages_count) {
@@ -987,4 +1181,264 @@ void PrintWebViewHelper::SetPrintPagesParams(
print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));
}
bool PrintWebViewHelper::PreviewPageRendered(int page_number,
PdfMetafileSkia* metafile) {
DCHECK_GE(page_number, FIRST_PAGE_INDEX);
// For non-modifiable files, |metafile| should be NULL, so do not bother
// sending a message. If we don't generate draft metafiles, |metafile| is
// NULL.
if (!print_preview_context_.IsModifiable() ||
!print_preview_context_.generate_draft_pages()) {
DCHECK(!metafile);
return true;
}
if (!metafile) {
NOTREACHED();
print_preview_context_.set_error(
PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE);
return false;
}
return true;
}
PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
: total_page_count_(0),
current_page_index_(0),
generate_draft_pages_(true),
print_ready_metafile_page_count_(0),
error_(PREVIEW_ERROR_NONE),
state_(UNINITIALIZED) {
}
PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() {
}
void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
blink::WebLocalFrame* web_frame) {
DCHECK(web_frame);
DCHECK(!IsRendering());
state_ = INITIALIZED;
source_frame_.Reset(web_frame);
source_node_.reset();
}
void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
const blink::WebNode& web_node) {
DCHECK(!web_node.isNull());
DCHECK(web_node.document().frame());
DCHECK(!IsRendering());
state_ = INITIALIZED;
source_frame_.Reset(web_node.document().frame());
source_node_ = web_node;
}
void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
DCHECK_EQ(INITIALIZED, state_);
ClearContext();
}
bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
PrepareFrameAndViewForPrint* prepared_frame,
const std::vector<int>& pages) {
DCHECK_EQ(INITIALIZED, state_);
state_ = RENDERING;
// Need to make sure old object gets destroyed first.
prep_frame_view_.reset(prepared_frame);
prep_frame_view_->StartPrinting();
total_page_count_ = prep_frame_view_->GetExpectedPageCount();
if (total_page_count_ == 0) {
LOG(ERROR) << "CreatePreviewDocument got 0 page count";
set_error(PREVIEW_ERROR_ZERO_PAGES);
return false;
}
metafile_.reset(new PdfMetafileSkia);
if (!metafile_->Init()) {
set_error(PREVIEW_ERROR_METAFILE_INIT_FAILED);
LOG(ERROR) << "PdfMetafileSkia Init failed";
return false;
}
current_page_index_ = 0;
pages_to_render_ = pages;
// Sort and make unique.
std::sort(pages_to_render_.begin(), pages_to_render_.end());
pages_to_render_.resize(
std::unique(pages_to_render_.begin(), pages_to_render_.end()) -
pages_to_render_.begin());
// Remove invalid pages.
pages_to_render_.resize(std::lower_bound(pages_to_render_.begin(),
pages_to_render_.end(),
total_page_count_) -
pages_to_render_.begin());
print_ready_metafile_page_count_ = pages_to_render_.size();
if (pages_to_render_.empty()) {
print_ready_metafile_page_count_ = total_page_count_;
// Render all pages.
for (int i = 0; i < total_page_count_; ++i)
pages_to_render_.push_back(i);
} else if (generate_draft_pages_) {
int pages_index = 0;
for (int i = 0; i < total_page_count_; ++i) {
if (pages_index < print_ready_metafile_page_count_ &&
i == pages_to_render_[pages_index]) {
pages_index++;
continue;
}
pages_to_render_.push_back(i);
}
}
document_render_time_ = base::TimeDelta();
begin_time_ = base::TimeTicks::Now();
return true;
}
void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage(
const base::TimeDelta& page_time) {
DCHECK_EQ(RENDERING, state_);
document_render_time_ += page_time;
UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time);
}
void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() {
DCHECK_EQ(RENDERING, state_);
state_ = DONE;
prep_frame_view_->FinishPrinting();
}
void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
DCHECK(IsRendering());
base::TimeTicks begin_time = base::TimeTicks::Now();
metafile_->FinishDocument();
if (print_ready_metafile_page_count_ <= 0) {
NOTREACHED();
return;
}
UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime",
document_render_time_);
base::TimeDelta total_time =
(base::TimeTicks::Now() - begin_time) + document_render_time_;
UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime",
total_time);
UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage",
total_time / pages_to_render_.size());
}
void PrintWebViewHelper::PrintPreviewContext::Finished() {
DCHECK_EQ(DONE, state_);
state_ = INITIALIZED;
ClearContext();
}
void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error) {
DCHECK(state_ == INITIALIZED || state_ == RENDERING);
state_ = INITIALIZED;
if (report_error) {
DCHECK_NE(PREVIEW_ERROR_NONE, error_);
UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_,
PREVIEW_ERROR_LAST_ENUM);
}
ClearContext();
}
int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() {
DCHECK_EQ(RENDERING, state_);
if (IsFinalPageRendered())
return -1;
return pages_to_render_[current_page_index_++];
}
bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const {
return state_ == RENDERING || state_ == DONE;
}
bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() {
// The only kind of node we can print right now is a PDF node.
return !PrintingNodeOrPdfFrame(source_frame(), source_node_);
}
bool PrintWebViewHelper::PrintPreviewContext::HasSelection() {
return IsModifiable() && source_frame()->hasSelection();
}
bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile()
const {
DCHECK(IsRendering());
return current_page_index_ == print_ready_metafile_page_count_;
}
bool PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const {
DCHECK(IsRendering());
return static_cast<size_t>(current_page_index_) == pages_to_render_.size();
}
void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages(
bool generate_draft_pages) {
DCHECK_EQ(INITIALIZED, state_);
generate_draft_pages_ = generate_draft_pages;
}
void PrintWebViewHelper::PrintPreviewContext::set_error(
enum PrintPreviewErrorBuckets error) {
error_ = error;
}
blink::WebLocalFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() {
DCHECK(state_ != UNINITIALIZED);
return source_frame_.GetFrame();
}
const blink::WebNode&
PrintWebViewHelper::PrintPreviewContext::source_node() const {
DCHECK(state_ != UNINITIALIZED);
return source_node_;
}
blink::WebLocalFrame*
PrintWebViewHelper::PrintPreviewContext::prepared_frame() {
DCHECK(state_ != UNINITIALIZED);
return prep_frame_view_->frame();
}
const blink::WebNode&
PrintWebViewHelper::PrintPreviewContext::prepared_node() const {
DCHECK(state_ != UNINITIALIZED);
return prep_frame_view_->node();
}
int PrintWebViewHelper::PrintPreviewContext::total_page_count() const {
DCHECK(state_ != UNINITIALIZED);
return total_page_count_;
}
bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() const {
return generate_draft_pages_;
}
PdfMetafileSkia* PrintWebViewHelper::PrintPreviewContext::metafile() {
DCHECK(IsRendering());
return metafile_.get();
}
int PrintWebViewHelper::PrintPreviewContext::last_error() const {
return error_;
}
void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
prep_frame_view_.reset();
metafile_.reset();
pages_to_render_.clear();
error_ = PREVIEW_ERROR_NONE;
}
} // namespace printing

View File

@@ -76,6 +76,19 @@ class PrintWebViewHelper
OK,
FAIL_PRINT_INIT,
FAIL_PRINT,
FAIL_PREVIEW,
};
enum PrintPreviewErrorBuckets {
PREVIEW_ERROR_NONE, // Always first.
PREVIEW_ERROR_BAD_SETTING,
PREVIEW_ERROR_METAFILE_COPY_FAILED,
PREVIEW_ERROR_METAFILE_INIT_FAILED,
PREVIEW_ERROR_ZERO_PAGES,
PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED,
PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE,
PREVIEW_ERROR_INVALID_PRINTER_SETTINGS,
PREVIEW_ERROR_LAST_ENUM // Always last.
};
// RenderViewObserver implementation.
@@ -88,6 +101,8 @@ class PrintWebViewHelper
void OnPrintPages(bool silent, bool print_background);
void OnPrintingDone(bool success);
#endif // !DISABLE_BASIC_PRINTING
void OnPrintPreview(const base::DictionaryValue& settings);
// Get |page_size| and |content_area| information from
// |page_layout_in_points|.
@@ -99,6 +114,24 @@ class PrintWebViewHelper
// Update |ignore_css_margins_| based on settings.
void UpdateFrameMarginsCssInfo(const base::DictionaryValue& settings);
// Prepare frame for creating preview document.
void PrepareFrameForPreviewDocument();
// Continue creating preview document.
void OnFramePreparedForPreviewDocument();
// Finalize the print ready preview document.
bool FinalizePrintReadyDocument();
// Renders a print preview page. |page_number| is 0-based.
// Returns true if print preview should continue, false on failure.
bool RenderPreviewPage(int page_number,
const PrintMsg_Print_Params& print_params);
// Initialize the print preview document.
bool CreatePreviewDocument();
// Main printing code -------------------------------------------------------
void Print(blink::WebLocalFrame* frame,
@@ -120,6 +153,14 @@ class PrintWebViewHelper
const blink::WebNode& node,
int* number_of_pages);
// Update the current print settings with new |passed_job_settings|.
// |passed_job_settings| dictionary contains print job details such as printer
// name, number of copies, page range, etc.
bool UpdatePrintSettings(blink::WebLocalFrame* frame,
const blink::WebNode& node,
const base::DictionaryValue& passed_job_settings);
// Get final print settings from the user.
// Return false if the user cancels or on error.
bool GetPrintSettingsFromUser(blink::WebFrame* frame,
@@ -193,6 +234,13 @@ class PrintWebViewHelper
// Script Initiated Printing ------------------------------------------------
// Notifies the browser a print preview page has been rendered.
// |page_number| is 0-based.
// For a valid |page_number| with modifiable content,
// |metafile| is the rendered page. Otherwise |metafile| is NULL.
// Returns true if print preview should continue, false on failure.
bool PreviewPageRendered(int page_number, PdfMetafileSkia* metafile);
void SetPrintPagesParams(const PrintMsg_PrintPages_Params& settings);
// WebView used only to print the selection.
@@ -213,10 +261,121 @@ class PrintWebViewHelper
// True, when printing from print preview.
bool print_for_preview_;
// Keeps track of the state of print preview between messages.
// TODO(vitalybuka): Create PrintPreviewContext when needed and delete after
// use. Now it's interaction with various messages is confusing.
class PrintPreviewContext {
public:
PrintPreviewContext();
~PrintPreviewContext();
// Initializes the print preview context. Need to be called to set
// the |web_frame| / |web_node| to generate the print preview for.
void InitWithFrame(blink::WebLocalFrame* web_frame);
void InitWithNode(const blink::WebNode& web_node);
// Does bookkeeping at the beginning of print preview.
void OnPrintPreview();
// Create the print preview document. |pages| is empty to print all pages.
// Takes ownership of |prepared_frame|.
bool CreatePreviewDocument(PrepareFrameAndViewForPrint* prepared_frame,
const std::vector<int>& pages);
// Called after a page gets rendered. |page_time| is how long the
// rendering took.
void RenderedPreviewPage(const base::TimeDelta& page_time);
// Updates the print preview context when the required pages are rendered.
void AllPagesRendered();
// Finalizes the print ready preview document.
void FinalizePrintReadyDocument();
// Cleanup after print preview finishes.
void Finished();
// Cleanup after print preview fails.
void Failed(bool report_error);
// Helper functions
int GetNextPageNumber();
bool IsRendering() const;
bool IsModifiable();
bool HasSelection();
bool IsLastPageOfPrintReadyMetafile() const;
bool IsFinalPageRendered() const;
// Setters
void set_generate_draft_pages(bool generate_draft_pages);
void set_error(enum PrintPreviewErrorBuckets error);
// Getters
// Original frame for which preview was requested.
blink::WebLocalFrame* source_frame();
// Original node for which preview was requested.
const blink::WebNode& source_node() const;
// Frame to be use to render preview. May be the same as source_frame(), or
// generated from it, e.g. copy of selected block.
blink::WebLocalFrame* prepared_frame();
// Node to be use to render preview. May be the same as source_node(), or
// generated from it, e.g. copy of selected block.
const blink::WebNode& prepared_node() const;
int total_page_count() const;
bool generate_draft_pages() const;
PdfMetafileSkia* metafile();
int last_error() const;
private:
enum State {
UNINITIALIZED, // Not ready to render.
INITIALIZED, // Ready to render.
RENDERING, // Rendering.
DONE // Finished rendering.
};
// Reset some of the internal rendering context.
void ClearContext();
// Specifies what to render for print preview.
FrameReference source_frame_;
blink::WebNode source_node_;
scoped_ptr<PrepareFrameAndViewForPrint> prep_frame_view_;
scoped_ptr<PdfMetafileSkia> metafile_;
// Total page count in the renderer.
int total_page_count_;
// The current page to render.
int current_page_index_;
// List of page indices that need to be rendered.
std::vector<int> pages_to_render_;
// True, when draft pages needs to be generated.
bool generate_draft_pages_;
// Specifies the total number of pages in the print ready metafile.
int print_ready_metafile_page_count_;
base::TimeDelta document_render_time_;
base::TimeTicks begin_time_;
enum PrintPreviewErrorBuckets error_;
State state_;
};
bool print_node_in_progress_;
bool is_loading_;
bool is_scripted_preview_delayed_;
PrintPreviewContext print_preview_context_;
// Used to fix a race condition where the source is a PDF and print preview
// hangs because RequestPrintPreview is called before DidStopLoading() is
// called. This is a store for the RequestPrintPreview() call and its

View File

@@ -24,6 +24,36 @@ namespace printing {
using blink::WebFrame;
bool PrintWebViewHelper::RenderPreviewPage(
int page_number,
const PrintMsg_Print_Params& print_params) {
PrintMsg_PrintPage_Params page_params;
page_params.params = print_params;
page_params.page_number = page_number;
scoped_ptr<PdfMetafileSkia> draft_metafile;
PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) {
draft_metafile.reset(new PdfMetafileSkia);
initial_render_metafile = draft_metafile.get();
}
base::TimeTicks begin_time = base::TimeTicks::Now();
PrintPageInternal(page_params,
print_preview_context_.prepared_frame(),
initial_render_metafile);
print_preview_context_.RenderedPreviewPage(
base::TimeTicks::Now() - begin_time);
if (draft_metafile.get()) {
draft_metafile->FinishDocument();
} else if (print_preview_context_.IsModifiable() &&
print_preview_context_.generate_draft_pages()) {
DCHECK(!draft_metafile.get());
draft_metafile =
print_preview_context_.metafile()->GetMetafileForCurrentPage();
}
return PreviewPageRendered(page_number, draft_metafile.get());
}
bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
int page_count) {
PdfMetafileSkia metafile;

View File

@@ -50,6 +50,47 @@ void PrintWebViewHelper::PrintPageInternal(
Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params));
}
bool PrintWebViewHelper::RenderPreviewPage(
int page_number,
const PrintMsg_Print_Params& print_params) {
PrintMsg_Print_Params printParams = print_params;
scoped_ptr<PdfMetafileSkia> draft_metafile;
PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
bool render_to_draft = print_preview_context_.IsModifiable() &&
is_print_ready_metafile_sent_;
if (render_to_draft) {
draft_metafile.reset(new PdfMetafileSkia());
if (!draft_metafile->Init()) {
print_preview_context_.set_error(
PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED);
LOG(ERROR) << "Draft PdfMetafileSkia Init failed";
return false;
}
initial_render_metafile = draft_metafile.get();
}
base::TimeTicks begin_time = base::TimeTicks::Now();
gfx::Size page_size;
RenderPage(printParams, page_number, print_preview_context_.prepared_frame(),
true, initial_render_metafile, &page_size, NULL);
print_preview_context_.RenderedPreviewPage(
base::TimeTicks::Now() - begin_time);
if (draft_metafile.get()) {
draft_metafile->FinishDocument();
} else {
if (print_preview_context_.IsModifiable() &&
print_preview_context_.generate_draft_pages()) {
DCHECK(!draft_metafile.get());
draft_metafile =
print_preview_context_.metafile()->GetMetafileForCurrentPage();
}
}
return PreviewPageRendered(page_number, draft_metafile.get());
}
void PrintWebViewHelper::RenderPage(const PrintMsg_Print_Params& params,
int page_number,
WebFrame* frame,

View File

@@ -21,7 +21,6 @@ namespace printing {
using blink::WebFrame;
#if 0
bool PrintWebViewHelper::RenderPreviewPage(
int page_number,
const PrintMsg_Print_Params& print_params) {
@@ -53,7 +52,6 @@ bool PrintWebViewHelper::RenderPreviewPage(
}
return PreviewPageRendered(page_number, draft_metafile.get());
}
#endif
bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
int page_count) {

View File

@@ -62,9 +62,12 @@ Emitted when application is quitting.
* `event` Event
* `path` String
Emitted when user wants to open a file with the application, it usually
happens when the application is already opened and then OS wants to reuse the
application to open file.
Emitted when user wants to open a file with the application, it usually happens
when the application is already opened and then OS wants to reuse the
application to open file. But it is also emitted when a file is dropped onto the
dock and the application is not yet running. Make sure to listen to open-file
very early in your application startup to handle this case (even before the
`ready` event is emitted).
You should call `event.preventDefault()` if you want to handle this event.

View File

@@ -556,20 +556,11 @@ process.
### BrowserWindow.print([options])
* `options` Object
* `silent` Boolean - Don't ask user for print settings, defaults to `false`
* `printBackground` Boolean - Also prints the background color and image of
the web page, defaults to `false`.
Same with `webContents.print([options])`
Prints window's web page. When `silent` is set to `false`, Electron will pick
up system's default printer and default settings for printing.
### BrowserWindow.printToPDF(options, callback)
Calling `window.print()` in web page is equivalent to call
`BrowserWindow.print({silent: false, printBackground: false})`.
**Note:** On Windows, the print API relies on `pdf.dll`. If your application
doesn't need print feature, you can safely remove `pdf.dll` in saving binary
size.
Same with `webContents.printToPDF(options, callback)`
### BrowserWindow.loadUrl(url, [options])
@@ -877,6 +868,16 @@ Injects CSS into this page.
Evaluates `code` in page.
### WebContents.setAudioMuted(muted)
+ `muted` Boolean
Set the page muted.
### WebContents.isAudioMuted()
Returns whether this page has been muted.
### WebContents.undo()
Executes editing command `undo` in page.
@@ -940,6 +941,45 @@ 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.print([options])
* `options` Object
* `silent` Boolean - Don't ask user for print settings, defaults to `false`
* `printBackground` Boolean - Also prints the background color and image of
the web page, defaults to `false`.
Prints window's web page. When `silent` is set to `false`, Electron will pick
up system's default printer and default settings for printing.
Calling `window.print()` in web page is equivalent to call
`WebContents.print({silent: false, printBackground: false})`.
**Note:** On Windows, the print API relies on `pdf.dll`. If your application
doesn't need print feature, you can safely remove `pdf.dll` in saving binary
size.
### WebContents.printToPDF(options, callback)
* `options` Object
* `marginsType` Integer - Specify the type of margins to use
* 0 - default
* 1 - none
* 2 - minimum
* `printBackground` Boolean - Whether to print CSS backgrounds.
* `printSelectionOnly` Boolean - Whether to print selection only.
* `landscape` Boolean - `true` for landscape, `false` for portrait.
* `callback` Function - `function(error, data) {}`
* `error` Error
* `data` Buffer - PDF file content
Prints windows' web page as PDF with Chromium's preview printing custom
settings.
By default, the options will be
`{marginsType:0, printBackgrounds:false, printSelectionOnly:false,
landscape:false}`.
### WebContents.send(channel[, args...])
* `channel` String

View File

@@ -19,6 +19,10 @@ app.on('ready', function() {
Sets `path` of client certificate file.
## --ignore-connections-limit=`domains`
Ignore the connections limit for `domains` list seperated by `,`.
## --disable-http-cache
Disables the disk cache for HTTP requests.

View File

@@ -84,12 +84,21 @@ Create a request job which sends a string as response.
Create a request job which sends a buffer as response.
## Class: protocol.RequestHttpJob(options)
* `options` Object
* `url` String
* `method` String - Default is `GET`
* `referrer` String
Send a request to `url` and pipe the response back.
## 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
Default message is `net::ERR_NOT_IMPLEMENTED`. Code should be in the following
range.
* Ranges:

View File

@@ -96,7 +96,7 @@ Sets the `image` associated with this tray icon.
* `image` [NativeImage](native-image.md)
Sets the `image` associated with this tray icon when pressed.
Sets the `image` associated with this tray icon when pressed on OS X.
### Tray.setToolTip(toolTip)

View File

@@ -130,6 +130,14 @@ If "on", the guest page will have web security disabled.
## Methods
The webview element must be loaded before using the methods.
**Example**
```javascript
webview.addEventListener("dom-ready", function(){
webview.openDevTools();
});
```
### `<webview>`.getUrl()
Returns URL of guest page.
@@ -242,6 +250,16 @@ Starts inspecting element at position (`x`, `y`) of guest page.
Opens the devtools for the service worker context present in the guest page.
### `<webview>`.setAudioMuted(muted)
+ `muted` Boolean
Set guest page muted.
### `<webview>`.isAudioMuted()
Returns whether guest page has been muted.
### `<webview>`.undo()
Executes editing command `undo` in page.
@@ -290,6 +308,14 @@ Executes editing command `replace` in page.
Executes editing command `replaceMisspelling` in page.
### `<webview>.print([options])`
Prints webview's web page. Same with `webContents.print([options])`.
### `<webview>.printToPDF(options, callback)`
Prints webview's web page as PDF, Same with `webContents.printToPDF(options, callback)`
### `<webview>`.send(channel[, args...])
* `channel` String

View File

@@ -106,26 +106,8 @@ You can rename the `electron` executable to any name you like.
## Rebranding by rebuilding Electron from source
It is also possible to rebrand Electron by changing the product name and
building it from source. To do this you need to override the `GYP_DEFINES`
environment variable and have a clean rebuild:
__Windows__
```bash
> set "GYP_DEFINES=project_name=myapp product_name=MyApp"
> python script\clean.py
> python script\bootstrap.py
> python script\build.py -c R -t myapp
```
__Bash__
```bash
$ export GYP_DEFINES="project_name=myapp product_name=MyApp"
$ script/clean.py
$ script/bootstrap.py
$ script/build.py -c Release -t myapp
```
building it from source. To do this you need to modify the `atom.gyp` file and
have a clean rebuild.
### grunt-build-atom-shell

View File

@@ -1,17 +1,17 @@
# Desktop environment integration
Different operating systems provide different features on integrating desktop
applications into their desktop environments, for example, on Windows
applications into their desktop environments. For example, on Windows
applications can put shortcuts in the JumpList of task bar, and on Mac
applications can put a custom menu in the dock menu.
This guide introduces how to integrate your application into those desktop
This guide explains how to integrate your application into those desktop
environments with Electron APIs.
## Recent documents (Windows & OS X)
Windows and OS X have provided easy access to recent documents opened by the
application via JumpList and dock menu.
Windows and OS X provide easy access to a list of recent documents opened by
the application via JumpList and dock menu.
__JumpList:__
@@ -39,12 +39,12 @@ app.clearRecentDocuments();
### Windows notes
In order to be able to use this feature on Windows, your application has to be
registered as handler of the file type of the document, otherwise the file won't
appear in JumpList even after you have added it. You can find everything on
registering your application in [Application Registration][app-registration].
registered as a handler of the file type of the document, otherwise the file
won't appear in JumpList even after you have added it. You can find everything
on registering your application in [Application Registration][app-registration].
When a user clicks a file from JumpList, a new instance of your application will
be started with the path of file appended in command line.
be started with the path of the file added as a command line argument.
### OS X notes
@@ -53,7 +53,7 @@ of `app` module would be emitted for it.
## Custom dock menu (OS X)
OS X enables developers to specify a custom menu for dock, which usually
OS X enables developers to specify a custom menu for the dock, which usually
contains some shortcuts for commonly used features of your application:
__Dock menu of Terminal.app:__
@@ -104,7 +104,7 @@ __Tasks of Internet Explorer:__
![IE](http://i.msdn.microsoft.com/dynimg/IC420539.png)
Unlike the dock menu in OS X which is a real menu, user tasks in Windows work
like application shortcuts that when user clicks a task a program would be
like application shortcuts that when user clicks a task, a program would be
executed with specified arguments.
To set user tasks for your application, you can use
@@ -146,7 +146,7 @@ __Launcher shortcuts of Audacious:__
## Progress bar in taskbar (Windows & Unity)
On Windows, a taskbar button can be used to display a progress bar. This enables
a window to provide progress information to the user without that user having to
a window to provide progress information to the user without the user having to
switch to the window itself.
The Unity DE also has a similar feature that allows you to specify the progress
@@ -171,11 +171,11 @@ window.setProgressBar(0.5);
## Represented file of window (OS X)
On OS X a window can set its represented file, so the file's icon can show in
title bar, and when users Command-Click or Control-Click on the tile a path
the title bar, and when users Command-Click or Control-Click on the tile a path
popup will show.
You can also set edited state of a window so the file icon can indicate whether
the document in this window has been modified.
You can also set the edited state of a window so that the file icon can indicate
whether the document in this window has been modified.
__Represented file popup menu:__

View File

@@ -0,0 +1,131 @@
# クイックスタート
## 導入
ElectronではリッチなネイティブAPIを持ったランタイムを提供することによってピュアなJavaScriptでデスクトップアプリケーションをつくることができます。ウェブサーバーの代わりにデスクトップアプリケーションに焦点をあてたio.jsランタイムであるといえばわかりやすいかもしれません。
ElectronはJavaScriptをGUIライブラリにバインディングしません。その代わりに、ElectronはウェブページをGUIとして使用します。なのでElectronはJavaScriptによってコントロールされる最小のChromiumブラウザでもあるともいえます。
### メインプロセス
Electronでは、`package.json``main`で実行されるプロセスを __メインプロセス__ と呼びます。メインスクリプトではGUIにウェブページを表示することができるプロセスを実行します。
### レンダラープロセス
Electronはウェブページを表示させるためにChromiumを使用しているので、Chromiumのマルチプロセスアーキテクチャが使用されることになります。Electronで実行されるウェブページはそれぞれ自身のプロセスで実行されます。それを __レンダラープロセス__ と呼びます。
通常、ブラウザのウェブページはサウンドボックス環境で実行されネイティブなリソースへのアクセスができません。Electronではウェブページからio.jsのAPIを使って、ネイティブリソースへの権限が与えられます。そのおかげでウェブページの中からJavaScriptを使って低レベルなオペレーティングシステムとのインタラクションが可能になります。
### メインプロセスとリレンダラープロセスの違い
メインプロセスは `BrowserWindow` インスタンスを作ることによってウェブページをつくります。それぞれの `BrowserWindow` インスタンスはそれ自身の リレンダラープロセス上でウェブページを実行します。`BrowserWindow` インスタンスが破棄されると、対応するリレンダラープロセスも終了されます。
メインプロセスはすべてのウェブページとそれに対応するリレンダラープロセスを管理しています。それぞれのリレンダラープロセスは分離しているのでウェブページで実行されていることだけを気に留めておいてください。
ウェブページでは、GUI関連のAPIを呼ぶことはできません。なぜならば、ウェブページで管理しているネイティブのGUIリソースは非常に危険で簡単にリークしてしまうからです。もしウェブページ内でGUIを操作したい場合には、メインプロセスと通信をする必要があります。
Electronでは、メインプロセスとリレンダラープロセスとのコミュニケーションをするために[ipc](../api/ipc-renderer.md)モジュールを提供しています。またそれと、RPC形式の通信を行う[remote](../api/remote.md)モジュールもあります。
## Electronアプリを作成する
一般的に Electronアプリの構成は次のようになります
```text
your-app/
├── package.json
├── main.js
└── index.html
```
`package.json`の形式はNodeモジュールとまったく同じです。 `main` フィールドでアプリを起動するためのスクリプトを特定し、メインプロセスで実行します。 `package.json`の例は次のようになります:
```json
{
"name" : "your-app",
"version" : "0.1.0",
"main" : "main.js"
}
```
`main.js` ではウィンドウを作成してシステムイベントを管理します。典型的な例は次のようになります:
```javascript
var app = require('app'); // Module to control application life.
var BrowserWindow = require('browser-window'); // Module to create native browser window.
// Report crashes to our server.
require('crash-reporter').start();
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is GCed.
var mainWindow = null;
// Quit when all windows are closed.
app.on('window-all-closed', function() {
if (process.platform != 'darwin') {
app.quit();
}
});
// 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.
mainWindow = new BrowserWindow({width: 800, height: 600});
// and load the index.html of the app.
mainWindow.loadUrl('file://' + __dirname + '/index.html');
// Open the devtools.
mainWindow.openDevTools();
// Emitted when the window is closed.
mainWindow.on('closed', function() {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
});
```
最後に表示するウェブページ`index.html`は次のようになります:
```html
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using io.js <script>document.write(process.version)</script>
and Electron <script>document.write(process.versions['electron'])</script>.
</body>
</html>
```
## アプリを実行する
アプリケーションを作り終えたら、[Application distribution](./application-distribution.md)ガイドにしたがってディストリビューションを作成します、そしてパッケージされたアプリケーションとして配布することが可能です。またダウンロードしたElectronのバイナリをアプリケーション・ディレクトリを実行するために利用することもできます。
Windowsの場合
```bash
$ .\electron\electron.exe your-app\
```
Linuxの場合
```bash
$ ./electron/electron your-app/
```
OS Xの場合
```bash
$ ./Electron.app/Contents/MacOS/Electron your-app/
```
`Electron.app` はElectronのリリースパッケージに含まれており、[ここ](https://github.com/atom/electron/releases) からダウンロードできます。

View File

@@ -147,11 +147,13 @@
'atom/browser/net/atom_url_request_job_factory.cc',
'atom/browser/net/atom_url_request_job_factory.h',
'atom/browser/net/http_protocol_handler.cc',
'atom/browser/net/http_protocol_handler.h',
'atom/browser/net/http_protocol_handler.h',
'atom/browser/net/url_request_string_job.cc',
'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/net/url_request_fetch_job.cc',
'atom/browser/net/url_request_fetch_job.h',
'atom/browser/ui/accelerator_util.cc',
'atom/browser/ui/accelerator_util.h',
'atom/browser/ui/accelerator_util_mac.mm',
@@ -314,6 +316,8 @@
'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/printing/print_preview_message_handler.cc',
'chromium_src/chrome/browser/printing/print_preview_message_handler.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',

View File

@@ -1,5 +1,6 @@
assert = require 'assert'
ipc = require 'ipc'
http = require 'http'
path = require 'path'
remote = require 'remote'
protocol = remote.require 'protocol'
@@ -73,6 +74,28 @@ describe 'protocol module', ->
protocol.unregisterProtocol 'atom-error-job'
done()
it 'returns RequestHttpJob should send respone', (done) ->
server = http.createServer (req, res) ->
res.writeHead(200, {'Content-Type': 'text/plain'})
res.end('hello')
server.close()
server.listen 0, '127.0.0.1', ->
{port} = server.address()
url = "http://127.0.0.1:#{port}"
job = new protocol.RequestHttpJob({url})
handler = remote.createFunctionWithReturnValue job
protocol.registerProtocol 'atom-http-job', handler
$.ajax
url: 'atom-http-job://fake-host'
success: (data) ->
assert.equal data, 'hello'
protocol.unregisterProtocol 'atom-http-job'
done()
error: (xhr, errorType, error) ->
assert false, 'Got error: ' + errorType + ' ' + error
protocol.unregisterProtocol 'atom-http-job'
it 'returns RequestBufferJob should send buffer', (done) ->
data = new Buffer("hello")
job = new protocol.RequestBufferJob(data: data)