blob: 69c66e4d496206be2dd53ad7740b4579813116cd [file] [log] [blame]
[email protected]80a8fad2011-01-29 04:02:381// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]73852b8f2010-05-14 00:38:122// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/printing/print_dialog_cloud.h"
6#include "chrome/browser/printing/print_dialog_cloud_internal.h"
7
[email protected]73852b8f2010-05-14 00:38:128#include "base/base64.h"
[email protected]ba4fc242011-10-04 18:56:569#include "base/bind.h"
10#include "base/bind_helpers.h"
[email protected]65c9d89a2011-04-13 21:02:3911#include "base/command_line.h"
[email protected]73852b8f2010-05-14 00:38:1212#include "base/file_util.h"
13#include "base/json/json_reader.h"
[email protected]4b8852a2011-06-10 17:24:4614#include "base/utf_string_conversions.h"
[email protected]73852b8f2010-05-14 00:38:1215#include "base/values.h"
[email protected]0744cc72011-08-12 12:05:4516#include "chrome/browser/browser_process_impl.h"
[email protected]dce502762011-07-20 08:53:4917#include "chrome/browser/debugger/devtools_window.h"
[email protected]ea161da2010-11-02 21:57:3518#include "chrome/browser/prefs/pref_service.h"
[email protected]2283eead2010-09-29 23:17:3019#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
[email protected]8ecad5e2010-12-02 21:18:3320#include "chrome/browser/profiles/profile.h"
[email protected]e39027a2011-01-24 21:41:5421#include "chrome/browser/profiles/profile_manager.h"
[email protected]eb2d7902011-02-02 18:19:5622#include "chrome/browser/ui/browser_dialogs.h"
[email protected]6768ac02011-04-06 17:41:0423#include "chrome/browser/ui/browser_list.h"
[email protected]22c830d2011-11-29 20:00:3724#include "chrome/browser/ui/dialog_style.h"
[email protected]0ec4898e2011-12-30 21:09:2425#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
[email protected]65c9d89a2011-04-13 21:02:3926#include "chrome/common/chrome_switches.h"
[email protected]ea161da2010-11-02 21:57:3527#include "chrome/common/pref_names.h"
[email protected]1375e3ab2011-03-24 17:07:2228#include "chrome/common/print_messages.h"
[email protected]73852b8f2010-05-14 00:38:1229#include "chrome/common/url_constants.h"
[email protected]5f945a0e2011-03-01 17:47:5330#include "content/browser/renderer_host/render_view_host.h"
[email protected]5f945a0e2011-03-01 17:47:5331#include "content/browser/tab_contents/tab_contents_view.h"
[email protected]67fc0392011-02-25 02:56:5732#include "content/browser/webui/web_ui.h"
[email protected]c38831a12011-10-28 12:44:4933#include "content/public/browser/browser_thread.h"
[email protected]cdcb1dee2012-01-04 00:46:2034#include "content/public/browser/navigation_controller.h"
[email protected]022af742011-12-28 18:37:2535#include "content/public/browser/navigation_entry.h"
[email protected]6c2381d2011-10-19 02:52:5336#include "content/public/browser/notification_registrar.h"
37#include "content/public/browser/notification_source.h"
[email protected]0d6e9bd2011-10-18 04:29:1638#include "content/public/browser/notification_types.h"
[email protected]0ec4898e2011-12-30 21:09:2439#include "content/public/browser/web_contents.h"
[email protected]c051a1b2011-01-21 23:30:1740#include "ui/base/l10n/l10n_util.h"
[email protected]939856a2010-08-24 20:29:0241#include "webkit/glue/webpreferences.h"
[email protected]73852b8f2010-05-14 00:38:1242
43#include "grit/generated_resources.h"
44
45// This module implements the UI support in Chrome for cloud printing.
46// This means hosting a dialog containing HTML/JavaScript and using
47// the published cloud print user interface integration APIs to get
48// page setup settings from the dialog contents and provide the
[email protected]a984bdf2011-03-15 20:17:1649// generated print data to the dialog contents for uploading to the
[email protected]73852b8f2010-05-14 00:38:1250// cloud print service.
51
52// Currently, the flow between these classes is as follows:
53
[email protected]a984bdf2011-03-15 20:17:1654// PrintDialogCloud::CreatePrintDialogForFile is called from
[email protected]73852b8f2010-05-14 00:38:1255// resource_message_filter_gtk.cc once the renderer has informed the
[email protected]a984bdf2011-03-15 20:17:1656// renderer host that print data generation into the renderer host provided
[email protected]032682b2011-01-12 22:05:0257// temp file has been completed. That call is on the FILE thread.
[email protected]73852b8f2010-05-14 00:38:1258// That, in turn, hops over to the UI thread to create an instance of
59// PrintDialogCloud.
60
61// The constructor for PrintDialogCloud creates a
62// CloudPrintHtmlDialogDelegate and asks the current active browser to
63// show an HTML dialog using that class as the delegate. That class
[email protected]89f550b2011-06-08 18:34:0364// hands in the kChromeUICloudPrintResourcesURL as the URL to visit. That is
[email protected]80a8fad2011-01-29 04:02:3865// recognized by the GetWebUIFactoryFunction as a signal to create an
[email protected]73852b8f2010-05-14 00:38:1266// ExternalHtmlDialogUI.
67
68// CloudPrintHtmlDialogDelegate also temporarily owns a
69// CloudPrintFlowHandler, a class which is responsible for the actual
[email protected]a984bdf2011-03-15 20:17:1670// interactions with the dialog contents, including handing in the
[email protected]73852b8f2010-05-14 00:38:1271// print data and getting any page setup parameters that the dialog
72// contents provides. As part of bringing up the dialog,
73// HtmlDialogUI::RenderViewCreated is called (an override of
[email protected]c39f9bf2011-02-12 00:43:5574// WebUI::RenderViewCreated). That routine, in turn, calls the
[email protected]36e12172011-02-08 23:46:0275// delegate's GetWebUIMessageHandlers routine, at which point the
[email protected]73852b8f2010-05-14 00:38:1276// ownership of the CloudPrintFlowHandler is handed over. A pointer
77// to the flow handler is kept to facilitate communication back and
78// forth between the two classes.
79
[email protected]c39f9bf2011-02-12 00:43:5580// The WebUI continues dialog bring-up, calling
[email protected]73852b8f2010-05-14 00:38:1281// CloudPrintFlowHandler::RegisterMessages. This is where the
82// additional object model capabilities are registered for the dialog
83// contents to use. It is also at this time that capabilities for the
84// dialog contents are adjusted to allow the dialog contents to close
85// the window. In addition, the pending URL is redirected to the
86// actual cloud print service URL. The flow controller also registers
87// for notification of when the dialog contents finish loading, which
[email protected]a984bdf2011-03-15 20:17:1688// is currently used to send the data to the dialog contents.
[email protected]73852b8f2010-05-14 00:38:1289
[email protected]a984bdf2011-03-15 20:17:1690// In order to send the data to the dialog contents, the flow
[email protected]73852b8f2010-05-14 00:38:1291// handler uses a CloudPrintDataSender. It creates one, letting it
[email protected]a984bdf2011-03-15 20:17:1692// know the name of the temporary file containing the data, and
[email protected]73852b8f2010-05-14 00:38:1293// posts the task of reading the file
94// (CloudPrintDataSender::ReadPrintDataFile) to the file thread. That
95// routine reads in the file, and then hops over to the IO thread to
96// send that data to the dialog contents.
97
98// When the dialog contents are finished (by either being cancelled or
99// hitting the print button), the delegate is notified, and responds
100// that the dialog should be closed, at which point things are torn
101// down and released.
102
103// TODO(scottbyer):
104// http://code.google.com/p/chromium/issues/detail?id=44093 The
[email protected]a984bdf2011-03-15 20:17:16105// high-level flow (where the data is generated before even
[email protected]73852b8f2010-05-14 00:38:12106// bringing up the dialog) isn't what we want.
107
[email protected]631bb742011-11-02 11:29:39108using content::BrowserThread;
[email protected]c5eed492012-01-04 17:07:50109using content::NavigationController;
[email protected]10f417c52011-12-28 21:04:23110using content::NavigationEntry;
[email protected]a81343d232011-12-27 07:39:20111using content::WebContents;
[email protected]26e2632a2011-12-31 04:02:55112using content::WebUIMessageHandler;
[email protected]631bb742011-11-02 11:29:39113
[email protected]73852b8f2010-05-14 00:38:12114namespace internal_cloud_print_helpers {
115
[email protected]73852b8f2010-05-14 00:38:12116// From the JSON parsed value, get the entries for the page setup
117// parameters.
118bool GetPageSetupParameters(const std::string& json,
[email protected]1375e3ab2011-03-24 17:07:22119 PrintMsg_Print_Params& parameters) {
[email protected]73852b8f2010-05-14 00:38:12120 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
121 DLOG_IF(ERROR, (!parsed_value.get() ||
122 !parsed_value->IsType(Value::TYPE_DICTIONARY)))
123 << "PageSetup call didn't have expected contents";
124 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
125 return false;
126
127 bool result = true;
128 DictionaryValue* params = static_cast<DictionaryValue*>(parsed_value.get());
[email protected]05c7da62011-05-05 17:23:56129 result &= params->GetDouble("dpi", &parameters.dpi);
130 result &= params->GetDouble("min_shrink", &parameters.min_shrink);
131 result &= params->GetDouble("max_shrink", &parameters.max_shrink);
[email protected]a65175d2010-08-17 04:00:57132 result &= params->GetBoolean("selection_only", &parameters.selection_only);
[email protected]73852b8f2010-05-14 00:38:12133 return result;
134}
135
[email protected]e8368e92011-08-20 04:05:56136string16 GetSwitchValueString16(const CommandLine& command_line,
137 const char* switchName) {
138#ifdef OS_WIN
139 CommandLine::StringType native_switch_val;
140 native_switch_val = command_line.GetSwitchValueNative(switchName);
141 return string16(native_switch_val);
142#elif defined(OS_POSIX)
143 // POSIX Command line string types are different.
144 CommandLine::StringType native_switch_val;
145 native_switch_val = command_line.GetSwitchValueASCII(switchName);
146 // Convert the ASCII string to UTF16 to prepare to pass.
147 return string16(ASCIIToUTF16(native_switch_val));
148#endif
149}
150
[email protected]73852b8f2010-05-14 00:38:12151void CloudPrintDataSenderHelper::CallJavascriptFunction(
152 const std::wstring& function_name) {
[email protected]adcf8492011-03-09 22:41:39153 web_ui_->CallJavascriptFunction(WideToASCII(function_name));
[email protected]73852b8f2010-05-14 00:38:12154}
155
156void CloudPrintDataSenderHelper::CallJavascriptFunction(
157 const std::wstring& function_name, const Value& arg) {
[email protected]adcf8492011-03-09 22:41:39158 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg);
[email protected]73852b8f2010-05-14 00:38:12159}
160
161void CloudPrintDataSenderHelper::CallJavascriptFunction(
162 const std::wstring& function_name, const Value& arg1, const Value& arg2) {
[email protected]adcf8492011-03-09 22:41:39163 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2);
[email protected]73852b8f2010-05-14 00:38:12164}
165
[email protected]e8368e92011-08-20 04:05:56166void CloudPrintDataSenderHelper::CallJavascriptFunction(
167 const std::wstring& function_name,
168 const Value& arg1,
169 const Value& arg2,
170 const Value& arg3) {
[email protected]46adf7ff2011-12-30 00:53:09171 web_ui_->CallJavascriptFunction(
172 WideToASCII(function_name), arg1, arg2, arg3);
[email protected]e8368e92011-08-20 04:05:56173}
174
[email protected]73852b8f2010-05-14 00:38:12175// Clears out the pointer we're using to communicate. Either routine is
176// potentially expensive enough that stopping whatever is in progress
177// is worth it.
178void CloudPrintDataSender::CancelPrintDataFile() {
[email protected]20305ec2011-01-21 04:55:52179 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12180 // We don't own helper, it was passed in to us, so no need to
181 // delete, just let it go.
182 helper_ = NULL;
183}
184
[email protected]38e08982010-10-22 17:28:43185CloudPrintDataSender::CloudPrintDataSender(CloudPrintDataSenderHelper* helper,
[email protected]a984bdf2011-03-15 20:17:16186 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56187 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16188 const std::string& file_type)
[email protected]38e08982010-10-22 17:28:43189 : helper_(helper),
[email protected]a984bdf2011-03-15 20:17:16190 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56191 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16192 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43193}
194
195CloudPrintDataSender::~CloudPrintDataSender() {}
196
[email protected]a984bdf2011-03-15 20:17:16197// Grab the raw file contents and massage them into shape for
[email protected]73852b8f2010-05-14 00:38:12198// sending to the dialog contents (and up to the cloud print server)
199// by encoding it and prefixing it with the appropriate mime type.
200// Once that is done, kick off the next part of the task on the IO
201// thread.
[email protected]a984bdf2011-03-15 20:17:16202void CloudPrintDataSender::ReadPrintDataFile(const FilePath& path_to_file) {
[email protected]ba4f1132010-10-09 02:02:35203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]73852b8f2010-05-14 00:38:12204 int64 file_size = 0;
[email protected]a984bdf2011-03-15 20:17:16205 if (file_util::GetFileSize(path_to_file, &file_size) && file_size != 0) {
[email protected]73852b8f2010-05-14 00:38:12206 std::string file_data;
207 if (file_size < kuint32max) {
208 file_data.reserve(static_cast<unsigned int>(file_size));
209 } else {
210 DLOG(WARNING) << " print data file too large to reserve space";
211 }
[email protected]a984bdf2011-03-15 20:17:16212 if (helper_ && file_util::ReadFileToString(path_to_file, &file_data)) {
[email protected]73852b8f2010-05-14 00:38:12213 std::string base64_data;
214 base::Base64Encode(file_data, &base64_data);
[email protected]a984bdf2011-03-15 20:17:16215 std::string header("data:");
216 header.append(file_type_);
217 header.append(";base64,");
[email protected]73852b8f2010-05-14 00:38:12218 base64_data.insert(0, header);
219 scoped_ptr<StringValue> new_data(new StringValue(base64_data));
220 print_data_.swap(new_data);
[email protected]3e2dd4fa2011-11-10 06:06:40221 BrowserThread::PostTask(
222 BrowserThread::IO, FROM_HERE,
223 base::Bind(&CloudPrintDataSender::SendPrintDataFile, this));
[email protected]73852b8f2010-05-14 00:38:12224 }
225 }
226}
227
228// We have the data in hand that needs to be pushed into the dialog
229// contents; do so from the IO thread.
230
231// TODO(scottbyer): If the print data ends up being larger than the
232// upload limit (currently 10MB), what we need to do is upload that
233// large data to google docs and set the URL in the printing
234// JavaScript to that location, and make sure it gets deleted when not
235// needed. - 4/1/2010
236void CloudPrintDataSender::SendPrintDataFile() {
[email protected]ba4f1132010-10-09 02:02:35237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20305ec2011-01-21 04:55:52238 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12239 if (helper_ && print_data_.get()) {
[email protected]9848c7e2010-06-03 16:06:56240 StringValue title(print_job_title_);
[email protected]e8368e92011-08-20 04:05:56241 StringValue ticket(print_ticket_);
242 // TODO(abodenha): Change Javascript call to pass in print ticket
243 // after server side support is added. Add test for it.
[email protected]73852b8f2010-05-14 00:38:12244
245 // Send the print data to the dialog contents. The JavaScript
246 // function is a preliminary API for prototyping purposes and is
247 // subject to change.
248 const_cast<CloudPrintDataSenderHelper*>(helper_)->CallJavascriptFunction(
249 L"printApp._printDataUrl", *print_data_, title);
250 }
251}
252
253
[email protected]a984bdf2011-03-15 20:17:16254CloudPrintFlowHandler::CloudPrintFlowHandler(const FilePath& path_to_file,
255 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56256 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16257 const std::string& file_type)
[email protected]c7bf7452011-09-12 21:31:50258 : dialog_delegate_(NULL),
259 path_to_file_(path_to_file),
[email protected]a984bdf2011-03-15 20:17:16260 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56261 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16262 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43263}
264
265CloudPrintFlowHandler::~CloudPrintFlowHandler() {
266 // This will also cancel any task in flight.
267 CancelAnyRunningTask();
268}
269
270
[email protected]73852b8f2010-05-14 00:38:12271void CloudPrintFlowHandler::SetDialogDelegate(
272 CloudPrintHtmlDialogDelegate* delegate) {
[email protected]7b748982011-02-14 19:28:23273 // Even if setting a new WebUI, it means any previous task needs
[email protected]73852b8f2010-05-14 00:38:12274 // to be cancelled, it's now invalid.
[email protected]ba4f1132010-10-09 02:02:35275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12276 CancelAnyRunningTask();
277 dialog_delegate_ = delegate;
278}
279
280// Cancels any print data sender we have in flight and removes our
281// reference to it, so when the task that is calling it finishes and
282// removes it's reference, it goes away.
283void CloudPrintFlowHandler::CancelAnyRunningTask() {
[email protected]ba4f1132010-10-09 02:02:35284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12285 if (print_data_sender_.get()) {
286 print_data_sender_->CancelPrintDataFile();
287 print_data_sender_ = NULL;
288 }
289}
290
[email protected]73852b8f2010-05-14 00:38:12291void CloudPrintFlowHandler::RegisterMessages() {
[email protected]73852b8f2010-05-14 00:38:12292 // TODO(scottbyer) - This is where we will register messages for the
293 // UI JS to use. Needed: Call to update page setup parameters.
[email protected]46adf7ff2011-12-30 00:53:09294 web_ui()->RegisterMessageCallback("ShowDebugger",
[email protected]ba4fc242011-10-04 18:56:56295 base::Bind(&CloudPrintFlowHandler::HandleShowDebugger,
296 base::Unretained(this)));
[email protected]46adf7ff2011-12-30 00:53:09297 web_ui()->RegisterMessageCallback("SendPrintData",
[email protected]ba4fc242011-10-04 18:56:56298 base::Bind(&CloudPrintFlowHandler::HandleSendPrintData,
299 base::Unretained(this)));
[email protected]46adf7ff2011-12-30 00:53:09300 web_ui()->RegisterMessageCallback("SetPageParameters",
[email protected]ba4fc242011-10-04 18:56:56301 base::Bind(&CloudPrintFlowHandler::HandleSetPageParameters,
302 base::Unretained(this)));
[email protected]73852b8f2010-05-14 00:38:12303
[email protected]0eb25c42011-08-11 14:50:14304 // Register for appropriate notifications, and re-direct the URL
305 // to the real server URL, now that we've gotten an HTML dialog
306 // going.
[email protected]c5eed492012-01-04 17:07:50307 NavigationController* controller =
[email protected]cdcb1dee2012-01-04 00:46:20308 &web_ui()->web_contents()->GetController();
[email protected]10f417c52011-12-28 21:04:23309 NavigationEntry* pending_entry = controller->GetPendingEntry();
[email protected]0eb25c42011-08-11 14:50:14310 if (pending_entry) {
[email protected]46adf7ff2011-12-30 00:53:09311 Profile* profile = Profile::FromWebUI(web_ui());
[email protected]ad23a092011-12-28 07:02:04312 pending_entry->SetURL(
[email protected]0eb25c42011-08-11 14:50:14313 CloudPrintURL(profile).GetCloudPrintServiceDialogURL());
[email protected]73852b8f2010-05-14 00:38:12314 }
[email protected]0eb25c42011-08-11 14:50:14315 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
[email protected]c5eed492012-01-04 17:07:50316 content::Source<NavigationController>(controller));
[email protected]73852b8f2010-05-14 00:38:12317}
318
[email protected]6c2381d2011-10-19 02:52:53319void CloudPrintFlowHandler::Observe(
320 int type,
321 const content::NotificationSource& source,
322 const content::NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:27323 if (type == content::NOTIFICATION_LOAD_STOP) {
[email protected]20c52d22011-06-20 22:42:42324 // Take the opportunity to set some (minimal) additional
325 // script permissions required for the web UI.
[email protected]0ec4898e2011-12-30 21:09:24326 GURL url = web_ui()->web_contents()->GetURL();
[email protected]20c52d22011-06-20 22:42:42327 GURL dialog_url = CloudPrintURL(
[email protected]46adf7ff2011-12-30 00:53:09328 Profile::FromWebUI(web_ui())).GetCloudPrintServiceDialogURL();
[email protected]20c52d22011-06-20 22:42:42329 if (url.host() == dialog_url.host() &&
330 url.path() == dialog_url.path() &&
331 url.scheme() == dialog_url.scheme()) {
[email protected]0ec4898e2011-12-30 21:09:24332 RenderViewHost* rvh = web_ui()->web_contents()->GetRenderViewHost();
[email protected]20c52d22011-06-20 22:42:42333 if (rvh && rvh->delegate()) {
334 WebPreferences webkit_prefs = rvh->delegate()->GetWebkitPrefs();
335 webkit_prefs.allow_scripts_to_close_windows = true;
[email protected]9abd51f2011-09-21 19:11:35336 rvh->UpdateWebkitPreferences(webkit_prefs);
[email protected]20c52d22011-06-20 22:42:42337 } else {
338 DCHECK(false);
339 }
340 }
341
[email protected]73852b8f2010-05-14 00:38:12342 // Choose one or the other. If you need to debug, bring up the
343 // debugger. You can then use the various chrome.send()
344 // registrations above to kick of the various function calls,
345 // including chrome.send("SendPrintData") in the javaScript
346 // console and watch things happen with:
347 // HandleShowDebugger(NULL);
348 HandleSendPrintData(NULL);
349 }
350}
351
[email protected]88942a22010-08-19 20:34:43352void CloudPrintFlowHandler::HandleShowDebugger(const ListValue* args) {
[email protected]73852b8f2010-05-14 00:38:12353 ShowDebugger();
354}
355
356void CloudPrintFlowHandler::ShowDebugger() {
[email protected]46adf7ff2011-12-30 00:53:09357 if (web_ui()) {
[email protected]0ec4898e2011-12-30 21:09:24358 RenderViewHost* rvh = web_ui()->web_contents()->GetRenderViewHost();
[email protected]73852b8f2010-05-14 00:38:12359 if (rvh)
[email protected]aebdd072011-07-07 12:36:59360 DevToolsWindow::OpenDevToolsWindow(rvh);
[email protected]73852b8f2010-05-14 00:38:12361 }
362}
363
364scoped_refptr<CloudPrintDataSender>
365CloudPrintFlowHandler::CreateCloudPrintDataSender() {
[email protected]46adf7ff2011-12-30 00:53:09366 DCHECK(web_ui());
367 print_data_helper_.reset(new CloudPrintDataSenderHelper(web_ui()));
[email protected]a984bdf2011-03-15 20:17:16368 return new CloudPrintDataSender(print_data_helper_.get(),
369 print_job_title_,
[email protected]e8368e92011-08-20 04:05:56370 print_ticket_,
[email protected]a984bdf2011-03-15 20:17:16371 file_type_);
[email protected]73852b8f2010-05-14 00:38:12372}
373
[email protected]88942a22010-08-19 20:34:43374void CloudPrintFlowHandler::HandleSendPrintData(const ListValue* args) {
[email protected]ba4f1132010-10-09 02:02:35375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12376 // This will cancel any ReadPrintDataFile() or SendPrintDataFile()
377 // requests in flight (this is anticipation of when setting page
378 // setup parameters becomes asynchronous and may be set while some
379 // data is in flight). Then we can clear out the print data.
380 CancelAnyRunningTask();
[email protected]46adf7ff2011-12-30 00:53:09381 if (web_ui()) {
[email protected]73852b8f2010-05-14 00:38:12382 print_data_sender_ = CreateCloudPrintDataSender();
[email protected]3e2dd4fa2011-11-10 06:06:40383 BrowserThread::PostTask(
384 BrowserThread::FILE, FROM_HERE,
385 base::Bind(&CloudPrintDataSender::ReadPrintDataFile,
386 print_data_sender_.get(), path_to_file_));
[email protected]73852b8f2010-05-14 00:38:12387 }
388}
389
[email protected]88942a22010-08-19 20:34:43390void CloudPrintFlowHandler::HandleSetPageParameters(const ListValue* args) {
[email protected]036056a32011-03-03 21:05:01391 std::string json;
[email protected]e675f7b2011-06-22 17:32:12392 bool ret = args->GetString(0, &json);
393 if (!ret || json.empty()) {
[email protected]036056a32011-03-03 21:05:01394 NOTREACHED() << "Empty json string";
[email protected]73852b8f2010-05-14 00:38:12395 return;
[email protected]036056a32011-03-03 21:05:01396 }
[email protected]73852b8f2010-05-14 00:38:12397
398 // These are backstop default values - 72 dpi to match the screen,
399 // 8.5x11 inch paper with margins subtracted (1/4 inch top, left,
400 // right and 0.56 bottom), and the min page shrink and max page
401 // shrink values appear all over the place with no explanation.
402
403 // TODO(scottbyer): Get a Linux/ChromeOS edge for PrintSettings
404 // working so that we can get the default values from there. Fix up
405 // PrintWebViewHelper to do the same.
406 const int kDPI = 72;
407 const int kWidth = static_cast<int>((8.5-0.25-0.25)*kDPI);
408 const int kHeight = static_cast<int>((11-0.25-0.56)*kDPI);
409 const double kMinPageShrink = 1.25;
410 const double kMaxPageShrink = 2.0;
411
[email protected]1375e3ab2011-03-24 17:07:22412 PrintMsg_Print_Params default_settings;
[email protected]10980442011-12-04 22:33:05413 default_settings.content_size = gfx::Size(kWidth, kHeight);
[email protected]73852b8f2010-05-14 00:38:12414 default_settings.dpi = kDPI;
415 default_settings.min_shrink = kMinPageShrink;
416 default_settings.max_shrink = kMaxPageShrink;
417 default_settings.desired_dpi = kDPI;
418 default_settings.document_cookie = 0;
419 default_settings.selection_only = false;
[email protected]718af822011-08-12 22:11:33420 default_settings.preview_request_id = 0;
421 default_settings.is_first_request = true;
[email protected]73852b8f2010-05-14 00:38:12422
423 if (!GetPageSetupParameters(json, default_settings)) {
424 NOTREACHED();
425 return;
426 }
427
428 // TODO(scottbyer) - Here is where we would kick the originating
429 // renderer thread with these new parameters in order to get it to
[email protected]a984bdf2011-03-15 20:17:16430 // re-generate the PDF data and hand it back to us. window.print() is
[email protected]73852b8f2010-05-14 00:38:12431 // currently synchronous, so there's a lot of work to do to get to
432 // that point.
433}
434
[email protected]ea161da2010-11-02 21:57:35435void CloudPrintFlowHandler::StoreDialogClientSize() const {
[email protected]0ec4898e2011-12-30 21:09:24436 if (web_ui() && web_ui()->web_contents() &&
437 web_ui()->web_contents()->GetView()) {
438 gfx::Size size = web_ui()->web_contents()->GetView()->GetContainerSize();
[email protected]46adf7ff2011-12-30 00:53:09439 Profile* profile = Profile::FromWebUI(web_ui());
[email protected]0eb25c42011-08-11 14:50:14440 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogWidth,
441 size.width());
442 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogHeight,
443 size.height());
[email protected]ea161da2010-11-02 21:57:35444 }
445}
446
[email protected]73852b8f2010-05-14 00:38:12447CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
[email protected]a984bdf2011-03-15 20:17:16448 const FilePath& path_to_file,
[email protected]73852b8f2010-05-14 00:38:12449 int width, int height,
[email protected]9848c7e2010-06-03 16:06:56450 const std::string& json_arguments,
[email protected]e39027a2011-01-24 21:41:54451 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56452 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16453 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03454 bool modal,
455 bool delete_on_close)
456 : delete_on_close_(delete_on_close),
457 flow_handler_(new CloudPrintFlowHandler(path_to_file,
[email protected]a984bdf2011-03-15 20:17:16458 print_job_title,
[email protected]e8368e92011-08-20 04:05:56459 print_ticket,
[email protected]a984bdf2011-03-15 20:17:16460 file_type)),
[email protected]e39027a2011-01-24 21:41:54461 modal_(modal),
[email protected]6ddda232011-04-22 15:41:47462 owns_flow_handler_(true),
463 path_to_file_(path_to_file) {
[email protected]73852b8f2010-05-14 00:38:12464 Init(width, height, json_arguments);
465}
466
[email protected]05acb55472011-02-03 00:11:07467// For unit testing.
[email protected]73852b8f2010-05-14 00:38:12468CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
469 CloudPrintFlowHandler* flow_handler,
470 int width, int height,
[email protected]e39027a2011-01-24 21:41:54471 const std::string& json_arguments,
[email protected]d955fc92011-09-19 20:49:03472 bool modal,
473 bool delete_on_close)
474 : delete_on_close_(delete_on_close),
475 flow_handler_(flow_handler),
[email protected]e39027a2011-01-24 21:41:54476 modal_(modal),
[email protected]18137e02010-05-25 21:10:35477 owns_flow_handler_(true) {
[email protected]73852b8f2010-05-14 00:38:12478 Init(width, height, json_arguments);
479}
480
[email protected]05acb55472011-02-03 00:11:07481void CloudPrintHtmlDialogDelegate::Init(int width, int height,
482 const std::string& json_arguments) {
[email protected]73852b8f2010-05-14 00:38:12483 // This information is needed to show the dialog HTML content.
[email protected]ba4f1132010-10-09 02:02:35484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]89f550b2011-06-08 18:34:03485 params_.url = GURL(chrome::kChromeUICloudPrintResourcesURL);
[email protected]73852b8f2010-05-14 00:38:12486 params_.height = height;
487 params_.width = width;
488 params_.json_input = json_arguments;
489
490 flow_handler_->SetDialogDelegate(this);
[email protected]e39027a2011-01-24 21:41:54491 // If we're not modal we can show the dialog with no browser.
492 // We need this to keep Chrome alive while our dialog is up.
493 if (!modal_)
494 BrowserList::StartKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12495}
496
497CloudPrintHtmlDialogDelegate::~CloudPrintHtmlDialogDelegate() {
498 // If the flow_handler_ is about to outlive us because we don't own
499 // it anymore, we need to have it remove it's reference to us.
[email protected]ba4f1132010-10-09 02:02:35500 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12501 flow_handler_->SetDialogDelegate(NULL);
502 if (owns_flow_handler_) {
503 delete flow_handler_;
504 }
505}
506
507bool CloudPrintHtmlDialogDelegate::IsDialogModal() const {
[email protected]e39027a2011-01-24 21:41:54508 return modal_;
[email protected]73852b8f2010-05-14 00:38:12509}
510
[email protected]bdae5c12011-08-05 21:49:06511string16 CloudPrintHtmlDialogDelegate::GetDialogTitle() const {
512 return string16();
[email protected]73852b8f2010-05-14 00:38:12513}
514
515GURL CloudPrintHtmlDialogDelegate::GetDialogContentURL() const {
516 return params_.url;
517}
518
[email protected]36e12172011-02-08 23:46:02519void CloudPrintHtmlDialogDelegate::GetWebUIMessageHandlers(
520 std::vector<WebUIMessageHandler*>* handlers) const {
[email protected]73852b8f2010-05-14 00:38:12521 handlers->push_back(flow_handler_);
522 // We don't own flow_handler_ anymore, but it sticks around until at
523 // least right after OnDialogClosed() is called (and this object is
524 // destroyed).
525 owns_flow_handler_ = false;
526}
527
528void CloudPrintHtmlDialogDelegate::GetDialogSize(gfx::Size* size) const {
529 size->set_width(params_.width);
530 size->set_height(params_.height);
531}
532
533std::string CloudPrintHtmlDialogDelegate::GetDialogArgs() const {
534 return params_.json_input;
535}
536
537void CloudPrintHtmlDialogDelegate::OnDialogClosed(
538 const std::string& json_retval) {
[email protected]ea161da2010-11-02 21:57:35539 // Get the final dialog size and store it.
540 flow_handler_->StoreDialogClientSize();
[email protected]6ddda232011-04-22 15:41:47541
[email protected]d955fc92011-09-19 20:49:03542 if (delete_on_close_) {
[email protected]3e2dd4fa2011-11-10 06:06:40543 BrowserThread::PostTask(
544 BrowserThread::FILE, FROM_HERE,
545 base::Bind(&internal_cloud_print_helpers::Delete, path_to_file_));
[email protected]6ddda232011-04-22 15:41:47546 }
547
[email protected]e39027a2011-01-24 21:41:54548 // If we're modal we can show the dialog with no browser.
549 // End the keep-alive so that Chrome can exit.
550 if (!modal_)
551 BrowserList::EndKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12552 delete this;
553}
554
[email protected]a81343d232011-12-27 07:39:20555void CloudPrintHtmlDialogDelegate::OnCloseContents(WebContents* source,
[email protected]18137e02010-05-25 21:10:35556 bool* out_close_dialog) {
557 if (out_close_dialog)
558 *out_close_dialog = true;
559}
560
[email protected]ea161da2010-11-02 21:57:35561bool CloudPrintHtmlDialogDelegate::ShouldShowDialogTitle() const {
562 return false;
563}
564
[email protected]34478212011-04-19 01:35:46565bool CloudPrintHtmlDialogDelegate::HandleContextMenu(
566 const ContextMenuParams& params) {
567 return true;
568}
569
[email protected]d955fc92011-09-19 20:49:03570void CreatePrintDialogForBytesImpl(scoped_refptr<RefCountedBytes> data,
571 const string16& print_job_title,
572 const string16& print_ticket,
573 const std::string& file_type,
574 bool modal) {
575 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
576 // TODO([email protected]) Writing the PDF to a file before printing
577 // is wasteful. Modify the dialog flow to pull PDF data from memory.
578 // See http://code.google.com/p/chromium/issues/detail?id=44093
579 FilePath path;
580 if (file_util::CreateTemporaryFile(&path)) {
581 file_util::WriteFile(path,
582 reinterpret_cast<const char*>(data->front()),
583 data->size());
584 }
585 print_dialog_cloud::CreatePrintDialogForFile(path,
586 print_job_title,
587 print_ticket,
588 file_type,
589 modal,
590 true);
591}
592
[email protected]6085c70d2011-03-22 22:51:07593// Called from the UI thread, starts up the dialog.
594void CreateDialogImpl(const FilePath& path_to_file,
595 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56596 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07597 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03598 bool modal,
599 bool delete_on_close) {
[email protected]ba4f1132010-10-09 02:02:35600 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6085c70d2011-03-22 22:51:07601 Browser* browser = BrowserList::GetLastActive();
[email protected]73852b8f2010-05-14 00:38:12602
[email protected]ea161da2010-11-02 21:57:35603 const int kDefaultWidth = 497;
604 const int kDefaultHeight = 332;
[email protected]05acb55472011-02-03 00:11:07605 string16 job_title = print_job_title;
[email protected]e39027a2011-01-24 21:41:54606 Profile* profile = NULL;
[email protected]05acb55472011-02-03 00:11:07607 if (modal) {
[email protected]0ec4898e2011-12-30 21:09:24608 if (job_title.empty()) {
[email protected]4ca15302012-01-03 05:53:20609 WebContents* web_contents = browser->GetSelectedWebContents();
[email protected]0ec4898e2011-12-30 21:09:24610 if (web_contents)
611 job_title = web_contents->GetTitle();
612 }
[email protected]6085c70d2011-03-22 22:51:07613 profile = browser->GetProfile();
[email protected]e39027a2011-01-24 21:41:54614 } else {
[email protected]0744cc72011-08-12 12:05:45615 std::vector<Profile*> loaded_profiles =
616 g_browser_process->profile_manager()->GetLoadedProfiles();
617 DCHECK_GT(loaded_profiles.size(), 0U);
618 profile = loaded_profiles[0];
[email protected]e39027a2011-01-24 21:41:54619 }
620 DCHECK(profile);
[email protected]05acb55472011-02-03 00:11:07621 PrefService* pref_service = profile->GetPrefs();
[email protected]ea161da2010-11-02 21:57:35622 DCHECK(pref_service);
623 if (!pref_service->FindPreference(prefs::kCloudPrintDialogWidth)) {
624 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogWidth,
[email protected]d36f941b2011-05-09 06:19:16625 kDefaultWidth,
626 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35627 }
628 if (!pref_service->FindPreference(prefs::kCloudPrintDialogHeight)) {
629 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogHeight,
[email protected]d36f941b2011-05-09 06:19:16630 kDefaultHeight,
631 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35632 }
633
634 int width = pref_service->GetInteger(prefs::kCloudPrintDialogWidth);
635 int height = pref_service->GetInteger(prefs::kCloudPrintDialogHeight);
[email protected]e39027a2011-01-24 21:41:54636
[email protected]73852b8f2010-05-14 00:38:12637 HtmlDialogUIDelegate* dialog_delegate =
638 new internal_cloud_print_helpers::CloudPrintHtmlDialogDelegate(
[email protected]e8368e92011-08-20 04:05:56639 path_to_file, width, height, std::string(), job_title, print_ticket,
[email protected]d955fc92011-09-19 20:49:03640 file_type, modal, delete_on_close);
[email protected]05acb55472011-02-03 00:11:07641 if (modal) {
[email protected]6085c70d2011-03-22 22:51:07642 DCHECK(browser);
[email protected]22c830d2011-11-29 20:00:37643 browser->BrowserShowHtmlDialog(dialog_delegate, NULL, STYLE_GENERIC);
[email protected]e39027a2011-01-24 21:41:54644 } else {
[email protected]22c830d2011-11-29 20:00:37645 browser::ShowHtmlDialog(NULL, profile, dialog_delegate, STYLE_GENERIC);
[email protected]e39027a2011-01-24 21:41:54646 }
[email protected]73852b8f2010-05-14 00:38:12647}
[email protected]6085c70d2011-03-22 22:51:07648
[email protected]6ddda232011-04-22 15:41:47649// Provides a runnable function to delete a file.
650void Delete(const FilePath& file_path) {
651 file_util::Delete(file_path, false);
652}
653
[email protected]6085c70d2011-03-22 22:51:07654} // namespace internal_cloud_print_helpers
655
656namespace print_dialog_cloud {
657
658// Called on the FILE or UI thread. This is the main entry point into creating
659// the dialog.
660
661// TODO(scottbyer): The signature here will need to change as the
662// workflow through the printing code changes to allow for dynamically
663// changing page setup parameters while the dialog is active.
664void CreatePrintDialogForFile(const FilePath& path_to_file,
665 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56666 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07667 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03668 bool modal,
669 bool delete_on_close) {
[email protected]6085c70d2011-03-22 22:51:07670 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE) ||
671 BrowserThread::CurrentlyOn(BrowserThread::UI));
672
673 BrowserThread::PostTask(
674 BrowserThread::UI, FROM_HERE,
[email protected]3e2dd4fa2011-11-10 06:06:40675 base::Bind(&internal_cloud_print_helpers::CreateDialogImpl, path_to_file,
676 print_job_title, print_ticket, file_type, modal,
677 delete_on_close));
[email protected]d955fc92011-09-19 20:49:03678}
679
680void CreatePrintDialogForBytes(scoped_refptr<RefCountedBytes> data,
681 const string16& print_job_title,
682 const string16& print_ticket,
683 const std::string& file_type,
684 bool modal) {
685 // TODO([email protected]) Avoid cloning the PDF data. Make use of a
686 // shared memory object instead.
687 // http://code.google.com/p/chromium/issues/detail?id=44093
688 scoped_refptr<RefCountedBytes> cloned_data(new RefCountedBytes(data->data()));
689 BrowserThread::PostTask(
690 BrowserThread::FILE, FROM_HERE,
[email protected]3e2dd4fa2011-11-10 06:06:40691 base::Bind(&internal_cloud_print_helpers::CreatePrintDialogForBytesImpl,
692 cloned_data, print_job_title, print_ticket, file_type, modal));
[email protected]6085c70d2011-03-22 22:51:07693}
694
[email protected]65c9d89a2011-04-13 21:02:39695bool CreatePrintDialogFromCommandLine(const CommandLine& command_line) {
696 if (!command_line.GetSwitchValuePath(switches::kCloudPrintFile).empty()) {
697 FilePath cloud_print_file;
698 cloud_print_file =
699 command_line.GetSwitchValuePath(switches::kCloudPrintFile);
700 if (!cloud_print_file.empty()) {
701 string16 print_job_title;
[email protected]e8368e92011-08-20 04:05:56702 string16 print_job_print_ticket;
[email protected]65c9d89a2011-04-13 21:02:39703 if (command_line.HasSwitch(switches::kCloudPrintJobTitle)) {
[email protected]e8368e92011-08-20 04:05:56704 print_job_title =
705 internal_cloud_print_helpers::GetSwitchValueString16(
706 command_line, switches::kCloudPrintJobTitle);
707 }
708 if (command_line.HasSwitch(switches::kCloudPrintPrintTicket)) {
709 print_job_print_ticket =
710 internal_cloud_print_helpers::GetSwitchValueString16(
711 command_line, switches::kCloudPrintPrintTicket);
[email protected]65c9d89a2011-04-13 21:02:39712 }
713 std::string file_type = "application/pdf";
714 if (command_line.HasSwitch(switches::kCloudPrintFileType)) {
715 file_type = command_line.GetSwitchValueASCII(
716 switches::kCloudPrintFileType);
717 }
[email protected]e8368e92011-08-20 04:05:56718
[email protected]d955fc92011-09-19 20:49:03719 bool delete_on_close = CommandLine::ForCurrentProcess()->HasSwitch(
720 switches::kCloudPrintDeleteFile);
721
[email protected]65c9d89a2011-04-13 21:02:39722 print_dialog_cloud::CreatePrintDialogForFile(cloud_print_file,
723 print_job_title,
[email protected]e8368e92011-08-20 04:05:56724 print_job_print_ticket,
[email protected]65c9d89a2011-04-13 21:02:39725 file_type,
[email protected]d955fc92011-09-19 20:49:03726 false,
727 delete_on_close);
[email protected]65c9d89a2011-04-13 21:02:39728 return true;
729 }
730 }
731 return false;
732}
733
[email protected]6085c70d2011-03-22 22:51:07734} // end namespace