blob: a325994a3960fb399abfa74c61eff4477c050f23 [file] [log] [blame]
[email protected]73852b8f2010-05-14 00:38:121// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// 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
8#include "app/l10n_util.h"
9#include "base/base64.h"
[email protected]4baf1c42010-05-18 18:45:2510#include "base/command_line.h"
[email protected]73852b8f2010-05-14 00:38:1211#include "base/file_util.h"
12#include "base/json/json_reader.h"
13#include "base/logging.h"
14#include "base/values.h"
15#include "chrome/browser/browser_list.h"
16#include "chrome/browser/chrome_thread.h"
[email protected]37858e52010-08-26 00:22:0217#include "chrome/browser/debugger/devtools_manager.h"
[email protected]73852b8f2010-05-14 00:38:1218#include "chrome/browser/dom_ui/dom_ui.h"
19#include "chrome/browser/dom_ui/dom_ui_util.h"
20#include "chrome/browser/dom_ui/html_dialog_ui.h"
[email protected]37858e52010-08-26 00:22:0221#include "chrome/browser/prefs/pref_service.h"
[email protected]4baf1c42010-05-18 18:45:2522#include "chrome/browser/profile.h"
[email protected]73852b8f2010-05-14 00:38:1223#include "chrome/browser/renderer_host/render_view_host.h"
[email protected]37858e52010-08-26 00:22:0224#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]4baf1c42010-05-18 18:45:2525#include "chrome/common/chrome_switches.h"
[email protected]73852b8f2010-05-14 00:38:1226#include "chrome/common/notification_observer.h"
27#include "chrome/common/notification_registrar.h"
28#include "chrome/common/notification_source.h"
[email protected]939856a2010-08-24 20:29:0229#include "chrome/common/notification_type.h"
[email protected]37858e52010-08-26 00:22:0230#include "chrome/common/pref_names.h"
[email protected]939856a2010-08-24 20:29:0231#include "chrome/common/render_messages_params.h"
[email protected]73852b8f2010-05-14 00:38:1232#include "chrome/common/url_constants.h"
[email protected]939856a2010-08-24 20:29:0233#include "webkit/glue/webpreferences.h"
[email protected]73852b8f2010-05-14 00:38:1234
35#include "grit/generated_resources.h"
36
37// This module implements the UI support in Chrome for cloud printing.
38// This means hosting a dialog containing HTML/JavaScript and using
39// the published cloud print user interface integration APIs to get
40// page setup settings from the dialog contents and provide the
41// generated print PDF to the dialog contents for uploading to the
42// cloud print service.
43
44// Currently, the flow between these classes is as follows:
45
46// PrintDialogCloud::CreatePrintDialogForPdf is called from
47// resource_message_filter_gtk.cc once the renderer has informed the
48// renderer host that PDF generation into the renderer host provided
49// temp file has been completed. That call is on the IO thread.
50// That, in turn, hops over to the UI thread to create an instance of
51// PrintDialogCloud.
52
53// The constructor for PrintDialogCloud creates a
54// CloudPrintHtmlDialogDelegate and asks the current active browser to
55// show an HTML dialog using that class as the delegate. That class
56// hands in the kCloudPrintResourcesURL as the URL to visit. That is
57// recognized by the GetDOMUIFactoryFunction as a signal to create an
58// ExternalHtmlDialogUI.
59
60// CloudPrintHtmlDialogDelegate also temporarily owns a
61// CloudPrintFlowHandler, a class which is responsible for the actual
62// interactions with the dialog contents, including handing in the PDF
63// print data and getting any page setup parameters that the dialog
64// contents provides. As part of bringing up the dialog,
65// HtmlDialogUI::RenderViewCreated is called (an override of
66// DOMUI::RenderViewCreated). That routine, in turn, calls the
67// delegate's GetDOMMessageHandlers routine, at which point the
68// ownership of the CloudPrintFlowHandler is handed over. A pointer
69// to the flow handler is kept to facilitate communication back and
70// forth between the two classes.
71
72// The DOMUI continues dialog bring-up, calling
73// CloudPrintFlowHandler::RegisterMessages. This is where the
74// additional object model capabilities are registered for the dialog
75// contents to use. It is also at this time that capabilities for the
76// dialog contents are adjusted to allow the dialog contents to close
77// the window. In addition, the pending URL is redirected to the
78// actual cloud print service URL. The flow controller also registers
79// for notification of when the dialog contents finish loading, which
80// is currently used to send the PDF data to the dialog contents.
81
82// In order to send the PDF data to the dialog contents, the flow
83// handler uses a CloudPrintDataSender. It creates one, letting it
84// know the name of the temporary file containing the PDF data, and
85// posts the task of reading the file
86// (CloudPrintDataSender::ReadPrintDataFile) to the file thread. That
87// routine reads in the file, and then hops over to the IO thread to
88// send that data to the dialog contents.
89
90// When the dialog contents are finished (by either being cancelled or
91// hitting the print button), the delegate is notified, and responds
92// that the dialog should be closed, at which point things are torn
93// down and released.
94
95// TODO(scottbyer):
96// http://code.google.com/p/chromium/issues/detail?id=44093 The
97// high-level flow (where the PDF data is generated before even
98// bringing up the dialog) isn't what we want.
99
100
101namespace internal_cloud_print_helpers {
102
[email protected]20ce516d2010-06-18 02:20:04103const char kDefaultCloudPrintServiceURL[] = "https://www.google.com/cloudprint";
104
[email protected]4baf1c42010-05-18 18:45:25105void CloudPrintService::RegisterPreferences() {
106 DCHECK(profile_);
107 PrefService* pref_service = profile_->GetPrefs();
108 if (pref_service->FindPreference(prefs::kCloudPrintServiceURL))
109 return;
[email protected]4baf1c42010-05-18 18:45:25110 pref_service->RegisterStringPref(prefs::kCloudPrintServiceURL,
111 kDefaultCloudPrintServiceURL);
112}
113
114// Returns the root service URL for the cloud print service. The
115// default is to point at the Google Cloud Print service. This can be
116// overridden by the command line or by the user preferences.
117GURL CloudPrintService::GetCloudPrintServiceURL() {
118 DCHECK(profile_);
119 RegisterPreferences();
120
121 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
122 GURL cloud_print_service_url = GURL(command_line.GetSwitchValueASCII(
123 switches::kCloudPrintServiceURL));
124 if (cloud_print_service_url.is_empty()) {
[email protected]ddd231e2010-06-29 20:35:19125 cloud_print_service_url = GURL(
126 profile_->GetPrefs()->GetString(prefs::kCloudPrintServiceURL));
[email protected]4baf1c42010-05-18 18:45:25127 }
128 return cloud_print_service_url;
129}
130
131GURL CloudPrintService::GetCloudPrintServiceDialogURL() {
132 GURL cloud_print_service_url = GetCloudPrintServiceURL();
133 std::string path(cloud_print_service_url.path() + "/client/dialog.html");
134 GURL::Replacements replacements;
135 replacements.SetPathStr(path);
136 GURL cloud_print_dialog_url = cloud_print_service_url.ReplaceComponents(
137 replacements);
138 return cloud_print_dialog_url;
139}
[email protected]73852b8f2010-05-14 00:38:12140
141bool GetRealOrInt(const DictionaryValue& dictionary,
[email protected]a65175d2010-08-17 04:00:57142 const std::string& path,
[email protected]73852b8f2010-05-14 00:38:12143 double* out_value) {
144 if (!dictionary.GetReal(path, out_value)) {
145 int int_value = 0;
146 if (!dictionary.GetInteger(path, &int_value))
147 return false;
148 *out_value = int_value;
149 }
150 return true;
151}
152
153// From the JSON parsed value, get the entries for the page setup
154// parameters.
155bool GetPageSetupParameters(const std::string& json,
156 ViewMsg_Print_Params& parameters) {
157 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
158 DLOG_IF(ERROR, (!parsed_value.get() ||
159 !parsed_value->IsType(Value::TYPE_DICTIONARY)))
160 << "PageSetup call didn't have expected contents";
161 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
162 return false;
163
164 bool result = true;
165 DictionaryValue* params = static_cast<DictionaryValue*>(parsed_value.get());
[email protected]a65175d2010-08-17 04:00:57166 result &= GetRealOrInt(*params, "dpi", &parameters.dpi);
167 result &= GetRealOrInt(*params, "min_shrink", &parameters.min_shrink);
168 result &= GetRealOrInt(*params, "max_shrink", &parameters.max_shrink);
169 result &= params->GetBoolean("selection_only", &parameters.selection_only);
[email protected]73852b8f2010-05-14 00:38:12170 return result;
171}
172
173void CloudPrintDataSenderHelper::CallJavascriptFunction(
174 const std::wstring& function_name) {
175 dom_ui_->CallJavascriptFunction(function_name);
176}
177
178void CloudPrintDataSenderHelper::CallJavascriptFunction(
179 const std::wstring& function_name, const Value& arg) {
180 dom_ui_->CallJavascriptFunction(function_name, arg);
181}
182
183void CloudPrintDataSenderHelper::CallJavascriptFunction(
184 const std::wstring& function_name, const Value& arg1, const Value& arg2) {
185 dom_ui_->CallJavascriptFunction(function_name, arg1, arg2);
186}
187
188// Clears out the pointer we're using to communicate. Either routine is
189// potentially expensive enough that stopping whatever is in progress
190// is worth it.
191void CloudPrintDataSender::CancelPrintDataFile() {
192 AutoLock lock(lock_);
193 // We don't own helper, it was passed in to us, so no need to
194 // delete, just let it go.
195 helper_ = NULL;
196}
197
198// Grab the raw PDF file contents and massage them into shape for
199// sending to the dialog contents (and up to the cloud print server)
200// by encoding it and prefixing it with the appropriate mime type.
201// Once that is done, kick off the next part of the task on the IO
202// thread.
203void CloudPrintDataSender::ReadPrintDataFile(const FilePath& path_to_pdf) {
204 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
205 int64 file_size = 0;
206 if (file_util::GetFileSize(path_to_pdf, &file_size) && file_size != 0) {
207 std::string file_data;
208 if (file_size < kuint32max) {
209 file_data.reserve(static_cast<unsigned int>(file_size));
210 } else {
211 DLOG(WARNING) << " print data file too large to reserve space";
212 }
213 if (helper_ && file_util::ReadFileToString(path_to_pdf, &file_data)) {
214 std::string base64_data;
215 base::Base64Encode(file_data, &base64_data);
216 std::string header("data:application/pdf;base64,");
217 base64_data.insert(0, header);
218 scoped_ptr<StringValue> new_data(new StringValue(base64_data));
219 print_data_.swap(new_data);
220 ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
221 NewRunnableMethod(
222 this,
223 &CloudPrintDataSender::SendPrintDataFile));
224 }
225 }
226}
227
228// We have the data in hand that needs to be pushed into the dialog
229// contents; do so from the IO thread.
230
231// TODO(scottbyer): If the print data ends up being larger than the
232// upload limit (currently 10MB), what we need to do is upload that
233// large data to google docs and set the URL in the printing
234// JavaScript to that location, and make sure it gets deleted when not
235// needed. - 4/1/2010
236void CloudPrintDataSender::SendPrintDataFile() {
237 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
238 AutoLock lock(lock_);
239 if (helper_ && print_data_.get()) {
[email protected]9848c7e2010-06-03 16:06:56240 StringValue title(print_job_title_);
[email protected]73852b8f2010-05-14 00:38:12241
242 // Send the print data to the dialog contents. The JavaScript
243 // function is a preliminary API for prototyping purposes and is
244 // subject to change.
245 const_cast<CloudPrintDataSenderHelper*>(helper_)->CallJavascriptFunction(
246 L"printApp._printDataUrl", *print_data_, title);
247 }
248}
249
250
251void CloudPrintFlowHandler::SetDialogDelegate(
252 CloudPrintHtmlDialogDelegate* delegate) {
253 // Even if setting a new dom_ui, it means any previous task needs
254 // to be cancelled, it's now invalid.
255 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
256 CancelAnyRunningTask();
257 dialog_delegate_ = delegate;
258}
259
260// Cancels any print data sender we have in flight and removes our
261// reference to it, so when the task that is calling it finishes and
262// removes it's reference, it goes away.
263void CloudPrintFlowHandler::CancelAnyRunningTask() {
264 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
265 if (print_data_sender_.get()) {
266 print_data_sender_->CancelPrintDataFile();
267 print_data_sender_ = NULL;
268 }
269}
270
271
272void CloudPrintFlowHandler::RegisterMessages() {
273 if (!dom_ui_)
274 return;
275
276 // TODO(scottbyer) - This is where we will register messages for the
277 // UI JS to use. Needed: Call to update page setup parameters.
278 dom_ui_->RegisterMessageCallback(
279 "ShowDebugger",
280 NewCallback(this, &CloudPrintFlowHandler::HandleShowDebugger));
281 dom_ui_->RegisterMessageCallback(
282 "SendPrintData",
283 NewCallback(this, &CloudPrintFlowHandler::HandleSendPrintData));
284 dom_ui_->RegisterMessageCallback(
285 "SetPageParameters",
286 NewCallback(this, &CloudPrintFlowHandler::HandleSetPageParameters));
287
288 if (dom_ui_->tab_contents()) {
289 // Also, take the opportunity to set some (minimal) additional
290 // script permissions required for the web UI.
291
292 // TODO(scottbyer): learn how to make sure we're talking to the
293 // right web site first.
294 RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host();
295 if (rvh && rvh->delegate()) {
296 WebPreferences webkit_prefs = rvh->delegate()->GetWebkitPrefs();
297 webkit_prefs.allow_scripts_to_close_windows = true;
298 rvh->UpdateWebPreferences(webkit_prefs);
299 }
300
301 // 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.
304 NavigationController* controller = &dom_ui_->tab_contents()->controller();
305 NavigationEntry* pending_entry = controller->pending_entry();
306 if (pending_entry)
[email protected]4baf1c42010-05-18 18:45:25307 pending_entry->set_url(CloudPrintService(
308 dom_ui_->GetProfile()).GetCloudPrintServiceDialogURL());
[email protected]73852b8f2010-05-14 00:38:12309 registrar_.Add(this, NotificationType::LOAD_STOP,
310 Source<NavigationController>(controller));
311 }
312}
313
314void CloudPrintFlowHandler::Observe(NotificationType type,
315 const NotificationSource& source,
316 const NotificationDetails& details) {
317 if (type == NotificationType::LOAD_STOP) {
318 // Choose one or the other. If you need to debug, bring up the
319 // debugger. You can then use the various chrome.send()
320 // registrations above to kick of the various function calls,
321 // including chrome.send("SendPrintData") in the javaScript
322 // console and watch things happen with:
323 // HandleShowDebugger(NULL);
324 HandleSendPrintData(NULL);
325 }
326}
327
[email protected]88942a22010-08-19 20:34:43328void CloudPrintFlowHandler::HandleShowDebugger(const ListValue* args) {
[email protected]73852b8f2010-05-14 00:38:12329 ShowDebugger();
330}
331
332void CloudPrintFlowHandler::ShowDebugger() {
333 if (dom_ui_) {
334 RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host();
335 if (rvh)
336 DevToolsManager::GetInstance()->OpenDevToolsWindow(rvh);
337 }
338}
339
340scoped_refptr<CloudPrintDataSender>
341CloudPrintFlowHandler::CreateCloudPrintDataSender() {
342 DCHECK(dom_ui_);
343 print_data_helper_.reset(new CloudPrintDataSenderHelper(dom_ui_));
[email protected]9848c7e2010-06-03 16:06:56344 return new CloudPrintDataSender(print_data_helper_.get(), print_job_title_);
[email protected]73852b8f2010-05-14 00:38:12345}
346
[email protected]88942a22010-08-19 20:34:43347void CloudPrintFlowHandler::HandleSendPrintData(const ListValue* args) {
[email protected]73852b8f2010-05-14 00:38:12348 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
349 // This will cancel any ReadPrintDataFile() or SendPrintDataFile()
350 // requests in flight (this is anticipation of when setting page
351 // setup parameters becomes asynchronous and may be set while some
352 // data is in flight). Then we can clear out the print data.
353 CancelAnyRunningTask();
354 if (dom_ui_) {
355 print_data_sender_ = CreateCloudPrintDataSender();
356 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
357 NewRunnableMethod(
358 print_data_sender_.get(),
359 &CloudPrintDataSender::ReadPrintDataFile,
360 path_to_pdf_));
361 }
362}
363
[email protected]88942a22010-08-19 20:34:43364void CloudPrintFlowHandler::HandleSetPageParameters(const ListValue* args) {
365 std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(args));
[email protected]73852b8f2010-05-14 00:38:12366 if (json.empty())
367 return;
368
369 // These are backstop default values - 72 dpi to match the screen,
370 // 8.5x11 inch paper with margins subtracted (1/4 inch top, left,
371 // right and 0.56 bottom), and the min page shrink and max page
372 // shrink values appear all over the place with no explanation.
373
374 // TODO(scottbyer): Get a Linux/ChromeOS edge for PrintSettings
375 // working so that we can get the default values from there. Fix up
376 // PrintWebViewHelper to do the same.
377 const int kDPI = 72;
378 const int kWidth = static_cast<int>((8.5-0.25-0.25)*kDPI);
379 const int kHeight = static_cast<int>((11-0.25-0.56)*kDPI);
380 const double kMinPageShrink = 1.25;
381 const double kMaxPageShrink = 2.0;
382
383 ViewMsg_Print_Params default_settings;
384 default_settings.printable_size = gfx::Size(kWidth, kHeight);
385 default_settings.dpi = kDPI;
386 default_settings.min_shrink = kMinPageShrink;
387 default_settings.max_shrink = kMaxPageShrink;
388 default_settings.desired_dpi = kDPI;
389 default_settings.document_cookie = 0;
390 default_settings.selection_only = false;
391
392 if (!GetPageSetupParameters(json, default_settings)) {
393 NOTREACHED();
394 return;
395 }
396
397 // TODO(scottbyer) - Here is where we would kick the originating
398 // renderer thread with these new parameters in order to get it to
399 // re-generate the PDF and hand it back to us. window.print() is
400 // currently synchronous, so there's a lot of work to do to get to
401 // that point.
402}
403
404CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
405 const FilePath& path_to_pdf,
406 int width, int height,
[email protected]9848c7e2010-06-03 16:06:56407 const std::string& json_arguments,
408 const string16& print_job_title)
409 : flow_handler_(new CloudPrintFlowHandler(path_to_pdf, print_job_title)),
[email protected]73852b8f2010-05-14 00:38:12410 owns_flow_handler_(true) {
411 Init(width, height, json_arguments);
412}
413
414CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
415 CloudPrintFlowHandler* flow_handler,
416 int width, int height,
417 const std::string& json_arguments)
418 : flow_handler_(flow_handler),
[email protected]18137e02010-05-25 21:10:35419 owns_flow_handler_(true) {
[email protected]73852b8f2010-05-14 00:38:12420 Init(width, height, json_arguments);
421}
422
423void CloudPrintHtmlDialogDelegate::Init(
[email protected]9848c7e2010-06-03 16:06:56424 int width, int height, const std::string& json_arguments) {
[email protected]73852b8f2010-05-14 00:38:12425 // This information is needed to show the dialog HTML content.
426 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
427 std::string cloud_print_url(chrome::kCloudPrintResourcesURL);
428 params_.url = GURL(cloud_print_url);
429 params_.height = height;
430 params_.width = width;
431 params_.json_input = json_arguments;
432
433 flow_handler_->SetDialogDelegate(this);
434}
435
436CloudPrintHtmlDialogDelegate::~CloudPrintHtmlDialogDelegate() {
437 // If the flow_handler_ is about to outlive us because we don't own
438 // it anymore, we need to have it remove it's reference to us.
439 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
440 flow_handler_->SetDialogDelegate(NULL);
441 if (owns_flow_handler_) {
442 delete flow_handler_;
443 }
444}
445
446bool CloudPrintHtmlDialogDelegate::IsDialogModal() const {
447 return true;
448}
449
450std::wstring CloudPrintHtmlDialogDelegate::GetDialogTitle() const {
451 return l10n_util::GetString(IDS_CLOUD_PRINT_TITLE);
452}
453
454GURL CloudPrintHtmlDialogDelegate::GetDialogContentURL() const {
455 return params_.url;
456}
457
458void CloudPrintHtmlDialogDelegate::GetDOMMessageHandlers(
459 std::vector<DOMMessageHandler*>* handlers) const {
460 handlers->push_back(flow_handler_);
461 // We don't own flow_handler_ anymore, but it sticks around until at
462 // least right after OnDialogClosed() is called (and this object is
463 // destroyed).
464 owns_flow_handler_ = false;
465}
466
467void CloudPrintHtmlDialogDelegate::GetDialogSize(gfx::Size* size) const {
468 size->set_width(params_.width);
469 size->set_height(params_.height);
470}
471
472std::string CloudPrintHtmlDialogDelegate::GetDialogArgs() const {
473 return params_.json_input;
474}
475
476void CloudPrintHtmlDialogDelegate::OnDialogClosed(
477 const std::string& json_retval) {
478 delete this;
479}
480
[email protected]18137e02010-05-25 21:10:35481void CloudPrintHtmlDialogDelegate::OnCloseContents(TabContents* source,
482 bool* out_close_dialog) {
483 if (out_close_dialog)
484 *out_close_dialog = true;
485}
486
[email protected]73852b8f2010-05-14 00:38:12487} // end of namespace internal_cloud_print_helpers
488
489// static, called on the IO thread. This is the main entry point into
490// creating the dialog.
491
492// TODO(scottbyer): The signature here will need to change as the
493// workflow through the printing code changes to allow for dynamically
494// changing page setup parameters while the dialog is active.
495void PrintDialogCloud::CreatePrintDialogForPdf(const FilePath& path_to_pdf) {
496 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
497
498 ChromeThread::PostTask(
499 ChromeThread::UI, FROM_HERE,
500 NewRunnableFunction(&PrintDialogCloud::CreateDialogImpl, path_to_pdf));
501}
502
503// static, called from the UI thread.
504void PrintDialogCloud::CreateDialogImpl(const FilePath& path_to_pdf) {
505 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
506 new PrintDialogCloud(path_to_pdf);
507}
508
509// Initialize the print dialog. Called on the UI thread.
510PrintDialogCloud::PrintDialogCloud(const FilePath& path_to_pdf)
511 : browser_(BrowserList::GetLastActive()) {
512
513 // TODO(scottbyer): Verify GAIA login valid, execute GAIA login if not (should
514 // be distilled out of bookmark sync.)
[email protected]9848c7e2010-06-03 16:06:56515 string16 print_job_title;
516 if (browser_ && browser_->GetSelectedTabContents())
517 print_job_title = browser_->GetSelectedTabContents()->GetTitle();
[email protected]73852b8f2010-05-14 00:38:12518
519 // TODO(scottbyer): Get the dialog width, height from the dialog
520 // contents, and take the screen size into account.
521 HtmlDialogUIDelegate* dialog_delegate =
522 new internal_cloud_print_helpers::CloudPrintHtmlDialogDelegate(
[email protected]9848c7e2010-06-03 16:06:56523 path_to_pdf, 500, 400, std::string(), print_job_title);
[email protected]73852b8f2010-05-14 00:38:12524 browser_->BrowserShowHtmlDialog(dialog_delegate, NULL);
525}
526
527PrintDialogCloud::~PrintDialogCloud() {
528}