blob: 8a2e56ee8c73e5304d759e9df74a81bdb94c8cb9 [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]65c9d89a2011-04-13 21:02:3925#include "chrome/common/chrome_switches.h"
[email protected]ea161da2010-11-02 21:57:3526#include "chrome/common/pref_names.h"
[email protected]1375e3ab2011-03-24 17:07:2227#include "chrome/common/print_messages.h"
[email protected]73852b8f2010-05-14 00:38:1228#include "chrome/common/url_constants.h"
[email protected]5f945a0e2011-03-01 17:47:5329#include "content/browser/renderer_host/render_view_host.h"
[email protected]5f945a0e2011-03-01 17:47:5330#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]c38831a12011-10-28 12:44:4933#include "content/public/browser/browser_thread.h"
[email protected]022af742011-12-28 18:37:2534#include "content/public/browser/navigation_entry.h"
[email protected]6c2381d2011-10-19 02:52:5335#include "content/public/browser/notification_registrar.h"
36#include "content/public/browser/notification_source.h"
[email protected]0d6e9bd2011-10-18 04:29:1637#include "content/public/browser/notification_types.h"
[email protected]c051a1b2011-01-21 23:30:1738#include "ui/base/l10n/l10n_util.h"
[email protected]939856a2010-08-24 20:29:0239#include "webkit/glue/webpreferences.h"
[email protected]73852b8f2010-05-14 00:38:1240
41#include "grit/generated_resources.h"
42
43// This module implements the UI support in Chrome for cloud printing.
44// This means hosting a dialog containing HTML/JavaScript and using
45// the published cloud print user interface integration APIs to get
46// page setup settings from the dialog contents and provide the
[email protected]a984bdf2011-03-15 20:17:1647// generated print data to the dialog contents for uploading to the
[email protected]73852b8f2010-05-14 00:38:1248// cloud print service.
49
50// Currently, the flow between these classes is as follows:
51
[email protected]a984bdf2011-03-15 20:17:1652// PrintDialogCloud::CreatePrintDialogForFile is called from
[email protected]73852b8f2010-05-14 00:38:1253// resource_message_filter_gtk.cc once the renderer has informed the
[email protected]a984bdf2011-03-15 20:17:1654// renderer host that print data generation into the renderer host provided
[email protected]032682b2011-01-12 22:05:0255// temp file has been completed. That call is on the FILE thread.
[email protected]73852b8f2010-05-14 00:38:1256// That, in turn, hops over to the UI thread to create an instance of
57// PrintDialogCloud.
58
59// The constructor for PrintDialogCloud creates a
60// CloudPrintHtmlDialogDelegate and asks the current active browser to
61// show an HTML dialog using that class as the delegate. That class
[email protected]89f550b2011-06-08 18:34:0362// hands in the kChromeUICloudPrintResourcesURL as the URL to visit. That is
[email protected]80a8fad2011-01-29 04:02:3863// recognized by the GetWebUIFactoryFunction as a signal to create an
[email protected]73852b8f2010-05-14 00:38:1264// ExternalHtmlDialogUI.
65
66// CloudPrintHtmlDialogDelegate also temporarily owns a
67// CloudPrintFlowHandler, a class which is responsible for the actual
[email protected]a984bdf2011-03-15 20:17:1668// interactions with the dialog contents, including handing in the
[email protected]73852b8f2010-05-14 00:38:1269// print data and getting any page setup parameters that the dialog
70// contents provides. As part of bringing up the dialog,
71// HtmlDialogUI::RenderViewCreated is called (an override of
[email protected]c39f9bf2011-02-12 00:43:5572// WebUI::RenderViewCreated). That routine, in turn, calls the
[email protected]36e12172011-02-08 23:46:0273// delegate's GetWebUIMessageHandlers routine, at which point the
[email protected]73852b8f2010-05-14 00:38:1274// ownership of the CloudPrintFlowHandler is handed over. A pointer
75// to the flow handler is kept to facilitate communication back and
76// forth between the two classes.
77
[email protected]c39f9bf2011-02-12 00:43:5578// The WebUI continues dialog bring-up, calling
[email protected]73852b8f2010-05-14 00:38:1279// CloudPrintFlowHandler::RegisterMessages. This is where the
80// additional object model capabilities are registered for the dialog
81// contents to use. It is also at this time that capabilities for the
82// dialog contents are adjusted to allow the dialog contents to close
83// the window. In addition, the pending URL is redirected to the
84// actual cloud print service URL. The flow controller also registers
85// for notification of when the dialog contents finish loading, which
[email protected]a984bdf2011-03-15 20:17:1686// is currently used to send the data to the dialog contents.
[email protected]73852b8f2010-05-14 00:38:1287
[email protected]a984bdf2011-03-15 20:17:1688// In order to send the data to the dialog contents, the flow
[email protected]73852b8f2010-05-14 00:38:1289// handler uses a CloudPrintDataSender. It creates one, letting it
[email protected]a984bdf2011-03-15 20:17:1690// know the name of the temporary file containing the data, and
[email protected]73852b8f2010-05-14 00:38:1291// posts the task of reading the file
92// (CloudPrintDataSender::ReadPrintDataFile) to the file thread. That
93// routine reads in the file, and then hops over to the IO thread to
94// send that data to the dialog contents.
95
96// When the dialog contents are finished (by either being cancelled or
97// hitting the print button), the delegate is notified, and responds
98// that the dialog should be closed, at which point things are torn
99// down and released.
100
101// TODO(scottbyer):
102// http://code.google.com/p/chromium/issues/detail?id=44093 The
[email protected]a984bdf2011-03-15 20:17:16103// high-level flow (where the data is generated before even
[email protected]73852b8f2010-05-14 00:38:12104// bringing up the dialog) isn't what we want.
105
[email protected]631bb742011-11-02 11:29:39106using content::BrowserThread;
[email protected]a81343d232011-12-27 07:39:20107using content::WebContents;
[email protected]631bb742011-11-02 11:29:39108
[email protected]73852b8f2010-05-14 00:38:12109namespace internal_cloud_print_helpers {
110
[email protected]73852b8f2010-05-14 00:38:12111// From the JSON parsed value, get the entries for the page setup
112// parameters.
113bool GetPageSetupParameters(const std::string& json,
[email protected]1375e3ab2011-03-24 17:07:22114 PrintMsg_Print_Params& parameters) {
[email protected]73852b8f2010-05-14 00:38:12115 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
116 DLOG_IF(ERROR, (!parsed_value.get() ||
117 !parsed_value->IsType(Value::TYPE_DICTIONARY)))
118 << "PageSetup call didn't have expected contents";
119 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
120 return false;
121
122 bool result = true;
123 DictionaryValue* params = static_cast<DictionaryValue*>(parsed_value.get());
[email protected]05c7da62011-05-05 17:23:56124 result &= params->GetDouble("dpi", &parameters.dpi);
125 result &= params->GetDouble("min_shrink", &parameters.min_shrink);
126 result &= params->GetDouble("max_shrink", &parameters.max_shrink);
[email protected]a65175d2010-08-17 04:00:57127 result &= params->GetBoolean("selection_only", &parameters.selection_only);
[email protected]73852b8f2010-05-14 00:38:12128 return result;
129}
130
[email protected]e8368e92011-08-20 04:05:56131string16 GetSwitchValueString16(const CommandLine& command_line,
132 const char* switchName) {
133#ifdef OS_WIN
134 CommandLine::StringType native_switch_val;
135 native_switch_val = command_line.GetSwitchValueNative(switchName);
136 return string16(native_switch_val);
137#elif defined(OS_POSIX)
138 // POSIX Command line string types are different.
139 CommandLine::StringType native_switch_val;
140 native_switch_val = command_line.GetSwitchValueASCII(switchName);
141 // Convert the ASCII string to UTF16 to prepare to pass.
142 return string16(ASCIIToUTF16(native_switch_val));
143#endif
144}
145
[email protected]73852b8f2010-05-14 00:38:12146void CloudPrintDataSenderHelper::CallJavascriptFunction(
147 const std::wstring& function_name) {
[email protected]adcf8492011-03-09 22:41:39148 web_ui_->CallJavascriptFunction(WideToASCII(function_name));
[email protected]73852b8f2010-05-14 00:38:12149}
150
151void CloudPrintDataSenderHelper::CallJavascriptFunction(
152 const std::wstring& function_name, const Value& arg) {
[email protected]adcf8492011-03-09 22:41:39153 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg);
[email protected]73852b8f2010-05-14 00:38:12154}
155
156void CloudPrintDataSenderHelper::CallJavascriptFunction(
157 const std::wstring& function_name, const Value& arg1, const Value& arg2) {
[email protected]adcf8492011-03-09 22:41:39158 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2);
[email protected]73852b8f2010-05-14 00:38:12159}
160
[email protected]e8368e92011-08-20 04:05:56161void CloudPrintDataSenderHelper::CallJavascriptFunction(
162 const std::wstring& function_name,
163 const Value& arg1,
164 const Value& arg2,
165 const Value& arg3) {
166 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2, arg3);
167}
168
[email protected]73852b8f2010-05-14 00:38:12169// Clears out the pointer we're using to communicate. Either routine is
170// potentially expensive enough that stopping whatever is in progress
171// is worth it.
172void CloudPrintDataSender::CancelPrintDataFile() {
[email protected]20305ec2011-01-21 04:55:52173 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12174 // We don't own helper, it was passed in to us, so no need to
175 // delete, just let it go.
176 helper_ = NULL;
177}
178
[email protected]38e08982010-10-22 17:28:43179CloudPrintDataSender::CloudPrintDataSender(CloudPrintDataSenderHelper* helper,
[email protected]a984bdf2011-03-15 20:17:16180 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56181 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16182 const std::string& file_type)
[email protected]38e08982010-10-22 17:28:43183 : helper_(helper),
[email protected]a984bdf2011-03-15 20:17:16184 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56185 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16186 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43187}
188
189CloudPrintDataSender::~CloudPrintDataSender() {}
190
[email protected]a984bdf2011-03-15 20:17:16191// Grab the raw file contents and massage them into shape for
[email protected]73852b8f2010-05-14 00:38:12192// sending to the dialog contents (and up to the cloud print server)
193// by encoding it and prefixing it with the appropriate mime type.
194// Once that is done, kick off the next part of the task on the IO
195// thread.
[email protected]a984bdf2011-03-15 20:17:16196void CloudPrintDataSender::ReadPrintDataFile(const FilePath& path_to_file) {
[email protected]ba4f1132010-10-09 02:02:35197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]73852b8f2010-05-14 00:38:12198 int64 file_size = 0;
[email protected]a984bdf2011-03-15 20:17:16199 if (file_util::GetFileSize(path_to_file, &file_size) && file_size != 0) {
[email protected]73852b8f2010-05-14 00:38:12200 std::string file_data;
201 if (file_size < kuint32max) {
202 file_data.reserve(static_cast<unsigned int>(file_size));
203 } else {
204 DLOG(WARNING) << " print data file too large to reserve space";
205 }
[email protected]a984bdf2011-03-15 20:17:16206 if (helper_ && file_util::ReadFileToString(path_to_file, &file_data)) {
[email protected]73852b8f2010-05-14 00:38:12207 std::string base64_data;
208 base::Base64Encode(file_data, &base64_data);
[email protected]a984bdf2011-03-15 20:17:16209 std::string header("data:");
210 header.append(file_type_);
211 header.append(";base64,");
[email protected]73852b8f2010-05-14 00:38:12212 base64_data.insert(0, header);
213 scoped_ptr<StringValue> new_data(new StringValue(base64_data));
214 print_data_.swap(new_data);
[email protected]3e2dd4fa2011-11-10 06:06:40215 BrowserThread::PostTask(
216 BrowserThread::IO, FROM_HERE,
217 base::Bind(&CloudPrintDataSender::SendPrintDataFile, this));
[email protected]73852b8f2010-05-14 00:38:12218 }
219 }
220}
221
222// We have the data in hand that needs to be pushed into the dialog
223// contents; do so from the IO thread.
224
225// TODO(scottbyer): If the print data ends up being larger than the
226// upload limit (currently 10MB), what we need to do is upload that
227// large data to google docs and set the URL in the printing
228// JavaScript to that location, and make sure it gets deleted when not
229// needed. - 4/1/2010
230void CloudPrintDataSender::SendPrintDataFile() {
[email protected]ba4f1132010-10-09 02:02:35231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20305ec2011-01-21 04:55:52232 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12233 if (helper_ && print_data_.get()) {
[email protected]9848c7e2010-06-03 16:06:56234 StringValue title(print_job_title_);
[email protected]e8368e92011-08-20 04:05:56235 StringValue ticket(print_ticket_);
236 // TODO(abodenha): Change Javascript call to pass in print ticket
237 // after server side support is added. Add test for it.
[email protected]73852b8f2010-05-14 00:38:12238
239 // Send the print data to the dialog contents. The JavaScript
240 // function is a preliminary API for prototyping purposes and is
241 // subject to change.
242 const_cast<CloudPrintDataSenderHelper*>(helper_)->CallJavascriptFunction(
243 L"printApp._printDataUrl", *print_data_, title);
244 }
245}
246
247
[email protected]a984bdf2011-03-15 20:17:16248CloudPrintFlowHandler::CloudPrintFlowHandler(const FilePath& path_to_file,
249 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56250 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16251 const std::string& file_type)
[email protected]c7bf7452011-09-12 21:31:50252 : dialog_delegate_(NULL),
253 path_to_file_(path_to_file),
[email protected]a984bdf2011-03-15 20:17:16254 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56255 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16256 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43257}
258
259CloudPrintFlowHandler::~CloudPrintFlowHandler() {
260 // This will also cancel any task in flight.
261 CancelAnyRunningTask();
262}
263
264
[email protected]73852b8f2010-05-14 00:38:12265void CloudPrintFlowHandler::SetDialogDelegate(
266 CloudPrintHtmlDialogDelegate* delegate) {
[email protected]7b748982011-02-14 19:28:23267 // Even if setting a new WebUI, it means any previous task needs
[email protected]73852b8f2010-05-14 00:38:12268 // to be cancelled, it's now invalid.
[email protected]ba4f1132010-10-09 02:02:35269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12270 CancelAnyRunningTask();
271 dialog_delegate_ = delegate;
272}
273
274// Cancels any print data sender we have in flight and removes our
275// reference to it, so when the task that is calling it finishes and
276// removes it's reference, it goes away.
277void CloudPrintFlowHandler::CancelAnyRunningTask() {
[email protected]ba4f1132010-10-09 02:02:35278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12279 if (print_data_sender_.get()) {
280 print_data_sender_->CancelPrintDataFile();
281 print_data_sender_ = NULL;
282 }
283}
284
[email protected]73852b8f2010-05-14 00:38:12285void CloudPrintFlowHandler::RegisterMessages() {
[email protected]7b748982011-02-14 19:28:23286 if (!web_ui_)
[email protected]73852b8f2010-05-14 00:38:12287 return;
288
289 // TODO(scottbyer) - This is where we will register messages for the
290 // UI JS to use. Needed: Call to update page setup parameters.
[email protected]ba4fc242011-10-04 18:56:56291 web_ui_->RegisterMessageCallback("ShowDebugger",
292 base::Bind(&CloudPrintFlowHandler::HandleShowDebugger,
293 base::Unretained(this)));
294 web_ui_->RegisterMessageCallback("SendPrintData",
295 base::Bind(&CloudPrintFlowHandler::HandleSendPrintData,
296 base::Unretained(this)));
297 web_ui_->RegisterMessageCallback("SetPageParameters",
298 base::Bind(&CloudPrintFlowHandler::HandleSetPageParameters,
299 base::Unretained(this)));
[email protected]73852b8f2010-05-14 00:38:12300
[email protected]0eb25c42011-08-11 14:50:14301 // Register for appropriate notifications, and re-direct the URL
302 // to the real server URL, now that we've gotten an HTML dialog
303 // going.
[email protected]f5fa20e2011-12-21 22:35:56304 NavigationController* controller = &web_ui_->tab_contents()->GetController();
[email protected]022af742011-12-28 18:37:25305 content::NavigationEntry* pending_entry = controller->GetPendingEntry();
[email protected]0eb25c42011-08-11 14:50:14306 if (pending_entry) {
307 Profile* profile = Profile::FromWebUI(web_ui_);
[email protected]ad23a092011-12-28 07:02:04308 pending_entry->SetURL(
[email protected]0eb25c42011-08-11 14:50:14309 CloudPrintURL(profile).GetCloudPrintServiceDialogURL());
[email protected]73852b8f2010-05-14 00:38:12310 }
[email protected]0eb25c42011-08-11 14:50:14311 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
[email protected]6c2381d2011-10-19 02:52:53312 content::Source<NavigationController>(controller));
[email protected]73852b8f2010-05-14 00:38:12313}
314
[email protected]6c2381d2011-10-19 02:52:53315void CloudPrintFlowHandler::Observe(
316 int type,
317 const content::NotificationSource& source,
318 const content::NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:27319 if (type == content::NOTIFICATION_LOAD_STOP) {
[email protected]20c52d22011-06-20 22:42:42320 // Take the opportunity to set some (minimal) additional
321 // script permissions required for the web UI.
322 GURL url = web_ui_->tab_contents()->GetURL();
323 GURL dialog_url = CloudPrintURL(
[email protected]0eb25c42011-08-11 14:50:14324 Profile::FromWebUI(web_ui_)).GetCloudPrintServiceDialogURL();
[email protected]20c52d22011-06-20 22:42:42325 if (url.host() == dialog_url.host() &&
326 url.path() == dialog_url.path() &&
327 url.scheme() == dialog_url.scheme()) {
[email protected]151a63d2011-12-20 22:32:52328 RenderViewHost* rvh = web_ui_->tab_contents()->GetRenderViewHost();
[email protected]20c52d22011-06-20 22:42:42329 if (rvh && rvh->delegate()) {
330 WebPreferences webkit_prefs = rvh->delegate()->GetWebkitPrefs();
331 webkit_prefs.allow_scripts_to_close_windows = true;
[email protected]9abd51f2011-09-21 19:11:35332 rvh->UpdateWebkitPreferences(webkit_prefs);
[email protected]20c52d22011-06-20 22:42:42333 } else {
334 DCHECK(false);
335 }
336 }
337
[email protected]73852b8f2010-05-14 00:38:12338 // Choose one or the other. If you need to debug, bring up the
339 // debugger. You can then use the various chrome.send()
340 // registrations above to kick of the various function calls,
341 // including chrome.send("SendPrintData") in the javaScript
342 // console and watch things happen with:
343 // HandleShowDebugger(NULL);
344 HandleSendPrintData(NULL);
345 }
346}
347
[email protected]88942a22010-08-19 20:34:43348void CloudPrintFlowHandler::HandleShowDebugger(const ListValue* args) {
[email protected]73852b8f2010-05-14 00:38:12349 ShowDebugger();
350}
351
352void CloudPrintFlowHandler::ShowDebugger() {
[email protected]7b748982011-02-14 19:28:23353 if (web_ui_) {
[email protected]151a63d2011-12-20 22:32:52354 RenderViewHost* rvh = web_ui_->tab_contents()->GetRenderViewHost();
[email protected]73852b8f2010-05-14 00:38:12355 if (rvh)
[email protected]aebdd072011-07-07 12:36:59356 DevToolsWindow::OpenDevToolsWindow(rvh);
[email protected]73852b8f2010-05-14 00:38:12357 }
358}
359
360scoped_refptr<CloudPrintDataSender>
361CloudPrintFlowHandler::CreateCloudPrintDataSender() {
[email protected]7b748982011-02-14 19:28:23362 DCHECK(web_ui_);
363 print_data_helper_.reset(new CloudPrintDataSenderHelper(web_ui_));
[email protected]a984bdf2011-03-15 20:17:16364 return new CloudPrintDataSender(print_data_helper_.get(),
365 print_job_title_,
[email protected]e8368e92011-08-20 04:05:56366 print_ticket_,
[email protected]a984bdf2011-03-15 20:17:16367 file_type_);
[email protected]73852b8f2010-05-14 00:38:12368}
369
[email protected]88942a22010-08-19 20:34:43370void CloudPrintFlowHandler::HandleSendPrintData(const ListValue* args) {
[email protected]ba4f1132010-10-09 02:02:35371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12372 // This will cancel any ReadPrintDataFile() or SendPrintDataFile()
373 // requests in flight (this is anticipation of when setting page
374 // setup parameters becomes asynchronous and may be set while some
375 // data is in flight). Then we can clear out the print data.
376 CancelAnyRunningTask();
[email protected]7b748982011-02-14 19:28:23377 if (web_ui_) {
[email protected]73852b8f2010-05-14 00:38:12378 print_data_sender_ = CreateCloudPrintDataSender();
[email protected]3e2dd4fa2011-11-10 06:06:40379 BrowserThread::PostTask(
380 BrowserThread::FILE, FROM_HERE,
381 base::Bind(&CloudPrintDataSender::ReadPrintDataFile,
382 print_data_sender_.get(), path_to_file_));
[email protected]73852b8f2010-05-14 00:38:12383 }
384}
385
[email protected]88942a22010-08-19 20:34:43386void CloudPrintFlowHandler::HandleSetPageParameters(const ListValue* args) {
[email protected]036056a32011-03-03 21:05:01387 std::string json;
[email protected]e675f7b2011-06-22 17:32:12388 bool ret = args->GetString(0, &json);
389 if (!ret || json.empty()) {
[email protected]036056a32011-03-03 21:05:01390 NOTREACHED() << "Empty json string";
[email protected]73852b8f2010-05-14 00:38:12391 return;
[email protected]036056a32011-03-03 21:05:01392 }
[email protected]73852b8f2010-05-14 00:38:12393
394 // These are backstop default values - 72 dpi to match the screen,
395 // 8.5x11 inch paper with margins subtracted (1/4 inch top, left,
396 // right and 0.56 bottom), and the min page shrink and max page
397 // shrink values appear all over the place with no explanation.
398
399 // TODO(scottbyer): Get a Linux/ChromeOS edge for PrintSettings
400 // working so that we can get the default values from there. Fix up
401 // PrintWebViewHelper to do the same.
402 const int kDPI = 72;
403 const int kWidth = static_cast<int>((8.5-0.25-0.25)*kDPI);
404 const int kHeight = static_cast<int>((11-0.25-0.56)*kDPI);
405 const double kMinPageShrink = 1.25;
406 const double kMaxPageShrink = 2.0;
407
[email protected]1375e3ab2011-03-24 17:07:22408 PrintMsg_Print_Params default_settings;
[email protected]10980442011-12-04 22:33:05409 default_settings.content_size = gfx::Size(kWidth, kHeight);
[email protected]73852b8f2010-05-14 00:38:12410 default_settings.dpi = kDPI;
411 default_settings.min_shrink = kMinPageShrink;
412 default_settings.max_shrink = kMaxPageShrink;
413 default_settings.desired_dpi = kDPI;
414 default_settings.document_cookie = 0;
415 default_settings.selection_only = false;
[email protected]718af822011-08-12 22:11:33416 default_settings.preview_request_id = 0;
417 default_settings.is_first_request = true;
[email protected]73852b8f2010-05-14 00:38:12418
419 if (!GetPageSetupParameters(json, default_settings)) {
420 NOTREACHED();
421 return;
422 }
423
424 // TODO(scottbyer) - Here is where we would kick the originating
425 // renderer thread with these new parameters in order to get it to
[email protected]a984bdf2011-03-15 20:17:16426 // re-generate the PDF data and hand it back to us. window.print() is
[email protected]73852b8f2010-05-14 00:38:12427 // currently synchronous, so there's a lot of work to do to get to
428 // that point.
429}
430
[email protected]ea161da2010-11-02 21:57:35431void CloudPrintFlowHandler::StoreDialogClientSize() const {
[email protected]d487beefe2011-12-21 05:41:21432 if (web_ui_ && web_ui_->tab_contents() &&
433 web_ui_->tab_contents()->GetView()) {
434 gfx::Size size = web_ui_->tab_contents()->GetView()->GetContainerSize();
[email protected]0eb25c42011-08-11 14:50:14435 Profile* profile = Profile::FromWebUI(web_ui_);
436 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogWidth,
437 size.width());
438 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogHeight,
439 size.height());
[email protected]ea161da2010-11-02 21:57:35440 }
441}
442
[email protected]73852b8f2010-05-14 00:38:12443CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
[email protected]a984bdf2011-03-15 20:17:16444 const FilePath& path_to_file,
[email protected]73852b8f2010-05-14 00:38:12445 int width, int height,
[email protected]9848c7e2010-06-03 16:06:56446 const std::string& json_arguments,
[email protected]e39027a2011-01-24 21:41:54447 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56448 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16449 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03450 bool modal,
451 bool delete_on_close)
452 : delete_on_close_(delete_on_close),
453 flow_handler_(new CloudPrintFlowHandler(path_to_file,
[email protected]a984bdf2011-03-15 20:17:16454 print_job_title,
[email protected]e8368e92011-08-20 04:05:56455 print_ticket,
[email protected]a984bdf2011-03-15 20:17:16456 file_type)),
[email protected]e39027a2011-01-24 21:41:54457 modal_(modal),
[email protected]6ddda232011-04-22 15:41:47458 owns_flow_handler_(true),
459 path_to_file_(path_to_file) {
[email protected]73852b8f2010-05-14 00:38:12460 Init(width, height, json_arguments);
461}
462
[email protected]05acb55472011-02-03 00:11:07463// For unit testing.
[email protected]73852b8f2010-05-14 00:38:12464CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
465 CloudPrintFlowHandler* flow_handler,
466 int width, int height,
[email protected]e39027a2011-01-24 21:41:54467 const std::string& json_arguments,
[email protected]d955fc92011-09-19 20:49:03468 bool modal,
469 bool delete_on_close)
470 : delete_on_close_(delete_on_close),
471 flow_handler_(flow_handler),
[email protected]e39027a2011-01-24 21:41:54472 modal_(modal),
[email protected]18137e02010-05-25 21:10:35473 owns_flow_handler_(true) {
[email protected]73852b8f2010-05-14 00:38:12474 Init(width, height, json_arguments);
475}
476
[email protected]05acb55472011-02-03 00:11:07477void CloudPrintHtmlDialogDelegate::Init(int width, int height,
478 const std::string& json_arguments) {
[email protected]73852b8f2010-05-14 00:38:12479 // This information is needed to show the dialog HTML content.
[email protected]ba4f1132010-10-09 02:02:35480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]89f550b2011-06-08 18:34:03481 params_.url = GURL(chrome::kChromeUICloudPrintResourcesURL);
[email protected]73852b8f2010-05-14 00:38:12482 params_.height = height;
483 params_.width = width;
484 params_.json_input = json_arguments;
485
486 flow_handler_->SetDialogDelegate(this);
[email protected]e39027a2011-01-24 21:41:54487 // If we're not modal we can show the dialog with no browser.
488 // We need this to keep Chrome alive while our dialog is up.
489 if (!modal_)
490 BrowserList::StartKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12491}
492
493CloudPrintHtmlDialogDelegate::~CloudPrintHtmlDialogDelegate() {
494 // If the flow_handler_ is about to outlive us because we don't own
495 // it anymore, we need to have it remove it's reference to us.
[email protected]ba4f1132010-10-09 02:02:35496 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12497 flow_handler_->SetDialogDelegate(NULL);
498 if (owns_flow_handler_) {
499 delete flow_handler_;
500 }
501}
502
503bool CloudPrintHtmlDialogDelegate::IsDialogModal() const {
[email protected]e39027a2011-01-24 21:41:54504 return modal_;
[email protected]73852b8f2010-05-14 00:38:12505}
506
[email protected]bdae5c12011-08-05 21:49:06507string16 CloudPrintHtmlDialogDelegate::GetDialogTitle() const {
508 return string16();
[email protected]73852b8f2010-05-14 00:38:12509}
510
511GURL CloudPrintHtmlDialogDelegate::GetDialogContentURL() const {
512 return params_.url;
513}
514
[email protected]36e12172011-02-08 23:46:02515void CloudPrintHtmlDialogDelegate::GetWebUIMessageHandlers(
516 std::vector<WebUIMessageHandler*>* handlers) const {
[email protected]73852b8f2010-05-14 00:38:12517 handlers->push_back(flow_handler_);
518 // We don't own flow_handler_ anymore, but it sticks around until at
519 // least right after OnDialogClosed() is called (and this object is
520 // destroyed).
521 owns_flow_handler_ = false;
522}
523
524void CloudPrintHtmlDialogDelegate::GetDialogSize(gfx::Size* size) const {
525 size->set_width(params_.width);
526 size->set_height(params_.height);
527}
528
529std::string CloudPrintHtmlDialogDelegate::GetDialogArgs() const {
530 return params_.json_input;
531}
532
533void CloudPrintHtmlDialogDelegate::OnDialogClosed(
534 const std::string& json_retval) {
[email protected]ea161da2010-11-02 21:57:35535 // Get the final dialog size and store it.
536 flow_handler_->StoreDialogClientSize();
[email protected]6ddda232011-04-22 15:41:47537
[email protected]d955fc92011-09-19 20:49:03538 if (delete_on_close_) {
[email protected]3e2dd4fa2011-11-10 06:06:40539 BrowserThread::PostTask(
540 BrowserThread::FILE, FROM_HERE,
541 base::Bind(&internal_cloud_print_helpers::Delete, path_to_file_));
[email protected]6ddda232011-04-22 15:41:47542 }
543
[email protected]e39027a2011-01-24 21:41:54544 // If we're modal we can show the dialog with no browser.
545 // End the keep-alive so that Chrome can exit.
546 if (!modal_)
547 BrowserList::EndKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12548 delete this;
549}
550
[email protected]a81343d232011-12-27 07:39:20551void CloudPrintHtmlDialogDelegate::OnCloseContents(WebContents* source,
[email protected]18137e02010-05-25 21:10:35552 bool* out_close_dialog) {
553 if (out_close_dialog)
554 *out_close_dialog = true;
555}
556
[email protected]ea161da2010-11-02 21:57:35557bool CloudPrintHtmlDialogDelegate::ShouldShowDialogTitle() const {
558 return false;
559}
560
[email protected]34478212011-04-19 01:35:46561bool CloudPrintHtmlDialogDelegate::HandleContextMenu(
562 const ContextMenuParams& params) {
563 return true;
564}
565
[email protected]d955fc92011-09-19 20:49:03566void CreatePrintDialogForBytesImpl(scoped_refptr<RefCountedBytes> data,
567 const string16& print_job_title,
568 const string16& print_ticket,
569 const std::string& file_type,
570 bool modal) {
571 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
572 // TODO([email protected]) Writing the PDF to a file before printing
573 // is wasteful. Modify the dialog flow to pull PDF data from memory.
574 // See http://code.google.com/p/chromium/issues/detail?id=44093
575 FilePath path;
576 if (file_util::CreateTemporaryFile(&path)) {
577 file_util::WriteFile(path,
578 reinterpret_cast<const char*>(data->front()),
579 data->size());
580 }
581 print_dialog_cloud::CreatePrintDialogForFile(path,
582 print_job_title,
583 print_ticket,
584 file_type,
585 modal,
586 true);
587}
588
[email protected]6085c70d2011-03-22 22:51:07589// Called from the UI thread, starts up the dialog.
590void CreateDialogImpl(const FilePath& path_to_file,
591 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56592 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07593 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03594 bool modal,
595 bool delete_on_close) {
[email protected]ba4f1132010-10-09 02:02:35596 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6085c70d2011-03-22 22:51:07597 Browser* browser = BrowserList::GetLastActive();
[email protected]73852b8f2010-05-14 00:38:12598
[email protected]ea161da2010-11-02 21:57:35599 const int kDefaultWidth = 497;
600 const int kDefaultHeight = 332;
[email protected]05acb55472011-02-03 00:11:07601 string16 job_title = print_job_title;
[email protected]e39027a2011-01-24 21:41:54602 Profile* profile = NULL;
[email protected]05acb55472011-02-03 00:11:07603 if (modal) {
[email protected]6085c70d2011-03-22 22:51:07604 DCHECK(browser);
605 if (job_title.empty() && browser->GetSelectedTabContents())
606 job_title = browser->GetSelectedTabContents()->GetTitle();
607 profile = browser->GetProfile();
[email protected]e39027a2011-01-24 21:41:54608 } else {
[email protected]0744cc72011-08-12 12:05:45609 std::vector<Profile*> loaded_profiles =
610 g_browser_process->profile_manager()->GetLoadedProfiles();
611 DCHECK_GT(loaded_profiles.size(), 0U);
612 profile = loaded_profiles[0];
[email protected]e39027a2011-01-24 21:41:54613 }
614 DCHECK(profile);
[email protected]05acb55472011-02-03 00:11:07615 PrefService* pref_service = profile->GetPrefs();
[email protected]ea161da2010-11-02 21:57:35616 DCHECK(pref_service);
617 if (!pref_service->FindPreference(prefs::kCloudPrintDialogWidth)) {
618 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogWidth,
[email protected]d36f941b2011-05-09 06:19:16619 kDefaultWidth,
620 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35621 }
622 if (!pref_service->FindPreference(prefs::kCloudPrintDialogHeight)) {
623 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogHeight,
[email protected]d36f941b2011-05-09 06:19:16624 kDefaultHeight,
625 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35626 }
627
628 int width = pref_service->GetInteger(prefs::kCloudPrintDialogWidth);
629 int height = pref_service->GetInteger(prefs::kCloudPrintDialogHeight);
[email protected]e39027a2011-01-24 21:41:54630
[email protected]73852b8f2010-05-14 00:38:12631 HtmlDialogUIDelegate* dialog_delegate =
632 new internal_cloud_print_helpers::CloudPrintHtmlDialogDelegate(
[email protected]e8368e92011-08-20 04:05:56633 path_to_file, width, height, std::string(), job_title, print_ticket,
[email protected]d955fc92011-09-19 20:49:03634 file_type, modal, delete_on_close);
[email protected]05acb55472011-02-03 00:11:07635 if (modal) {
[email protected]6085c70d2011-03-22 22:51:07636 DCHECK(browser);
[email protected]22c830d2011-11-29 20:00:37637 browser->BrowserShowHtmlDialog(dialog_delegate, NULL, STYLE_GENERIC);
[email protected]e39027a2011-01-24 21:41:54638 } else {
[email protected]22c830d2011-11-29 20:00:37639 browser::ShowHtmlDialog(NULL, profile, dialog_delegate, STYLE_GENERIC);
[email protected]e39027a2011-01-24 21:41:54640 }
[email protected]73852b8f2010-05-14 00:38:12641}
[email protected]6085c70d2011-03-22 22:51:07642
[email protected]6ddda232011-04-22 15:41:47643// Provides a runnable function to delete a file.
644void Delete(const FilePath& file_path) {
645 file_util::Delete(file_path, false);
646}
647
[email protected]6085c70d2011-03-22 22:51:07648} // namespace internal_cloud_print_helpers
649
650namespace print_dialog_cloud {
651
652// Called on the FILE or UI thread. This is the main entry point into creating
653// the dialog.
654
655// TODO(scottbyer): The signature here will need to change as the
656// workflow through the printing code changes to allow for dynamically
657// changing page setup parameters while the dialog is active.
658void CreatePrintDialogForFile(const FilePath& path_to_file,
659 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56660 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07661 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03662 bool modal,
663 bool delete_on_close) {
[email protected]6085c70d2011-03-22 22:51:07664 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE) ||
665 BrowserThread::CurrentlyOn(BrowserThread::UI));
666
667 BrowserThread::PostTask(
668 BrowserThread::UI, FROM_HERE,
[email protected]3e2dd4fa2011-11-10 06:06:40669 base::Bind(&internal_cloud_print_helpers::CreateDialogImpl, path_to_file,
670 print_job_title, print_ticket, file_type, modal,
671 delete_on_close));
[email protected]d955fc92011-09-19 20:49:03672}
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,
[email protected]3e2dd4fa2011-11-10 06:06:40685 base::Bind(&internal_cloud_print_helpers::CreatePrintDialogForBytesImpl,
686 cloned_data, print_job_title, print_ticket, file_type, modal));
[email protected]6085c70d2011-03-22 22:51:07687}
688
[email protected]65c9d89a2011-04-13 21:02:39689bool CreatePrintDialogFromCommandLine(const CommandLine& command_line) {
690 if (!command_line.GetSwitchValuePath(switches::kCloudPrintFile).empty()) {
691 FilePath cloud_print_file;
692 cloud_print_file =
693 command_line.GetSwitchValuePath(switches::kCloudPrintFile);
694 if (!cloud_print_file.empty()) {
695 string16 print_job_title;
[email protected]e8368e92011-08-20 04:05:56696 string16 print_job_print_ticket;
[email protected]65c9d89a2011-04-13 21:02:39697 if (command_line.HasSwitch(switches::kCloudPrintJobTitle)) {
[email protected]e8368e92011-08-20 04:05:56698 print_job_title =
699 internal_cloud_print_helpers::GetSwitchValueString16(
700 command_line, switches::kCloudPrintJobTitle);
701 }
702 if (command_line.HasSwitch(switches::kCloudPrintPrintTicket)) {
703 print_job_print_ticket =
704 internal_cloud_print_helpers::GetSwitchValueString16(
705 command_line, switches::kCloudPrintPrintTicket);
[email protected]65c9d89a2011-04-13 21:02:39706 }
707 std::string file_type = "application/pdf";
708 if (command_line.HasSwitch(switches::kCloudPrintFileType)) {
709 file_type = command_line.GetSwitchValueASCII(
710 switches::kCloudPrintFileType);
711 }
[email protected]e8368e92011-08-20 04:05:56712
[email protected]d955fc92011-09-19 20:49:03713 bool delete_on_close = CommandLine::ForCurrentProcess()->HasSwitch(
714 switches::kCloudPrintDeleteFile);
715
[email protected]65c9d89a2011-04-13 21:02:39716 print_dialog_cloud::CreatePrintDialogForFile(cloud_print_file,
717 print_job_title,
[email protected]e8368e92011-08-20 04:05:56718 print_job_print_ticket,
[email protected]65c9d89a2011-04-13 21:02:39719 file_type,
[email protected]d955fc92011-09-19 20:49:03720 false,
721 delete_on_close);
[email protected]65c9d89a2011-04-13 21:02:39722 return true;
723 }
724 }
725 return false;
726}
727
[email protected]6085c70d2011-03-22 22:51:07728} // end namespace