blob: 7711aed0682cf6b5648d91132c8eb5783a4c07f1 [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/browser_thread.h"
29#include "content/browser/renderer_host/render_view_host.h"
30#include "content/browser/tab_contents/tab_contents.h"
31#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]432115822011-07-10 15:52:2733#include "content/common/content_notification_types.h"
[email protected]ebbbb9f2011-03-09 13:16:1434#include "content/common/notification_registrar.h"
35#include "content/common/notification_source.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,
308 Source<NavigationController>(controller));
[email protected]73852b8f2010-05-14 00:38:12309}
310
[email protected]432115822011-07-10 15:52:27311void CloudPrintFlowHandler::Observe(int type,
[email protected]73852b8f2010-05-14 00:38:12312 const NotificationSource& source,
313 const NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:27314 if (type == content::NOTIFICATION_LOAD_STOP) {
[email protected]20c52d22011-06-20 22:42:42315 // Take the opportunity to set some (minimal) additional
316 // script permissions required for the web UI.
317 GURL url = web_ui_->tab_contents()->GetURL();
318 GURL dialog_url = CloudPrintURL(
[email protected]0eb25c42011-08-11 14:50:14319 Profile::FromWebUI(web_ui_)).GetCloudPrintServiceDialogURL();
[email protected]20c52d22011-06-20 22:42:42320 if (url.host() == dialog_url.host() &&
321 url.path() == dialog_url.path() &&
322 url.scheme() == dialog_url.scheme()) {
323 RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
324 if (rvh && rvh->delegate()) {
325 WebPreferences webkit_prefs = rvh->delegate()->GetWebkitPrefs();
326 webkit_prefs.allow_scripts_to_close_windows = true;
[email protected]9abd51f2011-09-21 19:11:35327 rvh->UpdateWebkitPreferences(webkit_prefs);
[email protected]20c52d22011-06-20 22:42:42328 } else {
329 DCHECK(false);
330 }
331 }
332
[email protected]73852b8f2010-05-14 00:38:12333 // Choose one or the other. If you need to debug, bring up the
334 // debugger. You can then use the various chrome.send()
335 // registrations above to kick of the various function calls,
336 // including chrome.send("SendPrintData") in the javaScript
337 // console and watch things happen with:
338 // HandleShowDebugger(NULL);
339 HandleSendPrintData(NULL);
340 }
341}
342
[email protected]88942a22010-08-19 20:34:43343void CloudPrintFlowHandler::HandleShowDebugger(const ListValue* args) {
[email protected]73852b8f2010-05-14 00:38:12344 ShowDebugger();
345}
346
347void CloudPrintFlowHandler::ShowDebugger() {
[email protected]7b748982011-02-14 19:28:23348 if (web_ui_) {
349 RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
[email protected]73852b8f2010-05-14 00:38:12350 if (rvh)
[email protected]aebdd072011-07-07 12:36:59351 DevToolsWindow::OpenDevToolsWindow(rvh);
[email protected]73852b8f2010-05-14 00:38:12352 }
353}
354
355scoped_refptr<CloudPrintDataSender>
356CloudPrintFlowHandler::CreateCloudPrintDataSender() {
[email protected]7b748982011-02-14 19:28:23357 DCHECK(web_ui_);
358 print_data_helper_.reset(new CloudPrintDataSenderHelper(web_ui_));
[email protected]a984bdf2011-03-15 20:17:16359 return new CloudPrintDataSender(print_data_helper_.get(),
360 print_job_title_,
[email protected]e8368e92011-08-20 04:05:56361 print_ticket_,
[email protected]a984bdf2011-03-15 20:17:16362 file_type_);
[email protected]73852b8f2010-05-14 00:38:12363}
364
[email protected]88942a22010-08-19 20:34:43365void CloudPrintFlowHandler::HandleSendPrintData(const ListValue* args) {
[email protected]ba4f1132010-10-09 02:02:35366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12367 // This will cancel any ReadPrintDataFile() or SendPrintDataFile()
368 // requests in flight (this is anticipation of when setting page
369 // setup parameters becomes asynchronous and may be set while some
370 // data is in flight). Then we can clear out the print data.
371 CancelAnyRunningTask();
[email protected]7b748982011-02-14 19:28:23372 if (web_ui_) {
[email protected]73852b8f2010-05-14 00:38:12373 print_data_sender_ = CreateCloudPrintDataSender();
[email protected]ba4f1132010-10-09 02:02:35374 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
375 NewRunnableMethod(
376 print_data_sender_.get(),
377 &CloudPrintDataSender::ReadPrintDataFile,
[email protected]a984bdf2011-03-15 20:17:16378 path_to_file_));
[email protected]73852b8f2010-05-14 00:38:12379 }
380}
381
[email protected]88942a22010-08-19 20:34:43382void CloudPrintFlowHandler::HandleSetPageParameters(const ListValue* args) {
[email protected]036056a32011-03-03 21:05:01383 std::string json;
[email protected]e675f7b2011-06-22 17:32:12384 bool ret = args->GetString(0, &json);
385 if (!ret || json.empty()) {
[email protected]036056a32011-03-03 21:05:01386 NOTREACHED() << "Empty json string";
[email protected]73852b8f2010-05-14 00:38:12387 return;
[email protected]036056a32011-03-03 21:05:01388 }
[email protected]73852b8f2010-05-14 00:38:12389
390 // These are backstop default values - 72 dpi to match the screen,
391 // 8.5x11 inch paper with margins subtracted (1/4 inch top, left,
392 // right and 0.56 bottom), and the min page shrink and max page
393 // shrink values appear all over the place with no explanation.
394
395 // TODO(scottbyer): Get a Linux/ChromeOS edge for PrintSettings
396 // working so that we can get the default values from there. Fix up
397 // PrintWebViewHelper to do the same.
398 const int kDPI = 72;
399 const int kWidth = static_cast<int>((8.5-0.25-0.25)*kDPI);
400 const int kHeight = static_cast<int>((11-0.25-0.56)*kDPI);
401 const double kMinPageShrink = 1.25;
402 const double kMaxPageShrink = 2.0;
403
[email protected]1375e3ab2011-03-24 17:07:22404 PrintMsg_Print_Params default_settings;
[email protected]73852b8f2010-05-14 00:38:12405 default_settings.printable_size = gfx::Size(kWidth, kHeight);
406 default_settings.dpi = kDPI;
407 default_settings.min_shrink = kMinPageShrink;
408 default_settings.max_shrink = kMaxPageShrink;
409 default_settings.desired_dpi = kDPI;
410 default_settings.document_cookie = 0;
411 default_settings.selection_only = false;
[email protected]718af822011-08-12 22:11:33412 default_settings.preview_request_id = 0;
413 default_settings.is_first_request = true;
[email protected]73852b8f2010-05-14 00:38:12414
415 if (!GetPageSetupParameters(json, default_settings)) {
416 NOTREACHED();
417 return;
418 }
419
420 // TODO(scottbyer) - Here is where we would kick the originating
421 // renderer thread with these new parameters in order to get it to
[email protected]a984bdf2011-03-15 20:17:16422 // re-generate the PDF data and hand it back to us. window.print() is
[email protected]73852b8f2010-05-14 00:38:12423 // currently synchronous, so there's a lot of work to do to get to
424 // that point.
425}
426
[email protected]ea161da2010-11-02 21:57:35427void CloudPrintFlowHandler::StoreDialogClientSize() const {
[email protected]7b748982011-02-14 19:28:23428 if (web_ui_ && web_ui_->tab_contents() && web_ui_->tab_contents()->view()) {
429 gfx::Size size = web_ui_->tab_contents()->view()->GetContainerSize();
[email protected]0eb25c42011-08-11 14:50:14430 Profile* profile = Profile::FromWebUI(web_ui_);
431 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogWidth,
432 size.width());
433 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogHeight,
434 size.height());
[email protected]ea161da2010-11-02 21:57:35435 }
436}
437
[email protected]73852b8f2010-05-14 00:38:12438CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
[email protected]a984bdf2011-03-15 20:17:16439 const FilePath& path_to_file,
[email protected]73852b8f2010-05-14 00:38:12440 int width, int height,
[email protected]9848c7e2010-06-03 16:06:56441 const std::string& json_arguments,
[email protected]e39027a2011-01-24 21:41:54442 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56443 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16444 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03445 bool modal,
446 bool delete_on_close)
447 : delete_on_close_(delete_on_close),
448 flow_handler_(new CloudPrintFlowHandler(path_to_file,
[email protected]a984bdf2011-03-15 20:17:16449 print_job_title,
[email protected]e8368e92011-08-20 04:05:56450 print_ticket,
[email protected]a984bdf2011-03-15 20:17:16451 file_type)),
[email protected]e39027a2011-01-24 21:41:54452 modal_(modal),
[email protected]6ddda232011-04-22 15:41:47453 owns_flow_handler_(true),
454 path_to_file_(path_to_file) {
[email protected]73852b8f2010-05-14 00:38:12455 Init(width, height, json_arguments);
456}
457
[email protected]05acb55472011-02-03 00:11:07458// For unit testing.
[email protected]73852b8f2010-05-14 00:38:12459CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
460 CloudPrintFlowHandler* flow_handler,
461 int width, int height,
[email protected]e39027a2011-01-24 21:41:54462 const std::string& json_arguments,
[email protected]d955fc92011-09-19 20:49:03463 bool modal,
464 bool delete_on_close)
465 : delete_on_close_(delete_on_close),
466 flow_handler_(flow_handler),
[email protected]e39027a2011-01-24 21:41:54467 modal_(modal),
[email protected]18137e02010-05-25 21:10:35468 owns_flow_handler_(true) {
[email protected]73852b8f2010-05-14 00:38:12469 Init(width, height, json_arguments);
470}
471
[email protected]05acb55472011-02-03 00:11:07472void CloudPrintHtmlDialogDelegate::Init(int width, int height,
473 const std::string& json_arguments) {
[email protected]73852b8f2010-05-14 00:38:12474 // This information is needed to show the dialog HTML content.
[email protected]ba4f1132010-10-09 02:02:35475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]89f550b2011-06-08 18:34:03476 params_.url = GURL(chrome::kChromeUICloudPrintResourcesURL);
[email protected]73852b8f2010-05-14 00:38:12477 params_.height = height;
478 params_.width = width;
479 params_.json_input = json_arguments;
480
481 flow_handler_->SetDialogDelegate(this);
[email protected]e39027a2011-01-24 21:41:54482 // If we're not modal we can show the dialog with no browser.
483 // We need this to keep Chrome alive while our dialog is up.
484 if (!modal_)
485 BrowserList::StartKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12486}
487
488CloudPrintHtmlDialogDelegate::~CloudPrintHtmlDialogDelegate() {
489 // If the flow_handler_ is about to outlive us because we don't own
490 // it anymore, we need to have it remove it's reference to us.
[email protected]ba4f1132010-10-09 02:02:35491 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12492 flow_handler_->SetDialogDelegate(NULL);
493 if (owns_flow_handler_) {
494 delete flow_handler_;
495 }
496}
497
498bool CloudPrintHtmlDialogDelegate::IsDialogModal() const {
[email protected]e39027a2011-01-24 21:41:54499 return modal_;
[email protected]73852b8f2010-05-14 00:38:12500}
501
[email protected]bdae5c12011-08-05 21:49:06502string16 CloudPrintHtmlDialogDelegate::GetDialogTitle() const {
503 return string16();
[email protected]73852b8f2010-05-14 00:38:12504}
505
506GURL CloudPrintHtmlDialogDelegate::GetDialogContentURL() const {
507 return params_.url;
508}
509
[email protected]36e12172011-02-08 23:46:02510void CloudPrintHtmlDialogDelegate::GetWebUIMessageHandlers(
511 std::vector<WebUIMessageHandler*>* handlers) const {
[email protected]73852b8f2010-05-14 00:38:12512 handlers->push_back(flow_handler_);
513 // We don't own flow_handler_ anymore, but it sticks around until at
514 // least right after OnDialogClosed() is called (and this object is
515 // destroyed).
516 owns_flow_handler_ = false;
517}
518
519void CloudPrintHtmlDialogDelegate::GetDialogSize(gfx::Size* size) const {
520 size->set_width(params_.width);
521 size->set_height(params_.height);
522}
523
524std::string CloudPrintHtmlDialogDelegate::GetDialogArgs() const {
525 return params_.json_input;
526}
527
528void CloudPrintHtmlDialogDelegate::OnDialogClosed(
529 const std::string& json_retval) {
[email protected]ea161da2010-11-02 21:57:35530 // Get the final dialog size and store it.
531 flow_handler_->StoreDialogClientSize();
[email protected]6ddda232011-04-22 15:41:47532
[email protected]d955fc92011-09-19 20:49:03533 if (delete_on_close_) {
[email protected]6ddda232011-04-22 15:41:47534 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
535 NewRunnableFunction(&internal_cloud_print_helpers::Delete,
536 path_to_file_));
537 }
538
[email protected]e39027a2011-01-24 21:41:54539 // If we're modal we can show the dialog with no browser.
540 // End the keep-alive so that Chrome can exit.
541 if (!modal_)
542 BrowserList::EndKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12543 delete this;
544}
545
[email protected]18137e02010-05-25 21:10:35546void CloudPrintHtmlDialogDelegate::OnCloseContents(TabContents* source,
547 bool* out_close_dialog) {
548 if (out_close_dialog)
549 *out_close_dialog = true;
550}
551
[email protected]ea161da2010-11-02 21:57:35552bool CloudPrintHtmlDialogDelegate::ShouldShowDialogTitle() const {
553 return false;
554}
555
[email protected]34478212011-04-19 01:35:46556bool CloudPrintHtmlDialogDelegate::HandleContextMenu(
557 const ContextMenuParams& params) {
558 return true;
559}
560
[email protected]d955fc92011-09-19 20:49:03561void CreatePrintDialogForBytesImpl(scoped_refptr<RefCountedBytes> data,
562 const string16& print_job_title,
563 const string16& print_ticket,
564 const std::string& file_type,
565 bool modal) {
566 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
567 // TODO([email protected]) Writing the PDF to a file before printing
568 // is wasteful. Modify the dialog flow to pull PDF data from memory.
569 // See http://code.google.com/p/chromium/issues/detail?id=44093
570 FilePath path;
571 if (file_util::CreateTemporaryFile(&path)) {
572 file_util::WriteFile(path,
573 reinterpret_cast<const char*>(data->front()),
574 data->size());
575 }
576 print_dialog_cloud::CreatePrintDialogForFile(path,
577 print_job_title,
578 print_ticket,
579 file_type,
580 modal,
581 true);
582}
583
[email protected]6085c70d2011-03-22 22:51:07584// Called from the UI thread, starts up the dialog.
585void CreateDialogImpl(const FilePath& path_to_file,
586 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56587 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07588 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03589 bool modal,
590 bool delete_on_close) {
[email protected]ba4f1132010-10-09 02:02:35591 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6085c70d2011-03-22 22:51:07592 Browser* browser = BrowserList::GetLastActive();
[email protected]73852b8f2010-05-14 00:38:12593
[email protected]ea161da2010-11-02 21:57:35594 const int kDefaultWidth = 497;
595 const int kDefaultHeight = 332;
[email protected]05acb55472011-02-03 00:11:07596 string16 job_title = print_job_title;
[email protected]e39027a2011-01-24 21:41:54597 Profile* profile = NULL;
[email protected]05acb55472011-02-03 00:11:07598 if (modal) {
[email protected]6085c70d2011-03-22 22:51:07599 DCHECK(browser);
600 if (job_title.empty() && browser->GetSelectedTabContents())
601 job_title = browser->GetSelectedTabContents()->GetTitle();
602 profile = browser->GetProfile();
[email protected]e39027a2011-01-24 21:41:54603 } else {
[email protected]0744cc72011-08-12 12:05:45604 std::vector<Profile*> loaded_profiles =
605 g_browser_process->profile_manager()->GetLoadedProfiles();
606 DCHECK_GT(loaded_profiles.size(), 0U);
607 profile = loaded_profiles[0];
[email protected]e39027a2011-01-24 21:41:54608 }
609 DCHECK(profile);
[email protected]05acb55472011-02-03 00:11:07610 PrefService* pref_service = profile->GetPrefs();
[email protected]ea161da2010-11-02 21:57:35611 DCHECK(pref_service);
612 if (!pref_service->FindPreference(prefs::kCloudPrintDialogWidth)) {
613 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogWidth,
[email protected]d36f941b2011-05-09 06:19:16614 kDefaultWidth,
615 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35616 }
617 if (!pref_service->FindPreference(prefs::kCloudPrintDialogHeight)) {
618 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogHeight,
[email protected]d36f941b2011-05-09 06:19:16619 kDefaultHeight,
620 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35621 }
622
623 int width = pref_service->GetInteger(prefs::kCloudPrintDialogWidth);
624 int height = pref_service->GetInteger(prefs::kCloudPrintDialogHeight);
[email protected]e39027a2011-01-24 21:41:54625
[email protected]73852b8f2010-05-14 00:38:12626 HtmlDialogUIDelegate* dialog_delegate =
627 new internal_cloud_print_helpers::CloudPrintHtmlDialogDelegate(
[email protected]e8368e92011-08-20 04:05:56628 path_to_file, width, height, std::string(), job_title, print_ticket,
[email protected]d955fc92011-09-19 20:49:03629 file_type, modal, delete_on_close);
[email protected]05acb55472011-02-03 00:11:07630 if (modal) {
[email protected]6085c70d2011-03-22 22:51:07631 DCHECK(browser);
632 browser->BrowserShowHtmlDialog(dialog_delegate, NULL);
[email protected]e39027a2011-01-24 21:41:54633 } else {
[email protected]eb2d7902011-02-02 18:19:56634 browser::ShowHtmlDialog(NULL, profile, dialog_delegate);
[email protected]e39027a2011-01-24 21:41:54635 }
[email protected]73852b8f2010-05-14 00:38:12636}
[email protected]6085c70d2011-03-22 22:51:07637
[email protected]6ddda232011-04-22 15:41:47638// Provides a runnable function to delete a file.
639void Delete(const FilePath& file_path) {
640 file_util::Delete(file_path, false);
641}
642
[email protected]6085c70d2011-03-22 22:51:07643} // namespace internal_cloud_print_helpers
644
645namespace print_dialog_cloud {
646
647// Called on the FILE or UI thread. This is the main entry point into creating
648// the dialog.
649
650// TODO(scottbyer): The signature here will need to change as the
651// workflow through the printing code changes to allow for dynamically
652// changing page setup parameters while the dialog is active.
653void CreatePrintDialogForFile(const FilePath& path_to_file,
654 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56655 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07656 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03657 bool modal,
658 bool delete_on_close) {
[email protected]6085c70d2011-03-22 22:51:07659 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE) ||
660 BrowserThread::CurrentlyOn(BrowserThread::UI));
661
662 BrowserThread::PostTask(
663 BrowserThread::UI, FROM_HERE,
664 NewRunnableFunction(&internal_cloud_print_helpers::CreateDialogImpl,
665 path_to_file,
666 print_job_title,
[email protected]e8368e92011-08-20 04:05:56667 print_ticket,
[email protected]6085c70d2011-03-22 22:51:07668 file_type,
[email protected]d955fc92011-09-19 20:49:03669 modal,
670 delete_on_close));
671}
672
673void CreatePrintDialogForBytes(scoped_refptr<RefCountedBytes> data,
674 const string16& print_job_title,
675 const string16& print_ticket,
676 const std::string& file_type,
677 bool modal) {
678 // TODO([email protected]) Avoid cloning the PDF data. Make use of a
679 // shared memory object instead.
680 // http://code.google.com/p/chromium/issues/detail?id=44093
681 scoped_refptr<RefCountedBytes> cloned_data(new RefCountedBytes(data->data()));
682 BrowserThread::PostTask(
683 BrowserThread::FILE, FROM_HERE,
684 NewRunnableFunction(
685 &internal_cloud_print_helpers::CreatePrintDialogForBytesImpl,
686 cloned_data,
687 print_job_title,
688 print_ticket,
689 file_type,
690 modal));
[email protected]6085c70d2011-03-22 22:51:07691}
692
[email protected]65c9d89a2011-04-13 21:02:39693bool CreatePrintDialogFromCommandLine(const CommandLine& command_line) {
694 if (!command_line.GetSwitchValuePath(switches::kCloudPrintFile).empty()) {
695 FilePath cloud_print_file;
696 cloud_print_file =
697 command_line.GetSwitchValuePath(switches::kCloudPrintFile);
698 if (!cloud_print_file.empty()) {
699 string16 print_job_title;
[email protected]e8368e92011-08-20 04:05:56700 string16 print_job_print_ticket;
[email protected]65c9d89a2011-04-13 21:02:39701 if (command_line.HasSwitch(switches::kCloudPrintJobTitle)) {
[email protected]e8368e92011-08-20 04:05:56702 print_job_title =
703 internal_cloud_print_helpers::GetSwitchValueString16(
704 command_line, switches::kCloudPrintJobTitle);
705 }
706 if (command_line.HasSwitch(switches::kCloudPrintPrintTicket)) {
707 print_job_print_ticket =
708 internal_cloud_print_helpers::GetSwitchValueString16(
709 command_line, switches::kCloudPrintPrintTicket);
[email protected]65c9d89a2011-04-13 21:02:39710 }
711 std::string file_type = "application/pdf";
712 if (command_line.HasSwitch(switches::kCloudPrintFileType)) {
713 file_type = command_line.GetSwitchValueASCII(
714 switches::kCloudPrintFileType);
715 }
[email protected]e8368e92011-08-20 04:05:56716
[email protected]d955fc92011-09-19 20:49:03717 bool delete_on_close = CommandLine::ForCurrentProcess()->HasSwitch(
718 switches::kCloudPrintDeleteFile);
719
[email protected]65c9d89a2011-04-13 21:02:39720 print_dialog_cloud::CreatePrintDialogForFile(cloud_print_file,
721 print_job_title,
[email protected]e8368e92011-08-20 04:05:56722 print_job_print_ticket,
[email protected]65c9d89a2011-04-13 21:02:39723 file_type,
[email protected]d955fc92011-09-19 20:49:03724 false,
725 delete_on_close);
[email protected]65c9d89a2011-04-13 21:02:39726 return true;
727 }
728 }
729 return false;
730}
731
[email protected]6085c70d2011-03-22 22:51:07732} // end namespace