blob: 4d1db8ff87ad9ebf6e38565dd1afd37fd7b192f6 [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]65c9d89a2011-04-13 21:02:3924#include "chrome/common/chrome_switches.h"
[email protected]ea161da2010-11-02 21:57:3525#include "chrome/common/pref_names.h"
[email protected]1375e3ab2011-03-24 17:07:2226#include "chrome/common/print_messages.h"
[email protected]73852b8f2010-05-14 00:38:1227#include "chrome/common/url_constants.h"
[email protected]5f945a0e2011-03-01 17:47:5328#include "content/browser/renderer_host/render_view_host.h"
29#include "content/browser/tab_contents/tab_contents.h"
30#include "content/browser/tab_contents/tab_contents_view.h"
[email protected]67fc0392011-02-25 02:56:5731#include "content/browser/webui/web_ui.h"
[email protected]c38831a12011-10-28 12:44:4932#include "content/public/browser/browser_thread.h"
[email protected]6c2381d2011-10-19 02:52:5333#include "content/public/browser/notification_registrar.h"
34#include "content/public/browser/notification_source.h"
[email protected]0d6e9bd2011-10-18 04:29:1635#include "content/public/browser/notification_types.h"
[email protected]c051a1b2011-01-21 23:30:1736#include "ui/base/l10n/l10n_util.h"
[email protected]939856a2010-08-24 20:29:0237#include "webkit/glue/webpreferences.h"
[email protected]73852b8f2010-05-14 00:38:1238
39#include "grit/generated_resources.h"
40
41// This module implements the UI support in Chrome for cloud printing.
42// This means hosting a dialog containing HTML/JavaScript and using
43// the published cloud print user interface integration APIs to get
44// page setup settings from the dialog contents and provide the
[email protected]a984bdf2011-03-15 20:17:1645// generated print data to the dialog contents for uploading to the
[email protected]73852b8f2010-05-14 00:38:1246// cloud print service.
47
48// Currently, the flow between these classes is as follows:
49
[email protected]a984bdf2011-03-15 20:17:1650// PrintDialogCloud::CreatePrintDialogForFile is called from
[email protected]73852b8f2010-05-14 00:38:1251// resource_message_filter_gtk.cc once the renderer has informed the
[email protected]a984bdf2011-03-15 20:17:1652// renderer host that print data generation into the renderer host provided
[email protected]032682b2011-01-12 22:05:0253// temp file has been completed. That call is on the FILE thread.
[email protected]73852b8f2010-05-14 00:38:1254// That, in turn, hops over to the UI thread to create an instance of
55// PrintDialogCloud.
56
57// The constructor for PrintDialogCloud creates a
58// CloudPrintHtmlDialogDelegate and asks the current active browser to
59// show an HTML dialog using that class as the delegate. That class
[email protected]89f550b2011-06-08 18:34:0360// hands in the kChromeUICloudPrintResourcesURL as the URL to visit. That is
[email protected]80a8fad2011-01-29 04:02:3861// recognized by the GetWebUIFactoryFunction as a signal to create an
[email protected]73852b8f2010-05-14 00:38:1262// ExternalHtmlDialogUI.
63
64// CloudPrintHtmlDialogDelegate also temporarily owns a
65// CloudPrintFlowHandler, a class which is responsible for the actual
[email protected]a984bdf2011-03-15 20:17:1666// interactions with the dialog contents, including handing in the
[email protected]73852b8f2010-05-14 00:38:1267// print data and getting any page setup parameters that the dialog
68// contents provides. As part of bringing up the dialog,
69// HtmlDialogUI::RenderViewCreated is called (an override of
[email protected]c39f9bf2011-02-12 00:43:5570// WebUI::RenderViewCreated). That routine, in turn, calls the
[email protected]36e12172011-02-08 23:46:0271// delegate's GetWebUIMessageHandlers routine, at which point the
[email protected]73852b8f2010-05-14 00:38:1272// ownership of the CloudPrintFlowHandler is handed over. A pointer
73// to the flow handler is kept to facilitate communication back and
74// forth between the two classes.
75
[email protected]c39f9bf2011-02-12 00:43:5576// The WebUI continues dialog bring-up, calling
[email protected]73852b8f2010-05-14 00:38:1277// CloudPrintFlowHandler::RegisterMessages. This is where the
78// additional object model capabilities are registered for the dialog
79// contents to use. It is also at this time that capabilities for the
80// dialog contents are adjusted to allow the dialog contents to close
81// the window. In addition, the pending URL is redirected to the
82// actual cloud print service URL. The flow controller also registers
83// for notification of when the dialog contents finish loading, which
[email protected]a984bdf2011-03-15 20:17:1684// is currently used to send the data to the dialog contents.
[email protected]73852b8f2010-05-14 00:38:1285
[email protected]a984bdf2011-03-15 20:17:1686// In order to send the data to the dialog contents, the flow
[email protected]73852b8f2010-05-14 00:38:1287// handler uses a CloudPrintDataSender. It creates one, letting it
[email protected]a984bdf2011-03-15 20:17:1688// know the name of the temporary file containing the data, and
[email protected]73852b8f2010-05-14 00:38:1289// posts the task of reading the file
90// (CloudPrintDataSender::ReadPrintDataFile) to the file thread. That
91// routine reads in the file, and then hops over to the IO thread to
92// send that data to the dialog contents.
93
94// When the dialog contents are finished (by either being cancelled or
95// hitting the print button), the delegate is notified, and responds
96// that the dialog should be closed, at which point things are torn
97// down and released.
98
99// TODO(scottbyer):
100// http://code.google.com/p/chromium/issues/detail?id=44093 The
[email protected]a984bdf2011-03-15 20:17:16101// high-level flow (where the data is generated before even
[email protected]73852b8f2010-05-14 00:38:12102// bringing up the dialog) isn't what we want.
103
[email protected]73852b8f2010-05-14 00:38:12104namespace internal_cloud_print_helpers {
105
[email protected]73852b8f2010-05-14 00:38:12106// From the JSON parsed value, get the entries for the page setup
107// parameters.
108bool GetPageSetupParameters(const std::string& json,
[email protected]1375e3ab2011-03-24 17:07:22109 PrintMsg_Print_Params& parameters) {
[email protected]73852b8f2010-05-14 00:38:12110 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
111 DLOG_IF(ERROR, (!parsed_value.get() ||
112 !parsed_value->IsType(Value::TYPE_DICTIONARY)))
113 << "PageSetup call didn't have expected contents";
114 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
115 return false;
116
117 bool result = true;
118 DictionaryValue* params = static_cast<DictionaryValue*>(parsed_value.get());
[email protected]05c7da62011-05-05 17:23:56119 result &= params->GetDouble("dpi", &parameters.dpi);
120 result &= params->GetDouble("min_shrink", &parameters.min_shrink);
121 result &= params->GetDouble("max_shrink", &parameters.max_shrink);
[email protected]a65175d2010-08-17 04:00:57122 result &= params->GetBoolean("selection_only", &parameters.selection_only);
[email protected]73852b8f2010-05-14 00:38:12123 return result;
124}
125
[email protected]e8368e92011-08-20 04:05:56126string16 GetSwitchValueString16(const CommandLine& command_line,
127 const char* switchName) {
128#ifdef OS_WIN
129 CommandLine::StringType native_switch_val;
130 native_switch_val = command_line.GetSwitchValueNative(switchName);
131 return string16(native_switch_val);
132#elif defined(OS_POSIX)
133 // POSIX Command line string types are different.
134 CommandLine::StringType native_switch_val;
135 native_switch_val = command_line.GetSwitchValueASCII(switchName);
136 // Convert the ASCII string to UTF16 to prepare to pass.
137 return string16(ASCIIToUTF16(native_switch_val));
138#endif
139}
140
[email protected]73852b8f2010-05-14 00:38:12141void CloudPrintDataSenderHelper::CallJavascriptFunction(
142 const std::wstring& function_name) {
[email protected]adcf8492011-03-09 22:41:39143 web_ui_->CallJavascriptFunction(WideToASCII(function_name));
[email protected]73852b8f2010-05-14 00:38:12144}
145
146void CloudPrintDataSenderHelper::CallJavascriptFunction(
147 const std::wstring& function_name, const Value& arg) {
[email protected]adcf8492011-03-09 22:41:39148 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg);
[email protected]73852b8f2010-05-14 00:38:12149}
150
151void CloudPrintDataSenderHelper::CallJavascriptFunction(
152 const std::wstring& function_name, const Value& arg1, const Value& arg2) {
[email protected]adcf8492011-03-09 22:41:39153 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2);
[email protected]73852b8f2010-05-14 00:38:12154}
155
[email protected]e8368e92011-08-20 04:05:56156void CloudPrintDataSenderHelper::CallJavascriptFunction(
157 const std::wstring& function_name,
158 const Value& arg1,
159 const Value& arg2,
160 const Value& arg3) {
161 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2, arg3);
162}
163
[email protected]73852b8f2010-05-14 00:38:12164// Clears out the pointer we're using to communicate. Either routine is
165// potentially expensive enough that stopping whatever is in progress
166// is worth it.
167void CloudPrintDataSender::CancelPrintDataFile() {
[email protected]20305ec2011-01-21 04:55:52168 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12169 // We don't own helper, it was passed in to us, so no need to
170 // delete, just let it go.
171 helper_ = NULL;
172}
173
[email protected]38e08982010-10-22 17:28:43174CloudPrintDataSender::CloudPrintDataSender(CloudPrintDataSenderHelper* helper,
[email protected]a984bdf2011-03-15 20:17:16175 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56176 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16177 const std::string& file_type)
[email protected]38e08982010-10-22 17:28:43178 : helper_(helper),
[email protected]a984bdf2011-03-15 20:17:16179 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56180 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16181 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43182}
183
184CloudPrintDataSender::~CloudPrintDataSender() {}
185
[email protected]a984bdf2011-03-15 20:17:16186// Grab the raw file contents and massage them into shape for
[email protected]73852b8f2010-05-14 00:38:12187// sending to the dialog contents (and up to the cloud print server)
188// by encoding it and prefixing it with the appropriate mime type.
189// Once that is done, kick off the next part of the task on the IO
190// thread.
[email protected]a984bdf2011-03-15 20:17:16191void CloudPrintDataSender::ReadPrintDataFile(const FilePath& path_to_file) {
[email protected]ba4f1132010-10-09 02:02:35192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]73852b8f2010-05-14 00:38:12193 int64 file_size = 0;
[email protected]a984bdf2011-03-15 20:17:16194 if (file_util::GetFileSize(path_to_file, &file_size) && file_size != 0) {
[email protected]73852b8f2010-05-14 00:38:12195 std::string file_data;
196 if (file_size < kuint32max) {
197 file_data.reserve(static_cast<unsigned int>(file_size));
198 } else {
199 DLOG(WARNING) << " print data file too large to reserve space";
200 }
[email protected]a984bdf2011-03-15 20:17:16201 if (helper_ && file_util::ReadFileToString(path_to_file, &file_data)) {
[email protected]73852b8f2010-05-14 00:38:12202 std::string base64_data;
203 base::Base64Encode(file_data, &base64_data);
[email protected]a984bdf2011-03-15 20:17:16204 std::string header("data:");
205 header.append(file_type_);
206 header.append(";base64,");
[email protected]73852b8f2010-05-14 00:38:12207 base64_data.insert(0, header);
208 scoped_ptr<StringValue> new_data(new StringValue(base64_data));
209 print_data_.swap(new_data);
[email protected]ba4f1132010-10-09 02:02:35210 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
211 NewRunnableMethod(
212 this,
213 &CloudPrintDataSender::SendPrintDataFile));
[email protected]73852b8f2010-05-14 00:38:12214 }
215 }
216}
217
218// We have the data in hand that needs to be pushed into the dialog
219// contents; do so from the IO thread.
220
221// TODO(scottbyer): If the print data ends up being larger than the
222// upload limit (currently 10MB), what we need to do is upload that
223// large data to google docs and set the URL in the printing
224// JavaScript to that location, and make sure it gets deleted when not
225// needed. - 4/1/2010
226void CloudPrintDataSender::SendPrintDataFile() {
[email protected]ba4f1132010-10-09 02:02:35227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20305ec2011-01-21 04:55:52228 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12229 if (helper_ && print_data_.get()) {
[email protected]9848c7e2010-06-03 16:06:56230 StringValue title(print_job_title_);
[email protected]e8368e92011-08-20 04:05:56231 StringValue ticket(print_ticket_);
232 // TODO(abodenha): Change Javascript call to pass in print ticket
233 // after server side support is added. Add test for it.
[email protected]73852b8f2010-05-14 00:38:12234
235 // Send the print data to the dialog contents. The JavaScript
236 // function is a preliminary API for prototyping purposes and is
237 // subject to change.
238 const_cast<CloudPrintDataSenderHelper*>(helper_)->CallJavascriptFunction(
239 L"printApp._printDataUrl", *print_data_, title);
240 }
241}
242
243
[email protected]a984bdf2011-03-15 20:17:16244CloudPrintFlowHandler::CloudPrintFlowHandler(const FilePath& path_to_file,
245 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56246 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16247 const std::string& file_type)
[email protected]c7bf7452011-09-12 21:31:50248 : dialog_delegate_(NULL),
249 path_to_file_(path_to_file),
[email protected]a984bdf2011-03-15 20:17:16250 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56251 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16252 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43253}
254
255CloudPrintFlowHandler::~CloudPrintFlowHandler() {
256 // This will also cancel any task in flight.
257 CancelAnyRunningTask();
258}
259
260
[email protected]73852b8f2010-05-14 00:38:12261void CloudPrintFlowHandler::SetDialogDelegate(
262 CloudPrintHtmlDialogDelegate* delegate) {
[email protected]7b748982011-02-14 19:28:23263 // Even if setting a new WebUI, it means any previous task needs
[email protected]73852b8f2010-05-14 00:38:12264 // to be cancelled, it's now invalid.
[email protected]ba4f1132010-10-09 02:02:35265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12266 CancelAnyRunningTask();
267 dialog_delegate_ = delegate;
268}
269
270// Cancels any print data sender we have in flight and removes our
271// reference to it, so when the task that is calling it finishes and
272// removes it's reference, it goes away.
273void CloudPrintFlowHandler::CancelAnyRunningTask() {
[email protected]ba4f1132010-10-09 02:02:35274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12275 if (print_data_sender_.get()) {
276 print_data_sender_->CancelPrintDataFile();
277 print_data_sender_ = NULL;
278 }
279}
280
[email protected]73852b8f2010-05-14 00:38:12281void CloudPrintFlowHandler::RegisterMessages() {
[email protected]7b748982011-02-14 19:28:23282 if (!web_ui_)
[email protected]73852b8f2010-05-14 00:38:12283 return;
284
285 // TODO(scottbyer) - This is where we will register messages for the
286 // UI JS to use. Needed: Call to update page setup parameters.
[email protected]ba4fc242011-10-04 18:56:56287 web_ui_->RegisterMessageCallback("ShowDebugger",
288 base::Bind(&CloudPrintFlowHandler::HandleShowDebugger,
289 base::Unretained(this)));
290 web_ui_->RegisterMessageCallback("SendPrintData",
291 base::Bind(&CloudPrintFlowHandler::HandleSendPrintData,
292 base::Unretained(this)));
293 web_ui_->RegisterMessageCallback("SetPageParameters",
294 base::Bind(&CloudPrintFlowHandler::HandleSetPageParameters,
295 base::Unretained(this)));
[email protected]73852b8f2010-05-14 00:38:12296
[email protected]0eb25c42011-08-11 14:50:14297 // Register for appropriate notifications, and re-direct the URL
298 // to the real server URL, now that we've gotten an HTML dialog
299 // going.
300 NavigationController* controller = &web_ui_->tab_contents()->controller();
301 NavigationEntry* pending_entry = controller->pending_entry();
302 if (pending_entry) {
303 Profile* profile = Profile::FromWebUI(web_ui_);
304 pending_entry->set_url(
305 CloudPrintURL(profile).GetCloudPrintServiceDialogURL());
[email protected]73852b8f2010-05-14 00:38:12306 }
[email protected]0eb25c42011-08-11 14:50:14307 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
[email protected]6c2381d2011-10-19 02:52:53308 content::Source<NavigationController>(controller));
[email protected]73852b8f2010-05-14 00:38:12309}
310
[email protected]6c2381d2011-10-19 02:52:53311void CloudPrintFlowHandler::Observe(
312 int type,
313 const content::NotificationSource& source,
314 const content::NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:27315 if (type == content::NOTIFICATION_LOAD_STOP) {
[email protected]20c52d22011-06-20 22:42:42316 // Take the opportunity to set some (minimal) additional
317 // script permissions required for the web UI.
318 GURL url = web_ui_->tab_contents()->GetURL();
319 GURL dialog_url = CloudPrintURL(
[email protected]0eb25c42011-08-11 14:50:14320 Profile::FromWebUI(web_ui_)).GetCloudPrintServiceDialogURL();
[email protected]20c52d22011-06-20 22:42:42321 if (url.host() == dialog_url.host() &&
322 url.path() == dialog_url.path() &&
323 url.scheme() == dialog_url.scheme()) {
324 RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
325 if (rvh && rvh->delegate()) {
326 WebPreferences webkit_prefs = rvh->delegate()->GetWebkitPrefs();
327 webkit_prefs.allow_scripts_to_close_windows = true;
[email protected]9abd51f2011-09-21 19:11:35328 rvh->UpdateWebkitPreferences(webkit_prefs);
[email protected]20c52d22011-06-20 22:42:42329 } else {
330 DCHECK(false);
331 }
332 }
333
[email protected]73852b8f2010-05-14 00:38:12334 // Choose one or the other. If you need to debug, bring up the
335 // debugger. You can then use the various chrome.send()
336 // registrations above to kick of the various function calls,
337 // including chrome.send("SendPrintData") in the javaScript
338 // console and watch things happen with:
339 // HandleShowDebugger(NULL);
340 HandleSendPrintData(NULL);
341 }
342}
343
[email protected]88942a22010-08-19 20:34:43344void CloudPrintFlowHandler::HandleShowDebugger(const ListValue* args) {
[email protected]73852b8f2010-05-14 00:38:12345 ShowDebugger();
346}
347
348void CloudPrintFlowHandler::ShowDebugger() {
[email protected]7b748982011-02-14 19:28:23349 if (web_ui_) {
350 RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
[email protected]73852b8f2010-05-14 00:38:12351 if (rvh)
[email protected]aebdd072011-07-07 12:36:59352 DevToolsWindow::OpenDevToolsWindow(rvh);
[email protected]73852b8f2010-05-14 00:38:12353 }
354}
355
356scoped_refptr<CloudPrintDataSender>
357CloudPrintFlowHandler::CreateCloudPrintDataSender() {
[email protected]7b748982011-02-14 19:28:23358 DCHECK(web_ui_);
359 print_data_helper_.reset(new CloudPrintDataSenderHelper(web_ui_));
[email protected]a984bdf2011-03-15 20:17:16360 return new CloudPrintDataSender(print_data_helper_.get(),
361 print_job_title_,
[email protected]e8368e92011-08-20 04:05:56362 print_ticket_,
[email protected]a984bdf2011-03-15 20:17:16363 file_type_);
[email protected]73852b8f2010-05-14 00:38:12364}
365
[email protected]88942a22010-08-19 20:34:43366void CloudPrintFlowHandler::HandleSendPrintData(const ListValue* args) {
[email protected]ba4f1132010-10-09 02:02:35367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12368 // This will cancel any ReadPrintDataFile() or SendPrintDataFile()
369 // requests in flight (this is anticipation of when setting page
370 // setup parameters becomes asynchronous and may be set while some
371 // data is in flight). Then we can clear out the print data.
372 CancelAnyRunningTask();
[email protected]7b748982011-02-14 19:28:23373 if (web_ui_) {
[email protected]73852b8f2010-05-14 00:38:12374 print_data_sender_ = CreateCloudPrintDataSender();
[email protected]ba4f1132010-10-09 02:02:35375 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
376 NewRunnableMethod(
377 print_data_sender_.get(),
378 &CloudPrintDataSender::ReadPrintDataFile,
[email protected]a984bdf2011-03-15 20:17:16379 path_to_file_));
[email protected]73852b8f2010-05-14 00:38:12380 }
381}
382
[email protected]88942a22010-08-19 20:34:43383void CloudPrintFlowHandler::HandleSetPageParameters(const ListValue* args) {
[email protected]036056a32011-03-03 21:05:01384 std::string json;
[email protected]e675f7b2011-06-22 17:32:12385 bool ret = args->GetString(0, &json);
386 if (!ret || json.empty()) {
[email protected]036056a32011-03-03 21:05:01387 NOTREACHED() << "Empty json string";
[email protected]73852b8f2010-05-14 00:38:12388 return;
[email protected]036056a32011-03-03 21:05:01389 }
[email protected]73852b8f2010-05-14 00:38:12390
391 // These are backstop default values - 72 dpi to match the screen,
392 // 8.5x11 inch paper with margins subtracted (1/4 inch top, left,
393 // right and 0.56 bottom), and the min page shrink and max page
394 // shrink values appear all over the place with no explanation.
395
396 // TODO(scottbyer): Get a Linux/ChromeOS edge for PrintSettings
397 // working so that we can get the default values from there. Fix up
398 // PrintWebViewHelper to do the same.
399 const int kDPI = 72;
400 const int kWidth = static_cast<int>((8.5-0.25-0.25)*kDPI);
401 const int kHeight = static_cast<int>((11-0.25-0.56)*kDPI);
402 const double kMinPageShrink = 1.25;
403 const double kMaxPageShrink = 2.0;
404
[email protected]1375e3ab2011-03-24 17:07:22405 PrintMsg_Print_Params default_settings;
[email protected]73852b8f2010-05-14 00:38:12406 default_settings.printable_size = gfx::Size(kWidth, kHeight);
407 default_settings.dpi = kDPI;
408 default_settings.min_shrink = kMinPageShrink;
409 default_settings.max_shrink = kMaxPageShrink;
410 default_settings.desired_dpi = kDPI;
411 default_settings.document_cookie = 0;
412 default_settings.selection_only = false;
[email protected]718af822011-08-12 22:11:33413 default_settings.preview_request_id = 0;
414 default_settings.is_first_request = true;
[email protected]73852b8f2010-05-14 00:38:12415
416 if (!GetPageSetupParameters(json, default_settings)) {
417 NOTREACHED();
418 return;
419 }
420
421 // TODO(scottbyer) - Here is where we would kick the originating
422 // renderer thread with these new parameters in order to get it to
[email protected]a984bdf2011-03-15 20:17:16423 // re-generate the PDF data and hand it back to us. window.print() is
[email protected]73852b8f2010-05-14 00:38:12424 // currently synchronous, so there's a lot of work to do to get to
425 // that point.
426}
427
[email protected]ea161da2010-11-02 21:57:35428void CloudPrintFlowHandler::StoreDialogClientSize() const {
[email protected]7b748982011-02-14 19:28:23429 if (web_ui_ && web_ui_->tab_contents() && web_ui_->tab_contents()->view()) {
430 gfx::Size size = web_ui_->tab_contents()->view()->GetContainerSize();
[email protected]0eb25c42011-08-11 14:50:14431 Profile* profile = Profile::FromWebUI(web_ui_);
432 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogWidth,
433 size.width());
434 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogHeight,
435 size.height());
[email protected]ea161da2010-11-02 21:57:35436 }
437}
438
[email protected]73852b8f2010-05-14 00:38:12439CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
[email protected]a984bdf2011-03-15 20:17:16440 const FilePath& path_to_file,
[email protected]73852b8f2010-05-14 00:38:12441 int width, int height,
[email protected]9848c7e2010-06-03 16:06:56442 const std::string& json_arguments,
[email protected]e39027a2011-01-24 21:41:54443 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56444 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16445 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03446 bool modal,
447 bool delete_on_close)
448 : delete_on_close_(delete_on_close),
449 flow_handler_(new CloudPrintFlowHandler(path_to_file,
[email protected]a984bdf2011-03-15 20:17:16450 print_job_title,
[email protected]e8368e92011-08-20 04:05:56451 print_ticket,
[email protected]a984bdf2011-03-15 20:17:16452 file_type)),
[email protected]e39027a2011-01-24 21:41:54453 modal_(modal),
[email protected]6ddda232011-04-22 15:41:47454 owns_flow_handler_(true),
455 path_to_file_(path_to_file) {
[email protected]73852b8f2010-05-14 00:38:12456 Init(width, height, json_arguments);
457}
458
[email protected]05acb55472011-02-03 00:11:07459// For unit testing.
[email protected]73852b8f2010-05-14 00:38:12460CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
461 CloudPrintFlowHandler* flow_handler,
462 int width, int height,
[email protected]e39027a2011-01-24 21:41:54463 const std::string& json_arguments,
[email protected]d955fc92011-09-19 20:49:03464 bool modal,
465 bool delete_on_close)
466 : delete_on_close_(delete_on_close),
467 flow_handler_(flow_handler),
[email protected]e39027a2011-01-24 21:41:54468 modal_(modal),
[email protected]18137e02010-05-25 21:10:35469 owns_flow_handler_(true) {
[email protected]73852b8f2010-05-14 00:38:12470 Init(width, height, json_arguments);
471}
472
[email protected]05acb55472011-02-03 00:11:07473void CloudPrintHtmlDialogDelegate::Init(int width, int height,
474 const std::string& json_arguments) {
[email protected]73852b8f2010-05-14 00:38:12475 // This information is needed to show the dialog HTML content.
[email protected]ba4f1132010-10-09 02:02:35476 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]89f550b2011-06-08 18:34:03477 params_.url = GURL(chrome::kChromeUICloudPrintResourcesURL);
[email protected]73852b8f2010-05-14 00:38:12478 params_.height = height;
479 params_.width = width;
480 params_.json_input = json_arguments;
481
482 flow_handler_->SetDialogDelegate(this);
[email protected]e39027a2011-01-24 21:41:54483 // If we're not modal we can show the dialog with no browser.
484 // We need this to keep Chrome alive while our dialog is up.
485 if (!modal_)
486 BrowserList::StartKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12487}
488
489CloudPrintHtmlDialogDelegate::~CloudPrintHtmlDialogDelegate() {
490 // If the flow_handler_ is about to outlive us because we don't own
491 // it anymore, we need to have it remove it's reference to us.
[email protected]ba4f1132010-10-09 02:02:35492 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12493 flow_handler_->SetDialogDelegate(NULL);
494 if (owns_flow_handler_) {
495 delete flow_handler_;
496 }
497}
498
499bool CloudPrintHtmlDialogDelegate::IsDialogModal() const {
[email protected]e39027a2011-01-24 21:41:54500 return modal_;
[email protected]73852b8f2010-05-14 00:38:12501}
502
[email protected]bdae5c12011-08-05 21:49:06503string16 CloudPrintHtmlDialogDelegate::GetDialogTitle() const {
504 return string16();
[email protected]73852b8f2010-05-14 00:38:12505}
506
507GURL CloudPrintHtmlDialogDelegate::GetDialogContentURL() const {
508 return params_.url;
509}
510
[email protected]36e12172011-02-08 23:46:02511void CloudPrintHtmlDialogDelegate::GetWebUIMessageHandlers(
512 std::vector<WebUIMessageHandler*>* handlers) const {
[email protected]73852b8f2010-05-14 00:38:12513 handlers->push_back(flow_handler_);
514 // We don't own flow_handler_ anymore, but it sticks around until at
515 // least right after OnDialogClosed() is called (and this object is
516 // destroyed).
517 owns_flow_handler_ = false;
518}
519
520void CloudPrintHtmlDialogDelegate::GetDialogSize(gfx::Size* size) const {
521 size->set_width(params_.width);
522 size->set_height(params_.height);
523}
524
525std::string CloudPrintHtmlDialogDelegate::GetDialogArgs() const {
526 return params_.json_input;
527}
528
529void CloudPrintHtmlDialogDelegate::OnDialogClosed(
530 const std::string& json_retval) {
[email protected]ea161da2010-11-02 21:57:35531 // Get the final dialog size and store it.
532 flow_handler_->StoreDialogClientSize();
[email protected]6ddda232011-04-22 15:41:47533
[email protected]d955fc92011-09-19 20:49:03534 if (delete_on_close_) {
[email protected]6ddda232011-04-22 15:41:47535 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
536 NewRunnableFunction(&internal_cloud_print_helpers::Delete,
537 path_to_file_));
538 }
539
[email protected]e39027a2011-01-24 21:41:54540 // If we're modal we can show the dialog with no browser.
541 // End the keep-alive so that Chrome can exit.
542 if (!modal_)
543 BrowserList::EndKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12544 delete this;
545}
546
[email protected]18137e02010-05-25 21:10:35547void CloudPrintHtmlDialogDelegate::OnCloseContents(TabContents* source,
548 bool* out_close_dialog) {
549 if (out_close_dialog)
550 *out_close_dialog = true;
551}
552
[email protected]ea161da2010-11-02 21:57:35553bool CloudPrintHtmlDialogDelegate::ShouldShowDialogTitle() const {
554 return false;
555}
556
[email protected]34478212011-04-19 01:35:46557bool CloudPrintHtmlDialogDelegate::HandleContextMenu(
558 const ContextMenuParams& params) {
559 return true;
560}
561
[email protected]d955fc92011-09-19 20:49:03562void CreatePrintDialogForBytesImpl(scoped_refptr<RefCountedBytes> data,
563 const string16& print_job_title,
564 const string16& print_ticket,
565 const std::string& file_type,
566 bool modal) {
567 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
568 // TODO([email protected]) Writing the PDF to a file before printing
569 // is wasteful. Modify the dialog flow to pull PDF data from memory.
570 // See http://code.google.com/p/chromium/issues/detail?id=44093
571 FilePath path;
572 if (file_util::CreateTemporaryFile(&path)) {
573 file_util::WriteFile(path,
574 reinterpret_cast<const char*>(data->front()),
575 data->size());
576 }
577 print_dialog_cloud::CreatePrintDialogForFile(path,
578 print_job_title,
579 print_ticket,
580 file_type,
581 modal,
582 true);
583}
584
[email protected]6085c70d2011-03-22 22:51:07585// Called from the UI thread, starts up the dialog.
586void CreateDialogImpl(const FilePath& path_to_file,
587 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56588 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07589 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03590 bool modal,
591 bool delete_on_close) {
[email protected]ba4f1132010-10-09 02:02:35592 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6085c70d2011-03-22 22:51:07593 Browser* browser = BrowserList::GetLastActive();
[email protected]73852b8f2010-05-14 00:38:12594
[email protected]ea161da2010-11-02 21:57:35595 const int kDefaultWidth = 497;
596 const int kDefaultHeight = 332;
[email protected]05acb55472011-02-03 00:11:07597 string16 job_title = print_job_title;
[email protected]e39027a2011-01-24 21:41:54598 Profile* profile = NULL;
[email protected]05acb55472011-02-03 00:11:07599 if (modal) {
[email protected]6085c70d2011-03-22 22:51:07600 DCHECK(browser);
601 if (job_title.empty() && browser->GetSelectedTabContents())
602 job_title = browser->GetSelectedTabContents()->GetTitle();
603 profile = browser->GetProfile();
[email protected]e39027a2011-01-24 21:41:54604 } else {
[email protected]0744cc72011-08-12 12:05:45605 std::vector<Profile*> loaded_profiles =
606 g_browser_process->profile_manager()->GetLoadedProfiles();
607 DCHECK_GT(loaded_profiles.size(), 0U);
608 profile = loaded_profiles[0];
[email protected]e39027a2011-01-24 21:41:54609 }
610 DCHECK(profile);
[email protected]05acb55472011-02-03 00:11:07611 PrefService* pref_service = profile->GetPrefs();
[email protected]ea161da2010-11-02 21:57:35612 DCHECK(pref_service);
613 if (!pref_service->FindPreference(prefs::kCloudPrintDialogWidth)) {
614 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogWidth,
[email protected]d36f941b2011-05-09 06:19:16615 kDefaultWidth,
616 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35617 }
618 if (!pref_service->FindPreference(prefs::kCloudPrintDialogHeight)) {
619 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogHeight,
[email protected]d36f941b2011-05-09 06:19:16620 kDefaultHeight,
621 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35622 }
623
624 int width = pref_service->GetInteger(prefs::kCloudPrintDialogWidth);
625 int height = pref_service->GetInteger(prefs::kCloudPrintDialogHeight);
[email protected]e39027a2011-01-24 21:41:54626
[email protected]73852b8f2010-05-14 00:38:12627 HtmlDialogUIDelegate* dialog_delegate =
628 new internal_cloud_print_helpers::CloudPrintHtmlDialogDelegate(
[email protected]e8368e92011-08-20 04:05:56629 path_to_file, width, height, std::string(), job_title, print_ticket,
[email protected]d955fc92011-09-19 20:49:03630 file_type, modal, delete_on_close);
[email protected]05acb55472011-02-03 00:11:07631 if (modal) {
[email protected]6085c70d2011-03-22 22:51:07632 DCHECK(browser);
633 browser->BrowserShowHtmlDialog(dialog_delegate, NULL);
[email protected]e39027a2011-01-24 21:41:54634 } else {
[email protected]eb2d7902011-02-02 18:19:56635 browser::ShowHtmlDialog(NULL, profile, dialog_delegate);
[email protected]e39027a2011-01-24 21:41:54636 }
[email protected]73852b8f2010-05-14 00:38:12637}
[email protected]6085c70d2011-03-22 22:51:07638
[email protected]6ddda232011-04-22 15:41:47639// Provides a runnable function to delete a file.
640void Delete(const FilePath& file_path) {
641 file_util::Delete(file_path, false);
642}
643
[email protected]6085c70d2011-03-22 22:51:07644} // namespace internal_cloud_print_helpers
645
646namespace print_dialog_cloud {
647
648// Called on the FILE or UI thread. This is the main entry point into creating
649// the dialog.
650
651// TODO(scottbyer): The signature here will need to change as the
652// workflow through the printing code changes to allow for dynamically
653// changing page setup parameters while the dialog is active.
654void CreatePrintDialogForFile(const FilePath& path_to_file,
655 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56656 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07657 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03658 bool modal,
659 bool delete_on_close) {
[email protected]6085c70d2011-03-22 22:51:07660 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE) ||
661 BrowserThread::CurrentlyOn(BrowserThread::UI));
662
663 BrowserThread::PostTask(
664 BrowserThread::UI, FROM_HERE,
665 NewRunnableFunction(&internal_cloud_print_helpers::CreateDialogImpl,
666 path_to_file,
667 print_job_title,
[email protected]e8368e92011-08-20 04:05:56668 print_ticket,
[email protected]6085c70d2011-03-22 22:51:07669 file_type,
[email protected]d955fc92011-09-19 20:49:03670 modal,
671 delete_on_close));
672}
673
674void CreatePrintDialogForBytes(scoped_refptr<RefCountedBytes> data,
675 const string16& print_job_title,
676 const string16& print_ticket,
677 const std::string& file_type,
678 bool modal) {
679 // TODO([email protected]) Avoid cloning the PDF data. Make use of a
680 // shared memory object instead.
681 // http://code.google.com/p/chromium/issues/detail?id=44093
682 scoped_refptr<RefCountedBytes> cloned_data(new RefCountedBytes(data->data()));
683 BrowserThread::PostTask(
684 BrowserThread::FILE, FROM_HERE,
685 NewRunnableFunction(
686 &internal_cloud_print_helpers::CreatePrintDialogForBytesImpl,
687 cloned_data,
688 print_job_title,
689 print_ticket,
690 file_type,
691 modal));
[email protected]6085c70d2011-03-22 22:51:07692}
693
[email protected]65c9d89a2011-04-13 21:02:39694bool CreatePrintDialogFromCommandLine(const CommandLine& command_line) {
695 if (!command_line.GetSwitchValuePath(switches::kCloudPrintFile).empty()) {
696 FilePath cloud_print_file;
697 cloud_print_file =
698 command_line.GetSwitchValuePath(switches::kCloudPrintFile);
699 if (!cloud_print_file.empty()) {
700 string16 print_job_title;
[email protected]e8368e92011-08-20 04:05:56701 string16 print_job_print_ticket;
[email protected]65c9d89a2011-04-13 21:02:39702 if (command_line.HasSwitch(switches::kCloudPrintJobTitle)) {
[email protected]e8368e92011-08-20 04:05:56703 print_job_title =
704 internal_cloud_print_helpers::GetSwitchValueString16(
705 command_line, switches::kCloudPrintJobTitle);
706 }
707 if (command_line.HasSwitch(switches::kCloudPrintPrintTicket)) {
708 print_job_print_ticket =
709 internal_cloud_print_helpers::GetSwitchValueString16(
710 command_line, switches::kCloudPrintPrintTicket);
[email protected]65c9d89a2011-04-13 21:02:39711 }
712 std::string file_type = "application/pdf";
713 if (command_line.HasSwitch(switches::kCloudPrintFileType)) {
714 file_type = command_line.GetSwitchValueASCII(
715 switches::kCloudPrintFileType);
716 }
[email protected]e8368e92011-08-20 04:05:56717
[email protected]d955fc92011-09-19 20:49:03718 bool delete_on_close = CommandLine::ForCurrentProcess()->HasSwitch(
719 switches::kCloudPrintDeleteFile);
720
[email protected]65c9d89a2011-04-13 21:02:39721 print_dialog_cloud::CreatePrintDialogForFile(cloud_print_file,
722 print_job_title,
[email protected]e8368e92011-08-20 04:05:56723 print_job_print_ticket,
[email protected]65c9d89a2011-04-13 21:02:39724 file_type,
[email protected]d955fc92011-09-19 20:49:03725 false,
726 delete_on_close);
[email protected]65c9d89a2011-04-13 21:02:39727 return true;
728 }
729 }
730 return false;
731}
732
[email protected]6085c70d2011-03-22 22:51:07733} // end namespace