blob: c1d4c4e9b058bc2bb15388a7fef7097c19977579 [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]c051a1b2011-01-21 23:30:1734#include "ui/base/l10n/l10n_util.h"
[email protected]939856a2010-08-24 20:29:0235#include "webkit/glue/webpreferences.h"
[email protected]73852b8f2010-05-14 00:38:1236
37#include "grit/generated_resources.h"
38
39// This module implements the UI support in Chrome for cloud printing.
40// This means hosting a dialog containing HTML/JavaScript and using
41// the published cloud print user interface integration APIs to get
42// page setup settings from the dialog contents and provide the
[email protected]a984bdf2011-03-15 20:17:1643// generated print data to the dialog contents for uploading to the
[email protected]73852b8f2010-05-14 00:38:1244// cloud print service.
45
46// Currently, the flow between these classes is as follows:
47
[email protected]a984bdf2011-03-15 20:17:1648// PrintDialogCloud::CreatePrintDialogForFile is called from
[email protected]73852b8f2010-05-14 00:38:1249// resource_message_filter_gtk.cc once the renderer has informed the
[email protected]a984bdf2011-03-15 20:17:1650// renderer host that print data generation into the renderer host provided
[email protected]032682b2011-01-12 22:05:0251// temp file has been completed. That call is on the FILE thread.
[email protected]73852b8f2010-05-14 00:38:1252// That, in turn, hops over to the UI thread to create an instance of
53// PrintDialogCloud.
54
55// The constructor for PrintDialogCloud creates a
56// CloudPrintHtmlDialogDelegate and asks the current active browser to
57// show an HTML dialog using that class as the delegate. That class
[email protected]89f550b2011-06-08 18:34:0358// hands in the kChromeUICloudPrintResourcesURL as the URL to visit. That is
[email protected]80a8fad2011-01-29 04:02:3859// recognized by the GetWebUIFactoryFunction as a signal to create an
[email protected]73852b8f2010-05-14 00:38:1260// ExternalHtmlDialogUI.
61
62// CloudPrintHtmlDialogDelegate also temporarily owns a
63// CloudPrintFlowHandler, a class which is responsible for the actual
[email protected]a984bdf2011-03-15 20:17:1664// interactions with the dialog contents, including handing in the
[email protected]73852b8f2010-05-14 00:38:1265// print data and getting any page setup parameters that the dialog
66// contents provides. As part of bringing up the dialog,
67// HtmlDialogUI::RenderViewCreated is called (an override of
[email protected]c39f9bf2011-02-12 00:43:5568// WebUI::RenderViewCreated). That routine, in turn, calls the
[email protected]36e12172011-02-08 23:46:0269// delegate's GetWebUIMessageHandlers routine, at which point the
[email protected]73852b8f2010-05-14 00:38:1270// ownership of the CloudPrintFlowHandler is handed over. A pointer
71// to the flow handler is kept to facilitate communication back and
72// forth between the two classes.
73
[email protected]c39f9bf2011-02-12 00:43:5574// The WebUI continues dialog bring-up, calling
[email protected]73852b8f2010-05-14 00:38:1275// CloudPrintFlowHandler::RegisterMessages. This is where the
76// additional object model capabilities are registered for the dialog
77// contents to use. It is also at this time that capabilities for the
78// dialog contents are adjusted to allow the dialog contents to close
79// the window. In addition, the pending URL is redirected to the
80// actual cloud print service URL. The flow controller also registers
81// for notification of when the dialog contents finish loading, which
[email protected]a984bdf2011-03-15 20:17:1682// is currently used to send the data to the dialog contents.
[email protected]73852b8f2010-05-14 00:38:1283
[email protected]a984bdf2011-03-15 20:17:1684// In order to send the data to the dialog contents, the flow
[email protected]73852b8f2010-05-14 00:38:1285// handler uses a CloudPrintDataSender. It creates one, letting it
[email protected]a984bdf2011-03-15 20:17:1686// know the name of the temporary file containing the data, and
[email protected]73852b8f2010-05-14 00:38:1287// posts the task of reading the file
88// (CloudPrintDataSender::ReadPrintDataFile) to the file thread. That
89// routine reads in the file, and then hops over to the IO thread to
90// send that data to the dialog contents.
91
92// When the dialog contents are finished (by either being cancelled or
93// hitting the print button), the delegate is notified, and responds
94// that the dialog should be closed, at which point things are torn
95// down and released.
96
97// TODO(scottbyer):
98// http://code.google.com/p/chromium/issues/detail?id=44093 The
[email protected]a984bdf2011-03-15 20:17:1699// high-level flow (where the data is generated before even
[email protected]73852b8f2010-05-14 00:38:12100// bringing up the dialog) isn't what we want.
101
[email protected]73852b8f2010-05-14 00:38:12102namespace internal_cloud_print_helpers {
103
[email protected]73852b8f2010-05-14 00:38:12104// From the JSON parsed value, get the entries for the page setup
105// parameters.
106bool GetPageSetupParameters(const std::string& json,
[email protected]1375e3ab2011-03-24 17:07:22107 PrintMsg_Print_Params& parameters) {
[email protected]73852b8f2010-05-14 00:38:12108 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
109 DLOG_IF(ERROR, (!parsed_value.get() ||
110 !parsed_value->IsType(Value::TYPE_DICTIONARY)))
111 << "PageSetup call didn't have expected contents";
112 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
113 return false;
114
115 bool result = true;
116 DictionaryValue* params = static_cast<DictionaryValue*>(parsed_value.get());
[email protected]05c7da62011-05-05 17:23:56117 result &= params->GetDouble("dpi", &parameters.dpi);
118 result &= params->GetDouble("min_shrink", &parameters.min_shrink);
119 result &= params->GetDouble("max_shrink", &parameters.max_shrink);
[email protected]a65175d2010-08-17 04:00:57120 result &= params->GetBoolean("selection_only", &parameters.selection_only);
[email protected]73852b8f2010-05-14 00:38:12121 return result;
122}
123
[email protected]e8368e92011-08-20 04:05:56124string16 GetSwitchValueString16(const CommandLine& command_line,
125 const char* switchName) {
126#ifdef OS_WIN
127 CommandLine::StringType native_switch_val;
128 native_switch_val = command_line.GetSwitchValueNative(switchName);
129 return string16(native_switch_val);
130#elif defined(OS_POSIX)
131 // POSIX Command line string types are different.
132 CommandLine::StringType native_switch_val;
133 native_switch_val = command_line.GetSwitchValueASCII(switchName);
134 // Convert the ASCII string to UTF16 to prepare to pass.
135 return string16(ASCIIToUTF16(native_switch_val));
136#endif
137}
138
[email protected]73852b8f2010-05-14 00:38:12139void CloudPrintDataSenderHelper::CallJavascriptFunction(
140 const std::wstring& function_name) {
[email protected]adcf8492011-03-09 22:41:39141 web_ui_->CallJavascriptFunction(WideToASCII(function_name));
[email protected]73852b8f2010-05-14 00:38:12142}
143
144void CloudPrintDataSenderHelper::CallJavascriptFunction(
145 const std::wstring& function_name, const Value& arg) {
[email protected]adcf8492011-03-09 22:41:39146 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg);
[email protected]73852b8f2010-05-14 00:38:12147}
148
149void CloudPrintDataSenderHelper::CallJavascriptFunction(
150 const std::wstring& function_name, const Value& arg1, const Value& arg2) {
[email protected]adcf8492011-03-09 22:41:39151 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2);
[email protected]73852b8f2010-05-14 00:38:12152}
153
[email protected]e8368e92011-08-20 04:05:56154void CloudPrintDataSenderHelper::CallJavascriptFunction(
155 const std::wstring& function_name,
156 const Value& arg1,
157 const Value& arg2,
158 const Value& arg3) {
159 web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2, arg3);
160}
161
[email protected]73852b8f2010-05-14 00:38:12162// Clears out the pointer we're using to communicate. Either routine is
163// potentially expensive enough that stopping whatever is in progress
164// is worth it.
165void CloudPrintDataSender::CancelPrintDataFile() {
[email protected]20305ec2011-01-21 04:55:52166 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12167 // We don't own helper, it was passed in to us, so no need to
168 // delete, just let it go.
169 helper_ = NULL;
170}
171
[email protected]38e08982010-10-22 17:28:43172CloudPrintDataSender::CloudPrintDataSender(CloudPrintDataSenderHelper* helper,
[email protected]a984bdf2011-03-15 20:17:16173 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56174 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16175 const std::string& file_type)
[email protected]38e08982010-10-22 17:28:43176 : helper_(helper),
[email protected]a984bdf2011-03-15 20:17:16177 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56178 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16179 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43180}
181
182CloudPrintDataSender::~CloudPrintDataSender() {}
183
[email protected]a984bdf2011-03-15 20:17:16184// Grab the raw file contents and massage them into shape for
[email protected]73852b8f2010-05-14 00:38:12185// sending to the dialog contents (and up to the cloud print server)
186// by encoding it and prefixing it with the appropriate mime type.
187// Once that is done, kick off the next part of the task on the IO
188// thread.
[email protected]a984bdf2011-03-15 20:17:16189void CloudPrintDataSender::ReadPrintDataFile(const FilePath& path_to_file) {
[email protected]ba4f1132010-10-09 02:02:35190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]73852b8f2010-05-14 00:38:12191 int64 file_size = 0;
[email protected]a984bdf2011-03-15 20:17:16192 if (file_util::GetFileSize(path_to_file, &file_size) && file_size != 0) {
[email protected]73852b8f2010-05-14 00:38:12193 std::string file_data;
194 if (file_size < kuint32max) {
195 file_data.reserve(static_cast<unsigned int>(file_size));
196 } else {
197 DLOG(WARNING) << " print data file too large to reserve space";
198 }
[email protected]a984bdf2011-03-15 20:17:16199 if (helper_ && file_util::ReadFileToString(path_to_file, &file_data)) {
[email protected]73852b8f2010-05-14 00:38:12200 std::string base64_data;
201 base::Base64Encode(file_data, &base64_data);
[email protected]a984bdf2011-03-15 20:17:16202 std::string header("data:");
203 header.append(file_type_);
204 header.append(";base64,");
[email protected]73852b8f2010-05-14 00:38:12205 base64_data.insert(0, header);
206 scoped_ptr<StringValue> new_data(new StringValue(base64_data));
207 print_data_.swap(new_data);
[email protected]ba4f1132010-10-09 02:02:35208 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
209 NewRunnableMethod(
210 this,
211 &CloudPrintDataSender::SendPrintDataFile));
[email protected]73852b8f2010-05-14 00:38:12212 }
213 }
214}
215
216// We have the data in hand that needs to be pushed into the dialog
217// contents; do so from the IO thread.
218
219// TODO(scottbyer): If the print data ends up being larger than the
220// upload limit (currently 10MB), what we need to do is upload that
221// large data to google docs and set the URL in the printing
222// JavaScript to that location, and make sure it gets deleted when not
223// needed. - 4/1/2010
224void CloudPrintDataSender::SendPrintDataFile() {
[email protected]ba4f1132010-10-09 02:02:35225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20305ec2011-01-21 04:55:52226 base::AutoLock lock(lock_);
[email protected]73852b8f2010-05-14 00:38:12227 if (helper_ && print_data_.get()) {
[email protected]9848c7e2010-06-03 16:06:56228 StringValue title(print_job_title_);
[email protected]e8368e92011-08-20 04:05:56229 StringValue ticket(print_ticket_);
230 // TODO(abodenha): Change Javascript call to pass in print ticket
231 // after server side support is added. Add test for it.
[email protected]73852b8f2010-05-14 00:38:12232
233 // Send the print data to the dialog contents. The JavaScript
234 // function is a preliminary API for prototyping purposes and is
235 // subject to change.
236 const_cast<CloudPrintDataSenderHelper*>(helper_)->CallJavascriptFunction(
237 L"printApp._printDataUrl", *print_data_, title);
238 }
239}
240
241
[email protected]a984bdf2011-03-15 20:17:16242CloudPrintFlowHandler::CloudPrintFlowHandler(const FilePath& path_to_file,
243 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56244 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16245 const std::string& file_type)
[email protected]c7bf7452011-09-12 21:31:50246 : dialog_delegate_(NULL),
247 path_to_file_(path_to_file),
[email protected]a984bdf2011-03-15 20:17:16248 print_job_title_(print_job_title),
[email protected]e8368e92011-08-20 04:05:56249 print_ticket_(print_ticket),
[email protected]a984bdf2011-03-15 20:17:16250 file_type_(file_type) {
[email protected]38e08982010-10-22 17:28:43251}
252
253CloudPrintFlowHandler::~CloudPrintFlowHandler() {
254 // This will also cancel any task in flight.
255 CancelAnyRunningTask();
256}
257
258
[email protected]73852b8f2010-05-14 00:38:12259void CloudPrintFlowHandler::SetDialogDelegate(
260 CloudPrintHtmlDialogDelegate* delegate) {
[email protected]7b748982011-02-14 19:28:23261 // Even if setting a new WebUI, it means any previous task needs
[email protected]73852b8f2010-05-14 00:38:12262 // to be cancelled, it's now invalid.
[email protected]ba4f1132010-10-09 02:02:35263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12264 CancelAnyRunningTask();
265 dialog_delegate_ = delegate;
266}
267
268// Cancels any print data sender we have in flight and removes our
269// reference to it, so when the task that is calling it finishes and
270// removes it's reference, it goes away.
271void CloudPrintFlowHandler::CancelAnyRunningTask() {
[email protected]ba4f1132010-10-09 02:02:35272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12273 if (print_data_sender_.get()) {
274 print_data_sender_->CancelPrintDataFile();
275 print_data_sender_ = NULL;
276 }
277}
278
[email protected]73852b8f2010-05-14 00:38:12279void CloudPrintFlowHandler::RegisterMessages() {
[email protected]7b748982011-02-14 19:28:23280 if (!web_ui_)
[email protected]73852b8f2010-05-14 00:38:12281 return;
282
283 // TODO(scottbyer) - This is where we will register messages for the
284 // UI JS to use. Needed: Call to update page setup parameters.
[email protected]7b748982011-02-14 19:28:23285 web_ui_->RegisterMessageCallback(
[email protected]73852b8f2010-05-14 00:38:12286 "ShowDebugger",
287 NewCallback(this, &CloudPrintFlowHandler::HandleShowDebugger));
[email protected]7b748982011-02-14 19:28:23288 web_ui_->RegisterMessageCallback(
[email protected]73852b8f2010-05-14 00:38:12289 "SendPrintData",
290 NewCallback(this, &CloudPrintFlowHandler::HandleSendPrintData));
[email protected]7b748982011-02-14 19:28:23291 web_ui_->RegisterMessageCallback(
[email protected]73852b8f2010-05-14 00:38:12292 "SetPageParameters",
293 NewCallback(this, &CloudPrintFlowHandler::HandleSetPageParameters));
294
[email protected]0eb25c42011-08-11 14:50:14295 // Register for appropriate notifications, and re-direct the URL
296 // to the real server URL, now that we've gotten an HTML dialog
297 // going.
298 NavigationController* controller = &web_ui_->tab_contents()->controller();
299 NavigationEntry* pending_entry = controller->pending_entry();
300 if (pending_entry) {
301 Profile* profile = Profile::FromWebUI(web_ui_);
302 pending_entry->set_url(
303 CloudPrintURL(profile).GetCloudPrintServiceDialogURL());
[email protected]73852b8f2010-05-14 00:38:12304 }
[email protected]0eb25c42011-08-11 14:50:14305 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
306 Source<NavigationController>(controller));
[email protected]73852b8f2010-05-14 00:38:12307}
308
[email protected]432115822011-07-10 15:52:27309void CloudPrintFlowHandler::Observe(int type,
[email protected]73852b8f2010-05-14 00:38:12310 const NotificationSource& source,
311 const NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:27312 if (type == content::NOTIFICATION_LOAD_STOP) {
[email protected]20c52d22011-06-20 22:42:42313 // Take the opportunity to set some (minimal) additional
314 // script permissions required for the web UI.
315 GURL url = web_ui_->tab_contents()->GetURL();
316 GURL dialog_url = CloudPrintURL(
[email protected]0eb25c42011-08-11 14:50:14317 Profile::FromWebUI(web_ui_)).GetCloudPrintServiceDialogURL();
[email protected]20c52d22011-06-20 22:42:42318 if (url.host() == dialog_url.host() &&
319 url.path() == dialog_url.path() &&
320 url.scheme() == dialog_url.scheme()) {
321 RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
322 if (rvh && rvh->delegate()) {
323 WebPreferences webkit_prefs = rvh->delegate()->GetWebkitPrefs();
324 webkit_prefs.allow_scripts_to_close_windows = true;
[email protected]9abd51f2011-09-21 19:11:35325 rvh->UpdateWebkitPreferences(webkit_prefs);
[email protected]20c52d22011-06-20 22:42:42326 } else {
327 DCHECK(false);
328 }
329 }
330
[email protected]73852b8f2010-05-14 00:38:12331 // Choose one or the other. If you need to debug, bring up the
332 // debugger. You can then use the various chrome.send()
333 // registrations above to kick of the various function calls,
334 // including chrome.send("SendPrintData") in the javaScript
335 // console and watch things happen with:
336 // HandleShowDebugger(NULL);
337 HandleSendPrintData(NULL);
338 }
339}
340
[email protected]88942a22010-08-19 20:34:43341void CloudPrintFlowHandler::HandleShowDebugger(const ListValue* args) {
[email protected]73852b8f2010-05-14 00:38:12342 ShowDebugger();
343}
344
345void CloudPrintFlowHandler::ShowDebugger() {
[email protected]7b748982011-02-14 19:28:23346 if (web_ui_) {
347 RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
[email protected]73852b8f2010-05-14 00:38:12348 if (rvh)
[email protected]aebdd072011-07-07 12:36:59349 DevToolsWindow::OpenDevToolsWindow(rvh);
[email protected]73852b8f2010-05-14 00:38:12350 }
351}
352
353scoped_refptr<CloudPrintDataSender>
354CloudPrintFlowHandler::CreateCloudPrintDataSender() {
[email protected]7b748982011-02-14 19:28:23355 DCHECK(web_ui_);
356 print_data_helper_.reset(new CloudPrintDataSenderHelper(web_ui_));
[email protected]a984bdf2011-03-15 20:17:16357 return new CloudPrintDataSender(print_data_helper_.get(),
358 print_job_title_,
[email protected]e8368e92011-08-20 04:05:56359 print_ticket_,
[email protected]a984bdf2011-03-15 20:17:16360 file_type_);
[email protected]73852b8f2010-05-14 00:38:12361}
362
[email protected]88942a22010-08-19 20:34:43363void CloudPrintFlowHandler::HandleSendPrintData(const ListValue* args) {
[email protected]ba4f1132010-10-09 02:02:35364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12365 // This will cancel any ReadPrintDataFile() or SendPrintDataFile()
366 // requests in flight (this is anticipation of when setting page
367 // setup parameters becomes asynchronous and may be set while some
368 // data is in flight). Then we can clear out the print data.
369 CancelAnyRunningTask();
[email protected]7b748982011-02-14 19:28:23370 if (web_ui_) {
[email protected]73852b8f2010-05-14 00:38:12371 print_data_sender_ = CreateCloudPrintDataSender();
[email protected]ba4f1132010-10-09 02:02:35372 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
373 NewRunnableMethod(
374 print_data_sender_.get(),
375 &CloudPrintDataSender::ReadPrintDataFile,
[email protected]a984bdf2011-03-15 20:17:16376 path_to_file_));
[email protected]73852b8f2010-05-14 00:38:12377 }
378}
379
[email protected]88942a22010-08-19 20:34:43380void CloudPrintFlowHandler::HandleSetPageParameters(const ListValue* args) {
[email protected]036056a32011-03-03 21:05:01381 std::string json;
[email protected]e675f7b2011-06-22 17:32:12382 bool ret = args->GetString(0, &json);
383 if (!ret || json.empty()) {
[email protected]036056a32011-03-03 21:05:01384 NOTREACHED() << "Empty json string";
[email protected]73852b8f2010-05-14 00:38:12385 return;
[email protected]036056a32011-03-03 21:05:01386 }
[email protected]73852b8f2010-05-14 00:38:12387
388 // These are backstop default values - 72 dpi to match the screen,
389 // 8.5x11 inch paper with margins subtracted (1/4 inch top, left,
390 // right and 0.56 bottom), and the min page shrink and max page
391 // shrink values appear all over the place with no explanation.
392
393 // TODO(scottbyer): Get a Linux/ChromeOS edge for PrintSettings
394 // working so that we can get the default values from there. Fix up
395 // PrintWebViewHelper to do the same.
396 const int kDPI = 72;
397 const int kWidth = static_cast<int>((8.5-0.25-0.25)*kDPI);
398 const int kHeight = static_cast<int>((11-0.25-0.56)*kDPI);
399 const double kMinPageShrink = 1.25;
400 const double kMaxPageShrink = 2.0;
401
[email protected]1375e3ab2011-03-24 17:07:22402 PrintMsg_Print_Params default_settings;
[email protected]73852b8f2010-05-14 00:38:12403 default_settings.printable_size = gfx::Size(kWidth, kHeight);
404 default_settings.dpi = kDPI;
405 default_settings.min_shrink = kMinPageShrink;
406 default_settings.max_shrink = kMaxPageShrink;
407 default_settings.desired_dpi = kDPI;
408 default_settings.document_cookie = 0;
409 default_settings.selection_only = false;
[email protected]718af822011-08-12 22:11:33410 default_settings.preview_request_id = 0;
411 default_settings.is_first_request = true;
[email protected]73852b8f2010-05-14 00:38:12412
413 if (!GetPageSetupParameters(json, default_settings)) {
414 NOTREACHED();
415 return;
416 }
417
418 // TODO(scottbyer) - Here is where we would kick the originating
419 // renderer thread with these new parameters in order to get it to
[email protected]a984bdf2011-03-15 20:17:16420 // re-generate the PDF data and hand it back to us. window.print() is
[email protected]73852b8f2010-05-14 00:38:12421 // currently synchronous, so there's a lot of work to do to get to
422 // that point.
423}
424
[email protected]ea161da2010-11-02 21:57:35425void CloudPrintFlowHandler::StoreDialogClientSize() const {
[email protected]7b748982011-02-14 19:28:23426 if (web_ui_ && web_ui_->tab_contents() && web_ui_->tab_contents()->view()) {
427 gfx::Size size = web_ui_->tab_contents()->view()->GetContainerSize();
[email protected]0eb25c42011-08-11 14:50:14428 Profile* profile = Profile::FromWebUI(web_ui_);
429 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogWidth,
430 size.width());
431 profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogHeight,
432 size.height());
[email protected]ea161da2010-11-02 21:57:35433 }
434}
435
[email protected]73852b8f2010-05-14 00:38:12436CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
[email protected]a984bdf2011-03-15 20:17:16437 const FilePath& path_to_file,
[email protected]73852b8f2010-05-14 00:38:12438 int width, int height,
[email protected]9848c7e2010-06-03 16:06:56439 const std::string& json_arguments,
[email protected]e39027a2011-01-24 21:41:54440 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56441 const string16& print_ticket,
[email protected]a984bdf2011-03-15 20:17:16442 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03443 bool modal,
444 bool delete_on_close)
445 : delete_on_close_(delete_on_close),
446 flow_handler_(new CloudPrintFlowHandler(path_to_file,
[email protected]a984bdf2011-03-15 20:17:16447 print_job_title,
[email protected]e8368e92011-08-20 04:05:56448 print_ticket,
[email protected]a984bdf2011-03-15 20:17:16449 file_type)),
[email protected]e39027a2011-01-24 21:41:54450 modal_(modal),
[email protected]6ddda232011-04-22 15:41:47451 owns_flow_handler_(true),
452 path_to_file_(path_to_file) {
[email protected]73852b8f2010-05-14 00:38:12453 Init(width, height, json_arguments);
454}
455
[email protected]05acb55472011-02-03 00:11:07456// For unit testing.
[email protected]73852b8f2010-05-14 00:38:12457CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
458 CloudPrintFlowHandler* flow_handler,
459 int width, int height,
[email protected]e39027a2011-01-24 21:41:54460 const std::string& json_arguments,
[email protected]d955fc92011-09-19 20:49:03461 bool modal,
462 bool delete_on_close)
463 : delete_on_close_(delete_on_close),
464 flow_handler_(flow_handler),
[email protected]e39027a2011-01-24 21:41:54465 modal_(modal),
[email protected]18137e02010-05-25 21:10:35466 owns_flow_handler_(true) {
[email protected]73852b8f2010-05-14 00:38:12467 Init(width, height, json_arguments);
468}
469
[email protected]05acb55472011-02-03 00:11:07470void CloudPrintHtmlDialogDelegate::Init(int width, int height,
471 const std::string& json_arguments) {
[email protected]73852b8f2010-05-14 00:38:12472 // This information is needed to show the dialog HTML content.
[email protected]ba4f1132010-10-09 02:02:35473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]89f550b2011-06-08 18:34:03474 params_.url = GURL(chrome::kChromeUICloudPrintResourcesURL);
[email protected]73852b8f2010-05-14 00:38:12475 params_.height = height;
476 params_.width = width;
477 params_.json_input = json_arguments;
478
479 flow_handler_->SetDialogDelegate(this);
[email protected]e39027a2011-01-24 21:41:54480 // If we're not modal we can show the dialog with no browser.
481 // We need this to keep Chrome alive while our dialog is up.
482 if (!modal_)
483 BrowserList::StartKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12484}
485
486CloudPrintHtmlDialogDelegate::~CloudPrintHtmlDialogDelegate() {
487 // If the flow_handler_ is about to outlive us because we don't own
488 // it anymore, we need to have it remove it's reference to us.
[email protected]ba4f1132010-10-09 02:02:35489 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]73852b8f2010-05-14 00:38:12490 flow_handler_->SetDialogDelegate(NULL);
491 if (owns_flow_handler_) {
492 delete flow_handler_;
493 }
494}
495
496bool CloudPrintHtmlDialogDelegate::IsDialogModal() const {
[email protected]e39027a2011-01-24 21:41:54497 return modal_;
[email protected]73852b8f2010-05-14 00:38:12498}
499
[email protected]bdae5c12011-08-05 21:49:06500string16 CloudPrintHtmlDialogDelegate::GetDialogTitle() const {
501 return string16();
[email protected]73852b8f2010-05-14 00:38:12502}
503
504GURL CloudPrintHtmlDialogDelegate::GetDialogContentURL() const {
505 return params_.url;
506}
507
[email protected]36e12172011-02-08 23:46:02508void CloudPrintHtmlDialogDelegate::GetWebUIMessageHandlers(
509 std::vector<WebUIMessageHandler*>* handlers) const {
[email protected]73852b8f2010-05-14 00:38:12510 handlers->push_back(flow_handler_);
511 // We don't own flow_handler_ anymore, but it sticks around until at
512 // least right after OnDialogClosed() is called (and this object is
513 // destroyed).
514 owns_flow_handler_ = false;
515}
516
517void CloudPrintHtmlDialogDelegate::GetDialogSize(gfx::Size* size) const {
518 size->set_width(params_.width);
519 size->set_height(params_.height);
520}
521
522std::string CloudPrintHtmlDialogDelegate::GetDialogArgs() const {
523 return params_.json_input;
524}
525
526void CloudPrintHtmlDialogDelegate::OnDialogClosed(
527 const std::string& json_retval) {
[email protected]ea161da2010-11-02 21:57:35528 // Get the final dialog size and store it.
529 flow_handler_->StoreDialogClientSize();
[email protected]6ddda232011-04-22 15:41:47530
[email protected]d955fc92011-09-19 20:49:03531 if (delete_on_close_) {
[email protected]6ddda232011-04-22 15:41:47532 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
533 NewRunnableFunction(&internal_cloud_print_helpers::Delete,
534 path_to_file_));
535 }
536
[email protected]e39027a2011-01-24 21:41:54537 // If we're modal we can show the dialog with no browser.
538 // End the keep-alive so that Chrome can exit.
539 if (!modal_)
540 BrowserList::EndKeepAlive();
[email protected]73852b8f2010-05-14 00:38:12541 delete this;
542}
543
[email protected]18137e02010-05-25 21:10:35544void CloudPrintHtmlDialogDelegate::OnCloseContents(TabContents* source,
545 bool* out_close_dialog) {
546 if (out_close_dialog)
547 *out_close_dialog = true;
548}
549
[email protected]ea161da2010-11-02 21:57:35550bool CloudPrintHtmlDialogDelegate::ShouldShowDialogTitle() const {
551 return false;
552}
553
[email protected]34478212011-04-19 01:35:46554bool CloudPrintHtmlDialogDelegate::HandleContextMenu(
555 const ContextMenuParams& params) {
556 return true;
557}
558
[email protected]d955fc92011-09-19 20:49:03559void CreatePrintDialogForBytesImpl(scoped_refptr<RefCountedBytes> data,
560 const string16& print_job_title,
561 const string16& print_ticket,
562 const std::string& file_type,
563 bool modal) {
564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
565 // TODO([email protected]) Writing the PDF to a file before printing
566 // is wasteful. Modify the dialog flow to pull PDF data from memory.
567 // See http://code.google.com/p/chromium/issues/detail?id=44093
568 FilePath path;
569 if (file_util::CreateTemporaryFile(&path)) {
570 file_util::WriteFile(path,
571 reinterpret_cast<const char*>(data->front()),
572 data->size());
573 }
574 print_dialog_cloud::CreatePrintDialogForFile(path,
575 print_job_title,
576 print_ticket,
577 file_type,
578 modal,
579 true);
580}
581
[email protected]6085c70d2011-03-22 22:51:07582// Called from the UI thread, starts up the dialog.
583void CreateDialogImpl(const FilePath& path_to_file,
584 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56585 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07586 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03587 bool modal,
588 bool delete_on_close) {
[email protected]ba4f1132010-10-09 02:02:35589 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]6085c70d2011-03-22 22:51:07590 Browser* browser = BrowserList::GetLastActive();
[email protected]73852b8f2010-05-14 00:38:12591
[email protected]ea161da2010-11-02 21:57:35592 const int kDefaultWidth = 497;
593 const int kDefaultHeight = 332;
[email protected]05acb55472011-02-03 00:11:07594 string16 job_title = print_job_title;
[email protected]e39027a2011-01-24 21:41:54595 Profile* profile = NULL;
[email protected]05acb55472011-02-03 00:11:07596 if (modal) {
[email protected]6085c70d2011-03-22 22:51:07597 DCHECK(browser);
598 if (job_title.empty() && browser->GetSelectedTabContents())
599 job_title = browser->GetSelectedTabContents()->GetTitle();
600 profile = browser->GetProfile();
[email protected]e39027a2011-01-24 21:41:54601 } else {
[email protected]0744cc72011-08-12 12:05:45602 std::vector<Profile*> loaded_profiles =
603 g_browser_process->profile_manager()->GetLoadedProfiles();
604 DCHECK_GT(loaded_profiles.size(), 0U);
605 profile = loaded_profiles[0];
[email protected]e39027a2011-01-24 21:41:54606 }
607 DCHECK(profile);
[email protected]05acb55472011-02-03 00:11:07608 PrefService* pref_service = profile->GetPrefs();
[email protected]ea161da2010-11-02 21:57:35609 DCHECK(pref_service);
610 if (!pref_service->FindPreference(prefs::kCloudPrintDialogWidth)) {
611 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogWidth,
[email protected]d36f941b2011-05-09 06:19:16612 kDefaultWidth,
613 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35614 }
615 if (!pref_service->FindPreference(prefs::kCloudPrintDialogHeight)) {
616 pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogHeight,
[email protected]d36f941b2011-05-09 06:19:16617 kDefaultHeight,
618 PrefService::UNSYNCABLE_PREF);
[email protected]ea161da2010-11-02 21:57:35619 }
620
621 int width = pref_service->GetInteger(prefs::kCloudPrintDialogWidth);
622 int height = pref_service->GetInteger(prefs::kCloudPrintDialogHeight);
[email protected]e39027a2011-01-24 21:41:54623
[email protected]73852b8f2010-05-14 00:38:12624 HtmlDialogUIDelegate* dialog_delegate =
625 new internal_cloud_print_helpers::CloudPrintHtmlDialogDelegate(
[email protected]e8368e92011-08-20 04:05:56626 path_to_file, width, height, std::string(), job_title, print_ticket,
[email protected]d955fc92011-09-19 20:49:03627 file_type, modal, delete_on_close);
[email protected]05acb55472011-02-03 00:11:07628 if (modal) {
[email protected]6085c70d2011-03-22 22:51:07629 DCHECK(browser);
630 browser->BrowserShowHtmlDialog(dialog_delegate, NULL);
[email protected]e39027a2011-01-24 21:41:54631 } else {
[email protected]eb2d7902011-02-02 18:19:56632 browser::ShowHtmlDialog(NULL, profile, dialog_delegate);
[email protected]e39027a2011-01-24 21:41:54633 }
[email protected]73852b8f2010-05-14 00:38:12634}
[email protected]6085c70d2011-03-22 22:51:07635
[email protected]6ddda232011-04-22 15:41:47636// Provides a runnable function to delete a file.
637void Delete(const FilePath& file_path) {
638 file_util::Delete(file_path, false);
639}
640
[email protected]6085c70d2011-03-22 22:51:07641} // namespace internal_cloud_print_helpers
642
643namespace print_dialog_cloud {
644
645// Called on the FILE or UI thread. This is the main entry point into creating
646// the dialog.
647
648// TODO(scottbyer): The signature here will need to change as the
649// workflow through the printing code changes to allow for dynamically
650// changing page setup parameters while the dialog is active.
651void CreatePrintDialogForFile(const FilePath& path_to_file,
652 const string16& print_job_title,
[email protected]e8368e92011-08-20 04:05:56653 const string16& print_ticket,
[email protected]6085c70d2011-03-22 22:51:07654 const std::string& file_type,
[email protected]d955fc92011-09-19 20:49:03655 bool modal,
656 bool delete_on_close) {
[email protected]6085c70d2011-03-22 22:51:07657 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE) ||
658 BrowserThread::CurrentlyOn(BrowserThread::UI));
659
660 BrowserThread::PostTask(
661 BrowserThread::UI, FROM_HERE,
662 NewRunnableFunction(&internal_cloud_print_helpers::CreateDialogImpl,
663 path_to_file,
664 print_job_title,
[email protected]e8368e92011-08-20 04:05:56665 print_ticket,
[email protected]6085c70d2011-03-22 22:51:07666 file_type,
[email protected]d955fc92011-09-19 20:49:03667 modal,
668 delete_on_close));
669}
670
671void CreatePrintDialogForBytes(scoped_refptr<RefCountedBytes> data,
672 const string16& print_job_title,
673 const string16& print_ticket,
674 const std::string& file_type,
675 bool modal) {
676 // TODO([email protected]) Avoid cloning the PDF data. Make use of a
677 // shared memory object instead.
678 // http://code.google.com/p/chromium/issues/detail?id=44093
679 scoped_refptr<RefCountedBytes> cloned_data(new RefCountedBytes(data->data()));
680 BrowserThread::PostTask(
681 BrowserThread::FILE, FROM_HERE,
682 NewRunnableFunction(
683 &internal_cloud_print_helpers::CreatePrintDialogForBytesImpl,
684 cloned_data,
685 print_job_title,
686 print_ticket,
687 file_type,
688 modal));
[email protected]6085c70d2011-03-22 22:51:07689}
690
[email protected]65c9d89a2011-04-13 21:02:39691bool CreatePrintDialogFromCommandLine(const CommandLine& command_line) {
692 if (!command_line.GetSwitchValuePath(switches::kCloudPrintFile).empty()) {
693 FilePath cloud_print_file;
694 cloud_print_file =
695 command_line.GetSwitchValuePath(switches::kCloudPrintFile);
696 if (!cloud_print_file.empty()) {
697 string16 print_job_title;
[email protected]e8368e92011-08-20 04:05:56698 string16 print_job_print_ticket;
[email protected]65c9d89a2011-04-13 21:02:39699 if (command_line.HasSwitch(switches::kCloudPrintJobTitle)) {
[email protected]e8368e92011-08-20 04:05:56700 print_job_title =
701 internal_cloud_print_helpers::GetSwitchValueString16(
702 command_line, switches::kCloudPrintJobTitle);
703 }
704 if (command_line.HasSwitch(switches::kCloudPrintPrintTicket)) {
705 print_job_print_ticket =
706 internal_cloud_print_helpers::GetSwitchValueString16(
707 command_line, switches::kCloudPrintPrintTicket);
[email protected]65c9d89a2011-04-13 21:02:39708 }
709 std::string file_type = "application/pdf";
710 if (command_line.HasSwitch(switches::kCloudPrintFileType)) {
711 file_type = command_line.GetSwitchValueASCII(
712 switches::kCloudPrintFileType);
713 }
[email protected]e8368e92011-08-20 04:05:56714
[email protected]d955fc92011-09-19 20:49:03715 bool delete_on_close = CommandLine::ForCurrentProcess()->HasSwitch(
716 switches::kCloudPrintDeleteFile);
717
[email protected]65c9d89a2011-04-13 21:02:39718 print_dialog_cloud::CreatePrintDialogForFile(cloud_print_file,
719 print_job_title,
[email protected]e8368e92011-08-20 04:05:56720 print_job_print_ticket,
[email protected]65c9d89a2011-04-13 21:02:39721 file_type,
[email protected]d955fc92011-09-19 20:49:03722 false,
723 delete_on_close);
[email protected]65c9d89a2011-04-13 21:02:39724 return true;
725 }
726 }
727 return false;
728}
729
[email protected]6085c70d2011-03-22 22:51:07730} // end namespace