blob: 618ba8d10caf957d4d8cfc0c2477cb43fffb481e [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]65c9d89a2011-04-13 21:02:399#include "base/command_line.h"
[email protected]73852b8f2010-05-14 00:38:1210#include "base/file_util.h"
11#include "base/json/json_reader.h"
[email protected]4b8852a2011-06-10 17:24:4612#include "base/utf_string_conversions.h"
[email protected]73852b8f2010-05-14 00:38:1213#include "base/values.h"
[email protected]0744cc72011-08-12 12:05:4514#include "chrome/browser/browser_process_impl.h"
[email protected]dce502762011-07-20 08:53:4915#include "chrome/browser/debugger/devtools_window.h"
[email protected]ea161da2010-11-02 21:57:3516#include "chrome/browser/prefs/pref_service.h"
[email protected]2283eead2010-09-29 23:17:3017#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
[email protected]8ecad5e2010-12-02 21:18:3318#include "chrome/browser/profiles/profile.h"
[email protected]e39027a2011-01-24 21:41:5419#include "chrome/browser/profiles/profile_manager.h"
[email protected]eb2d7902011-02-02 18:19:5620#include "chrome/browser/ui/browser_dialogs.h"
[email protected]6768ac02011-04-06 17:41:0421#include "chrome/browser/ui/browser_list.h"
[email protected]65c9d89a2011-04-13 21:02:3922#include "chrome/common/chrome_switches.h"
[email protected]ea161da2010-11-02 21:57:3523#include "chrome/common/pref_names.h"
[email protected]1375e3ab2011-03-24 17:07:2224#include "chrome/common/print_messages.h"
[email protected]73852b8f2010-05-14 00:38:1225#include "chrome/common/url_constants.h"
[email protected]5f945a0e2011-03-01 17:47:5326#include "content/browser/browser_thread.h"
27#include "content/browser/renderer_host/render_view_host.h"
28#include "content/browser/tab_contents/tab_contents.h"
29#include "content/browser/tab_contents/tab_contents_view.h"
[email protected]67fc0392011-02-25 02:56:5730#include "content/browser/webui/web_ui.h"
[email protected]432115822011-07-10 15:52:2731#include "content/common/content_notification_types.h"
[email protected]ebbbb9f2011-03-09 13:16:1432#include "content/common/notification_registrar.h"
33#include "content/common/notification_source.h"
[email protected]216813952011-05-19 22:21:2634#include "content/common/view_messages.h"
[email protected]c051a1b2011-01-21 23:30:1735#include "ui/base/l10n/l10n_util.h"
[email protected]939856a2010-08-24 20:29:0236#include "webkit/glue/webpreferences.h"
[email protected]73852b8f2010-05-14 00:38:1237
38#include "grit/generated_resources.h"
39
40// This module implements the UI support in Chrome for cloud printing.
41// This means hosting a dialog containing HTML/JavaScript and using
42// the published cloud print user interface integration APIs to get
43// page setup settings from the dialog contents and provide the
[email protected]a984bdf2011-03-15 20:17:1644// generated print data to the dialog contents for uploading to the
[email protected]73852b8f2010-05-14 00:38:1245// cloud print service.
46
47// Currently, the flow between these classes is as follows:
48
[email protected]a984bdf2011-03-15 20:17:1649// PrintDialogCloud::CreatePrintDialogForFile is called from
[email protected]73852b8f2010-05-14 00:38:1250// resource_message_filter_gtk.cc once the renderer has informed the
[email protected]a984bdf2011-03-15 20:17:1651// renderer host that print data generation into the renderer host provided
[email protected]032682b2011-01-12 22:05:0252// temp file has been completed. That call is on the FILE thread.
[email protected]73852b8f2010-05-14 00:38:1253// That, in turn, hops over to the UI thread to create an instance of
54// PrintDialogCloud.
55
56// The constructor for PrintDialogCloud creates a
57// CloudPrintHtmlDialogDelegate and asks the current active browser to
58// show an HTML dialog using that class as the delegate. That class
[email protected]89f550b2011-06-08 18:34:0359// hands in the kChromeUICloudPrintResourcesURL as the URL to visit. That is
[email protected]80a8fad2011-01-29 04:02:3860// recognized by the GetWebUIFactoryFunction as a signal to create an
[email protected]73852b8f2010-05-14 00:38:1261// ExternalHtmlDialogUI.
62
63// CloudPrintHtmlDialogDelegate also temporarily owns a
64// CloudPrintFlowHandler, a class which is responsible for the actual
[email protected]a984bdf2011-03-15 20:17:1665// interactions with the dialog contents, including handing in the
[email protected]73852b8f2010-05-14 00:38:1266// print data and getting any page setup parameters that the dialog
67// contents provides. As part of bringing up the dialog,
68// HtmlDialogUI::RenderViewCreated is called (an override of
[email protected]c39f9bf2011-02-12 00:43:5569// WebUI::RenderViewCreated). That routine, in turn, calls the
[email protected]36e12172011-02-08 23:46:0270// delegate's GetWebUIMessageHandlers routine, at which point the
[email protected]73852b8f2010-05-14 00:38:1271// ownership of the CloudPrintFlowHandler is handed over. A pointer
72// to the flow handler is kept to facilitate communication back and
73// forth between the two classes.
74
[email protected]c39f9bf2011-02-12 00:43:5575// The WebUI continues dialog bring-up, calling
[email protected]73852b8f2010-05-14 00:38:1276// CloudPrintFlowHandler::RegisterMessages. This is where the
77// additional object model capabilities are registered for the dialog
78// contents to use. It is also at this time that capabilities for the
79// dialog contents are adjusted to allow the dialog contents to close
80// the window. In addition, the pending URL is redirected to the
81// actual cloud print service URL. The flow controller also registers
82// for notification of when the dialog contents finish loading, which
[email protected]a984bdf2011-03-15 20:17:1683// is currently used to send the data to the dialog contents.
[email protected]73852b8f2010-05-14 00:38:1284
[email protected]a984bdf2011-03-15 20:17:1685// In order to send the data to the dialog contents, the flow
[email protected]73852b8f2010-05-14 00:38:1286// handler uses a CloudPrintDataSender. It creates one, letting it
[email protected]a984bdf2011-03-15 20:17:1687// know the name of the temporary file containing the data, and
[email protected]73852b8f2010-05-14 00:38:1288// posts the task of reading the file
89// (CloudPrintDataSender::ReadPrintDataFile) to the file thread. That
90// routine reads in the file, and then hops over to the IO thread to
91// send that data to the dialog contents.
92
93// When the dialog contents are finished (by either being cancelled or
94// hitting the print button), the delegate is notified, and responds
95// that the dialog should be closed, at which point things are torn
96// down and released.
97
98// TODO(scottbyer):
99// http://code.google.com/p/chromium/issues/detail?id=44093 The
[email protected]a984bdf2011-03-15 20:17:16100// high-level flow (where the data is generated before even
[email protected]73852b8f2010-05-14 00:38:12101// bringing up the dialog) isn't what we want.
102
[email protected]73852b8f2010-05-14 00:38:12103namespace internal_cloud_print_helpers {
104
[email protected]73852b8f2010-05-14 00:38:12105// From the JSON parsed value, get the entries for the page setup
106// parameters.
107bool GetPageSetupParameters(const std::string& json,
[email protected]1375e3ab2011-03-24 17:07:22108 PrintMsg_Print_Params& parameters) {
[email protected]73852b8f2010-05-14 00:38:12109 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
110 DLOG_IF(ERROR, (!parsed_value.get() ||
111 !parsed_value->IsType(Value::TYPE_DICTIONARY)))
112 << "PageSetup call didn't have expected contents";
113 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
114 return false;
115
116 bool result = true;
117 DictionaryValue* params = static_cast<DictionaryValue*>(parsed_value.get());
[email protected]05c7da62011-05-05 17:23:56118 result &= params->GetDouble("dpi", &parameters.dpi);
119 result &= params->GetDouble("min_shrink", &parameters.min_shrink);
120 result &= params->GetDouble("max_shrink", &parameters.max_shrink);
[email protected]a65175d2010-08-17 04:00:57121 result &= params->GetBoolean("selection_only", &parameters.selection_only);
[email protected]73852b8f2010-05-14 00:38:12122 return result;
123}
124
[email protected]e8368e92011-08-20 04:05:56125string16 GetSwitchValueString16(const CommandLine& command_line,
126 const char* switchName) {
127#ifdef OS_WIN
128 CommandLine::StringType native_switch_val;
129 native_switch_val = command_line.GetSwitchValueNative(switchName);
130 return string16(native_switch_val);
131#elif defined(OS_POSIX)
132 // POSIX Command line string types are different.
133 CommandLine::StringType native_switch_val;
134 native_switch_val = command_line.GetSwitchValueASCII(switchName);
135 // Convert the ASCII string to UTF16 to prepare to pass.
136 return string16(ASCIIToUTF16(native_switch_val));
137#endif
138}
139
[email protected]73852b8f2010-05-14 00:38:12140void CloudPrintDataSenderHelper::CallJavascriptFunction(
141 const std::wstring& function_name) {
[email protected]adcf8492011-03-09 22:41:39142 web_ui_->CallJavascriptFunction(WideToASCII(function_name));
[email protected]73852b8f2010-05-14 00:38:12143}
144
145void CloudPrintDataSenderHelper::CallJavascriptFunction(
146 const std::wstring& function_name, const Value& arg) {
[email protected]adcf8492011-03-09 22:41:39147 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg);
[email protected]73852b8f2010-05-14 00:38:12148}
149
150void CloudPrintDataSenderHelper::CallJavascriptFunction(
151 const std::wstring& function_name, const Value& arg1, const Value& arg2) {
[email protected]adcf8492011-03-09 22:41:39152 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2);
[email protected]73852b8f2010-05-14 00:38:12153}
154
[email protected]e8368e92011-08-20 04:05:56155void CloudPrintDataSenderHelper::CallJavascriptFunction(
156 const std::wstring& function_name,
157 const Value& arg1,
158 const Value& arg2,
159 const Value& arg3) {
160 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2, arg3);
161}
162
[email protected]73852b8f2010-05-14 00:38:12163// Clears out the pointer we're using to communicate. Either routine is
164// potentially expensive enough that stopping whatever is in progress
165// is worth it.
166void CloudPrintDataSender::CancelPrintDataFile() {
[email protected]20305ec2011-01-21 04:55:52167 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12168 // We don't own helper, it was passed in to us, so no need to
169 // delete, just let it go.
170 helper_ = NULL;
171}
172
[email protected]38e08982010-10-22 17:28:43173CloudPrintDataSender::CloudPrintDataSender(CloudPrintDataSenderHelper* helper,
[email protected]a984bdf2011-03-15 20:17:16174 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56175 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16176 const std::string& file_type)
[email protected]38e08982010-10-22 17:28:43177 : helper_(helper),
[email protected]a984bdf2011-03-15 20:17:16178 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56179 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16180 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43181}
182
183CloudPrintDataSender::~CloudPrintDataSender() {}
184
[email protected]a984bdf2011-03-15 20:17:16185// Grab the raw file contents and massage them into shape for
[email protected]73852b8f2010-05-14 00:38:12186// sending to the dialog contents (and up to the cloud print server)
187// by encoding it and prefixing it with the appropriate mime type.
188// Once that is done, kick off the next part of the task on the IO
189// thread.
[email protected]a984bdf2011-03-15 20:17:16190void CloudPrintDataSender::ReadPrintDataFile(const FilePath& path_to_file) {
[email protected]ba4f1132010-10-09 02:02:35191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]73852b8f2010-05-14 00:38:12192 int64 file_size = 0;
[email protected]a984bdf2011-03-15 20:17:16193 if (file_util::GetFileSize(path_to_file, &file_size) && file_size != 0) {
[email protected]73852b8f2010-05-14 00:38:12194 std::string file_data;
195 if (file_size < kuint32max) {
196 file_data.reserve(static_cast<unsigned int>(file_size));
197 } else {
198 DLOG(WARNING) << " print data file too large to reserve space";
199 }
[email protected]a984bdf2011-03-15 20:17:16200 if (helper_ && file_util::ReadFileToString(path_to_file, &file_data)) {
[email protected]73852b8f2010-05-14 00:38:12201 std::string base64_data;
202 base::Base64Encode(file_data, &base64_data);
[email protected]a984bdf2011-03-15 20:17:16203 std::string header("data:");
204 header.append(file_type_);
205 header.append(";base64,");
[email protected]73852b8f2010-05-14 00:38:12206 base64_data.insert(0, header);
207 scoped_ptr<StringValue> new_data(new StringValue(base64_data));
208 print_data_.swap(new_data);
[email protected]ba4f1132010-10-09 02:02:35209 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
210 NewRunnableMethod(
211 this,
212 &CloudPrintDataSender::SendPrintDataFile));
[email protected]73852b8f2010-05-14 00:38:12213 }
214 }
215}
216
217// We have the data in hand that needs to be pushed into the dialog
218// contents; do so from the IO thread.
219
220// TODO(scottbyer): If the print data ends up being larger than the
221// upload limit (currently 10MB), what we need to do is upload that
222// large data to google docs and set the URL in the printing
223// JavaScript to that location, and make sure it gets deleted when not
224// needed. - 4/1/2010
225void CloudPrintDataSender::SendPrintDataFile() {
[email protected]ba4f1132010-10-09 02:02:35226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20305ec2011-01-21 04:55:52227 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12228 if (helper_ && print_data_.get()) {
[email protected]9848c7e2010-06-03 16:06:56229 StringValue title(print_job_title_);
[email protected]e8368e92011-08-20 04:05:56230 StringValue ticket(print_ticket_);
231 // TODO(abodenha): Change Javascript call to pass in print ticket
232 // after server side support is added. Add test for it.
[email protected]73852b8f2010-05-14 00:38:12233
234 // Send the print data to the dialog contents. The JavaScript
235 // function is a preliminary API for prototyping purposes and is
236 // subject to change.
237 const_cast<CloudPrintDataSenderHelper*>(helper_)->CallJavascriptFunction(
238 L"printApp._printDataUrl", *print_data_, title);
239 }
240}
241
242
[email protected]a984bdf2011-03-15 20:17:16243CloudPrintFlowHandler::CloudPrintFlowHandler(const FilePath& path_to_file,
244 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56245 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16246 const std::string& file_type)
[email protected]c7bf7452011-09-12 21:31:50247 : dialog_delegate_(NULL),
248 path_to_file_(path_to_file),
[email protected]a984bdf2011-03-15 20:17:16249 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56250 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16251 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43252}
253
254CloudPrintFlowHandler::~CloudPrintFlowHandler() {
255 // This will also cancel any task in flight.
256 CancelAnyRunningTask();
257}
258
259
[email protected]73852b8f2010-05-14 00:38:12260void CloudPrintFlowHandler::SetDialogDelegate(
261 CloudPrintHtmlDialogDelegate* delegate) {
[email protected]7b748982011-02-14 19:28:23262 // Even if setting a new WebUI, it means any previous task needs
[email protected]73852b8f2010-05-14 00:38:12263 // to be cancelled, it's now invalid.
[email protected]ba4f1132010-10-09 02:02:35264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12265 CancelAnyRunningTask();
266 dialog_delegate_ = delegate;
267}
268
269// Cancels any print data sender we have in flight and removes our
270// reference to it, so when the task that is calling it finishes and
271// removes it's reference, it goes away.
272void CloudPrintFlowHandler::CancelAnyRunningTask() {
[email protected]ba4f1132010-10-09 02:02:35273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12274 if (print_data_sender_.get()) {
275 print_data_sender_->CancelPrintDataFile();
276 print_data_sender_ = NULL;
277 }
278}
279
[email protected]73852b8f2010-05-14 00:38:12280void CloudPrintFlowHandler::RegisterMessages() {
[email protected]7b748982011-02-14 19:28:23281 if (!web_ui_)
[email protected]73852b8f2010-05-14 00:38:12282 return;
283
284 // TODO(scottbyer) - This is where we will register messages for the
285 // UI JS to use. Needed: Call to update page setup parameters.
[email protected]7b748982011-02-14 19:28:23286 web_ui_->RegisterMessageCallback(
[email protected]73852b8f2010-05-14 00:38:12287 "ShowDebugger",
288 NewCallback(this, &CloudPrintFlowHandler::HandleShowDebugger));
[email protected]7b748982011-02-14 19:28:23289 web_ui_->RegisterMessageCallback(
[email protected]73852b8f2010-05-14 00:38:12290 "SendPrintData",
291 NewCallback(this, &CloudPrintFlowHandler::HandleSendPrintData));
[email protected]7b748982011-02-14 19:28:23292 web_ui_->RegisterMessageCallback(
[email protected]73852b8f2010-05-14 00:38:12293 "SetPageParameters",
294 NewCallback(this, &CloudPrintFlowHandler::HandleSetPageParameters));
295
[email protected]0eb25c42011-08-11 14:50:14296 // Register for appropriate notifications, and re-direct the URL
297 // to the real server URL, now that we've gotten an HTML dialog
298 // going.
299 NavigationController* controller = &web_ui_->tab_contents()->controller();
300 NavigationEntry* pending_entry = controller->pending_entry();
301 if (pending_entry) {
302 Profile* profile = Profile::FromWebUI(web_ui_);
303 pending_entry->set_url(
304 CloudPrintURL(profile).GetCloudPrintServiceDialogURL());
[email protected]73852b8f2010-05-14 00:38:12305 }
[email protected]0eb25c42011-08-11 14:50:14306 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
307 Source<NavigationController>(controller));
[email protected]73852b8f2010-05-14 00:38:12308}
309
[email protected]432115822011-07-10 15:52:27310void CloudPrintFlowHandler::Observe(int type,
[email protected]73852b8f2010-05-14 00:38:12311 const NotificationSource& source,
312 const NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:27313 if (type == content::NOTIFICATION_LOAD_STOP) {
[email protected]20c52d22011-06-20 22:42:42314 // Take the opportunity to set some (minimal) additional
315 // script permissions required for the web UI.
316 GURL url = web_ui_->tab_contents()->GetURL();
317 GURL dialog_url = CloudPrintURL(
[email protected]0eb25c42011-08-11 14:50:14318 Profile::FromWebUI(web_ui_)).GetCloudPrintServiceDialogURL();
[email protected]20c52d22011-06-20 22:42:42319 if (url.host() == dialog_url.host() &&
320 url.path() == dialog_url.path() &&
321 url.scheme() == dialog_url.scheme()) {
322 RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
323 if (rvh && rvh->delegate()) {
324 WebPreferences webkit_prefs = rvh->delegate()->GetWebkitPrefs();
325 webkit_prefs.allow_scripts_to_close_windows = true;
326 rvh->Send(new ViewMsg_UpdateWebPreferences(
327 rvh->routing_id(), webkit_prefs));
328 } 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