Home | History | Annotate | Download | only in printing
      1 // Copyright (c) 2011 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 "base/base64.h"
      9 #include "base/command_line.h"
     10 #include "base/file_util.h"
     11 #include "base/json/json_reader.h"
     12 #include "base/values.h"
     13 #include "chrome/browser/debugger/devtools_manager.h"
     14 #include "chrome/browser/prefs/pref_service.h"
     15 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/profiles/profile_manager.h"
     18 #include "chrome/browser/ui/browser_dialogs.h"
     19 #include "chrome/browser/ui/browser_list.h"
     20 #include "chrome/common/chrome_switches.h"
     21 #include "chrome/common/pref_names.h"
     22 #include "chrome/common/print_messages.h"
     23 #include "chrome/common/url_constants.h"
     24 #include "content/browser/browser_thread.h"
     25 #include "content/browser/renderer_host/render_view_host.h"
     26 #include "content/browser/tab_contents/tab_contents.h"
     27 #include "content/browser/tab_contents/tab_contents_view.h"
     28 #include "content/browser/webui/web_ui.h"
     29 #include "content/common/notification_registrar.h"
     30 #include "content/common/notification_source.h"
     31 #include "content/common/notification_type.h"
     32 #include "ui/base/l10n/l10n_util.h"
     33 #include "webkit/glue/webpreferences.h"
     34 
     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 data 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::CreatePrintDialogForFile is called from
     47 // resource_message_filter_gtk.cc once the renderer has informed the
     48 // renderer host that print data generation into the renderer host provided
     49 // temp file has been completed.  That call is on the FILE 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 GetWebUIFactoryFunction 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
     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 // WebUI::RenderViewCreated).  That routine, in turn, calls the
     67 // delegate's GetWebUIMessageHandlers 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 WebUI 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 data to the dialog contents.
     81 
     82 // In order to send the 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 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 data is generated before even
     98 // bringing up the dialog) isn't what we want.
     99 
    100 namespace internal_cloud_print_helpers {
    101 
    102 bool GetDoubleOrInt(const DictionaryValue& dictionary,
    103                     const std::string& path,
    104                     double* out_value) {
    105   if (!dictionary.GetDouble(path, out_value)) {
    106     int int_value = 0;
    107     if (!dictionary.GetInteger(path, &int_value))
    108       return false;
    109     *out_value = int_value;
    110   }
    111   return true;
    112 }
    113 
    114 // From the JSON parsed value, get the entries for the page setup
    115 // parameters.
    116 bool GetPageSetupParameters(const std::string& json,
    117                             PrintMsg_Print_Params& parameters) {
    118   scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
    119   DLOG_IF(ERROR, (!parsed_value.get() ||
    120                   !parsed_value->IsType(Value::TYPE_DICTIONARY)))
    121       << "PageSetup call didn't have expected contents";
    122   if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
    123     return false;
    124 
    125   bool result = true;
    126   DictionaryValue* params = static_cast<DictionaryValue*>(parsed_value.get());
    127   result &= GetDoubleOrInt(*params, "dpi", &parameters.dpi);
    128   result &= GetDoubleOrInt(*params, "min_shrink", &parameters.min_shrink);
    129   result &= GetDoubleOrInt(*params, "max_shrink", &parameters.max_shrink);
    130   result &= params->GetBoolean("selection_only", &parameters.selection_only);
    131   return result;
    132 }
    133 
    134 void CloudPrintDataSenderHelper::CallJavascriptFunction(
    135     const std::wstring& function_name) {
    136   web_ui_->CallJavascriptFunction(WideToASCII(function_name));
    137 }
    138 
    139 void CloudPrintDataSenderHelper::CallJavascriptFunction(
    140     const std::wstring& function_name, const Value& arg) {
    141   web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg);
    142 }
    143 
    144 void CloudPrintDataSenderHelper::CallJavascriptFunction(
    145     const std::wstring& function_name, const Value& arg1, const Value& arg2) {
    146   web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2);
    147 }
    148 
    149 // Clears out the pointer we're using to communicate.  Either routine is
    150 // potentially expensive enough that stopping whatever is in progress
    151 // is worth it.
    152 void CloudPrintDataSender::CancelPrintDataFile() {
    153   base::AutoLock lock(lock_);
    154   // We don't own helper, it was passed in to us, so no need to
    155   // delete, just let it go.
    156   helper_ = NULL;
    157 }
    158 
    159 CloudPrintDataSender::CloudPrintDataSender(CloudPrintDataSenderHelper* helper,
    160                                            const string16& print_job_title,
    161                                            const std::string& file_type)
    162     : helper_(helper),
    163       print_job_title_(print_job_title),
    164       file_type_(file_type) {
    165 }
    166 
    167 CloudPrintDataSender::~CloudPrintDataSender() {}
    168 
    169 // Grab the raw file contents and massage them into shape for
    170 // sending to the dialog contents (and up to the cloud print server)
    171 // by encoding it and prefixing it with the appropriate mime type.
    172 // Once that is done, kick off the next part of the task on the IO
    173 // thread.
    174 void CloudPrintDataSender::ReadPrintDataFile(const FilePath& path_to_file) {
    175   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    176   int64 file_size = 0;
    177   if (file_util::GetFileSize(path_to_file, &file_size) && file_size != 0) {
    178     std::string file_data;
    179     if (file_size < kuint32max) {
    180       file_data.reserve(static_cast<unsigned int>(file_size));
    181     } else {
    182       DLOG(WARNING) << " print data file too large to reserve space";
    183     }
    184     if (helper_ && file_util::ReadFileToString(path_to_file, &file_data)) {
    185       std::string base64_data;
    186       base::Base64Encode(file_data, &base64_data);
    187       std::string header("data:");
    188       header.append(file_type_);
    189       header.append(";base64,");
    190       base64_data.insert(0, header);
    191       scoped_ptr<StringValue> new_data(new StringValue(base64_data));
    192       print_data_.swap(new_data);
    193       BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    194                               NewRunnableMethod(
    195                                   this,
    196                                   &CloudPrintDataSender::SendPrintDataFile));
    197     }
    198   }
    199 }
    200 
    201 // We have the data in hand that needs to be pushed into the dialog
    202 // contents; do so from the IO thread.
    203 
    204 // TODO(scottbyer): If the print data ends up being larger than the
    205 // upload limit (currently 10MB), what we need to do is upload that
    206 // large data to google docs and set the URL in the printing
    207 // JavaScript to that location, and make sure it gets deleted when not
    208 // needed. - 4/1/2010
    209 void CloudPrintDataSender::SendPrintDataFile() {
    210   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    211   base::AutoLock lock(lock_);
    212   if (helper_ && print_data_.get()) {
    213     StringValue title(print_job_title_);
    214 
    215     // Send the print data to the dialog contents.  The JavaScript
    216     // function is a preliminary API for prototyping purposes and is
    217     // subject to change.
    218     const_cast<CloudPrintDataSenderHelper*>(helper_)->CallJavascriptFunction(
    219         L"printApp._printDataUrl", *print_data_, title);
    220   }
    221 }
    222 
    223 
    224 CloudPrintFlowHandler::CloudPrintFlowHandler(const FilePath& path_to_file,
    225                                              const string16& print_job_title,
    226                                              const std::string& file_type)
    227     : path_to_file_(path_to_file),
    228       print_job_title_(print_job_title),
    229       file_type_(file_type) {
    230 }
    231 
    232 CloudPrintFlowHandler::~CloudPrintFlowHandler() {
    233   // This will also cancel any task in flight.
    234   CancelAnyRunningTask();
    235 }
    236 
    237 
    238 void CloudPrintFlowHandler::SetDialogDelegate(
    239     CloudPrintHtmlDialogDelegate* delegate) {
    240   // Even if setting a new WebUI, it means any previous task needs
    241   // to be cancelled, it's now invalid.
    242   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    243   CancelAnyRunningTask();
    244   dialog_delegate_ = delegate;
    245 }
    246 
    247 // Cancels any print data sender we have in flight and removes our
    248 // reference to it, so when the task that is calling it finishes and
    249 // removes it's reference, it goes away.
    250 void CloudPrintFlowHandler::CancelAnyRunningTask() {
    251   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    252   if (print_data_sender_.get()) {
    253     print_data_sender_->CancelPrintDataFile();
    254     print_data_sender_ = NULL;
    255   }
    256 }
    257 
    258 void CloudPrintFlowHandler::RegisterMessages() {
    259   if (!web_ui_)
    260     return;
    261 
    262   // TODO(scottbyer) - This is where we will register messages for the
    263   // UI JS to use.  Needed: Call to update page setup parameters.
    264   web_ui_->RegisterMessageCallback(
    265       "ShowDebugger",
    266       NewCallback(this, &CloudPrintFlowHandler::HandleShowDebugger));
    267   web_ui_->RegisterMessageCallback(
    268       "SendPrintData",
    269       NewCallback(this, &CloudPrintFlowHandler::HandleSendPrintData));
    270   web_ui_->RegisterMessageCallback(
    271       "SetPageParameters",
    272       NewCallback(this, &CloudPrintFlowHandler::HandleSetPageParameters));
    273 
    274   if (web_ui_->tab_contents()) {
    275     // Also, take the opportunity to set some (minimal) additional
    276     // script permissions required for the web UI.
    277 
    278     // TODO(scottbyer): learn how to make sure we're talking to the
    279     // right web site first.
    280     RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
    281     if (rvh && rvh->delegate()) {
    282       WebPreferences webkit_prefs = rvh->delegate()->GetWebkitPrefs();
    283       webkit_prefs.allow_scripts_to_close_windows = true;
    284       rvh->UpdateWebPreferences(webkit_prefs);
    285     }
    286 
    287     // Register for appropriate notifications, and re-direct the URL
    288     // to the real server URL, now that we've gotten an HTML dialog
    289     // going.
    290     NavigationController* controller = &web_ui_->tab_contents()->controller();
    291     NavigationEntry* pending_entry = controller->pending_entry();
    292     if (pending_entry)
    293       pending_entry->set_url(CloudPrintURL(
    294           web_ui_->GetProfile()).GetCloudPrintServiceDialogURL());
    295     registrar_.Add(this, NotificationType::LOAD_STOP,
    296                    Source<NavigationController>(controller));
    297   }
    298 }
    299 
    300 void CloudPrintFlowHandler::Observe(NotificationType type,
    301                                     const NotificationSource& source,
    302                                     const NotificationDetails& details) {
    303   if (type == NotificationType::LOAD_STOP) {
    304     // Choose one or the other.  If you need to debug, bring up the
    305     // debugger.  You can then use the various chrome.send()
    306     // registrations above to kick of the various function calls,
    307     // including chrome.send("SendPrintData") in the javaScript
    308     // console and watch things happen with:
    309     // HandleShowDebugger(NULL);
    310     HandleSendPrintData(NULL);
    311   }
    312 }
    313 
    314 void CloudPrintFlowHandler::HandleShowDebugger(const ListValue* args) {
    315   ShowDebugger();
    316 }
    317 
    318 void CloudPrintFlowHandler::ShowDebugger() {
    319   if (web_ui_) {
    320     RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
    321     if (rvh)
    322       DevToolsManager::GetInstance()->OpenDevToolsWindow(rvh);
    323   }
    324 }
    325 
    326 scoped_refptr<CloudPrintDataSender>
    327 CloudPrintFlowHandler::CreateCloudPrintDataSender() {
    328   DCHECK(web_ui_);
    329   print_data_helper_.reset(new CloudPrintDataSenderHelper(web_ui_));
    330   return new CloudPrintDataSender(print_data_helper_.get(),
    331                                   print_job_title_,
    332                                   file_type_);
    333 }
    334 
    335 void CloudPrintFlowHandler::HandleSendPrintData(const ListValue* args) {
    336   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    337   // This will cancel any ReadPrintDataFile() or SendPrintDataFile()
    338   // requests in flight (this is anticipation of when setting page
    339   // setup parameters becomes asynchronous and may be set while some
    340   // data is in flight).  Then we can clear out the print data.
    341   CancelAnyRunningTask();
    342   if (web_ui_) {
    343     print_data_sender_ = CreateCloudPrintDataSender();
    344     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    345                             NewRunnableMethod(
    346                                 print_data_sender_.get(),
    347                                 &CloudPrintDataSender::ReadPrintDataFile,
    348                                 path_to_file_));
    349   }
    350 }
    351 
    352 void CloudPrintFlowHandler::HandleSetPageParameters(const ListValue* args) {
    353   std::string json;
    354   args->GetString(0, &json);
    355   if (json.empty()) {
    356     NOTREACHED() << "Empty json string";
    357     return;
    358   }
    359 
    360   // These are backstop default values - 72 dpi to match the screen,
    361   // 8.5x11 inch paper with margins subtracted (1/4 inch top, left,
    362   // right and 0.56 bottom), and the min page shrink and max page
    363   // shrink values appear all over the place with no explanation.
    364 
    365   // TODO(scottbyer): Get a Linux/ChromeOS edge for PrintSettings
    366   // working so that we can get the default values from there.  Fix up
    367   // PrintWebViewHelper to do the same.
    368   const int kDPI = 72;
    369   const int kWidth = static_cast<int>((8.5-0.25-0.25)*kDPI);
    370   const int kHeight = static_cast<int>((11-0.25-0.56)*kDPI);
    371   const double kMinPageShrink = 1.25;
    372   const double kMaxPageShrink = 2.0;
    373 
    374   PrintMsg_Print_Params default_settings;
    375   default_settings.printable_size = gfx::Size(kWidth, kHeight);
    376   default_settings.dpi = kDPI;
    377   default_settings.min_shrink = kMinPageShrink;
    378   default_settings.max_shrink = kMaxPageShrink;
    379   default_settings.desired_dpi = kDPI;
    380   default_settings.document_cookie = 0;
    381   default_settings.selection_only = false;
    382 
    383   if (!GetPageSetupParameters(json, default_settings)) {
    384     NOTREACHED();
    385     return;
    386   }
    387 
    388   // TODO(scottbyer) - Here is where we would kick the originating
    389   // renderer thread with these new parameters in order to get it to
    390   // re-generate the PDF data and hand it back to us.  window.print() is
    391   // currently synchronous, so there's a lot of work to do to get to
    392   // that point.
    393 }
    394 
    395 void CloudPrintFlowHandler::StoreDialogClientSize() const {
    396   if (web_ui_ && web_ui_->tab_contents() && web_ui_->tab_contents()->view()) {
    397     gfx::Size size = web_ui_->tab_contents()->view()->GetContainerSize();
    398     web_ui_->GetProfile()->GetPrefs()->SetInteger(
    399         prefs::kCloudPrintDialogWidth, size.width());
    400     web_ui_->GetProfile()->GetPrefs()->SetInteger(
    401         prefs::kCloudPrintDialogHeight, size.height());
    402   }
    403 }
    404 
    405 CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
    406     const FilePath& path_to_file,
    407     int width, int height,
    408     const std::string& json_arguments,
    409     const string16& print_job_title,
    410     const std::string& file_type,
    411     bool modal)
    412     : flow_handler_(new CloudPrintFlowHandler(path_to_file,
    413                                               print_job_title,
    414                                               file_type)),
    415       modal_(modal),
    416       owns_flow_handler_(true) {
    417   Init(width, height, json_arguments);
    418 }
    419 
    420 // For unit testing.
    421 CloudPrintHtmlDialogDelegate::CloudPrintHtmlDialogDelegate(
    422     CloudPrintFlowHandler* flow_handler,
    423     int width, int height,
    424     const std::string& json_arguments,
    425     bool modal)
    426     : flow_handler_(flow_handler),
    427       modal_(modal),
    428       owns_flow_handler_(true) {
    429   Init(width, height, json_arguments);
    430 }
    431 
    432 void CloudPrintHtmlDialogDelegate::Init(int width, int height,
    433                                         const std::string& json_arguments) {
    434   // This information is needed to show the dialog HTML content.
    435   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    436   params_.url = GURL(chrome::kCloudPrintResourcesURL);
    437   params_.height = height;
    438   params_.width = width;
    439   params_.json_input = json_arguments;
    440 
    441   flow_handler_->SetDialogDelegate(this);
    442   // If we're not modal we can show the dialog with no browser.
    443   // We need this to keep Chrome alive while our dialog is up.
    444   if (!modal_)
    445     BrowserList::StartKeepAlive();
    446 }
    447 
    448 CloudPrintHtmlDialogDelegate::~CloudPrintHtmlDialogDelegate() {
    449   // If the flow_handler_ is about to outlive us because we don't own
    450   // it anymore, we need to have it remove it's reference to us.
    451   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    452   flow_handler_->SetDialogDelegate(NULL);
    453   if (owns_flow_handler_) {
    454     delete flow_handler_;
    455   }
    456 }
    457 
    458 bool CloudPrintHtmlDialogDelegate::IsDialogModal() const {
    459     return modal_;
    460 }
    461 
    462 std::wstring CloudPrintHtmlDialogDelegate::GetDialogTitle() const {
    463   return std::wstring();
    464 }
    465 
    466 GURL CloudPrintHtmlDialogDelegate::GetDialogContentURL() const {
    467   return params_.url;
    468 }
    469 
    470 void CloudPrintHtmlDialogDelegate::GetWebUIMessageHandlers(
    471     std::vector<WebUIMessageHandler*>* handlers) const {
    472   handlers->push_back(flow_handler_);
    473   // We don't own flow_handler_ anymore, but it sticks around until at
    474   // least right after OnDialogClosed() is called (and this object is
    475   // destroyed).
    476   owns_flow_handler_ = false;
    477 }
    478 
    479 void CloudPrintHtmlDialogDelegate::GetDialogSize(gfx::Size* size) const {
    480   size->set_width(params_.width);
    481   size->set_height(params_.height);
    482 }
    483 
    484 std::string CloudPrintHtmlDialogDelegate::GetDialogArgs() const {
    485   return params_.json_input;
    486 }
    487 
    488 void CloudPrintHtmlDialogDelegate::OnDialogClosed(
    489     const std::string& json_retval) {
    490   // Get the final dialog size and store it.
    491   flow_handler_->StoreDialogClientSize();
    492   // If we're modal we can show the dialog with no browser.
    493   // End the keep-alive so that Chrome can exit.
    494   if (!modal_)
    495     BrowserList::EndKeepAlive();
    496   delete this;
    497 }
    498 
    499 void CloudPrintHtmlDialogDelegate::OnCloseContents(TabContents* source,
    500                                                    bool* out_close_dialog) {
    501   if (out_close_dialog)
    502     *out_close_dialog = true;
    503 }
    504 
    505 bool CloudPrintHtmlDialogDelegate::ShouldShowDialogTitle() const {
    506   return false;
    507 }
    508 
    509 bool CloudPrintHtmlDialogDelegate::HandleContextMenu(
    510     const ContextMenuParams& params) {
    511   return true;
    512 }
    513 
    514 // Called from the UI thread, starts up the dialog.
    515 void CreateDialogImpl(const FilePath& path_to_file,
    516                       const string16& print_job_title,
    517                       const std::string& file_type,
    518                       bool modal) {
    519   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    520   Browser* browser = BrowserList::GetLastActive();
    521 
    522   const int kDefaultWidth = 497;
    523   const int kDefaultHeight = 332;
    524   string16 job_title = print_job_title;
    525   Profile* profile = NULL;
    526   if (modal) {
    527     DCHECK(browser);
    528     if (job_title.empty() && browser->GetSelectedTabContents())
    529       job_title = browser->GetSelectedTabContents()->GetTitle();
    530     profile = browser->GetProfile();
    531   } else {
    532     profile = ProfileManager::GetDefaultProfile();
    533   }
    534   DCHECK(profile);
    535   PrefService* pref_service = profile->GetPrefs();
    536   DCHECK(pref_service);
    537   if (!pref_service->FindPreference(prefs::kCloudPrintDialogWidth)) {
    538     pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogWidth,
    539                                       kDefaultWidth);
    540   }
    541   if (!pref_service->FindPreference(prefs::kCloudPrintDialogHeight)) {
    542     pref_service->RegisterIntegerPref(prefs::kCloudPrintDialogHeight,
    543                                       kDefaultHeight);
    544   }
    545 
    546   int width = pref_service->GetInteger(prefs::kCloudPrintDialogWidth);
    547   int height = pref_service->GetInteger(prefs::kCloudPrintDialogHeight);
    548 
    549   HtmlDialogUIDelegate* dialog_delegate =
    550       new internal_cloud_print_helpers::CloudPrintHtmlDialogDelegate(
    551           path_to_file, width, height, std::string(), job_title, file_type,
    552           modal);
    553   if (modal) {
    554     DCHECK(browser);
    555     browser->BrowserShowHtmlDialog(dialog_delegate, NULL);
    556   } else {
    557     browser::ShowHtmlDialog(NULL, profile, dialog_delegate);
    558   }
    559 }
    560 
    561 }  // namespace internal_cloud_print_helpers
    562 
    563 namespace print_dialog_cloud {
    564 
    565 // Called on the FILE or UI thread.  This is the main entry point into creating
    566 // the dialog.
    567 
    568 // TODO(scottbyer): The signature here will need to change as the
    569 // workflow through the printing code changes to allow for dynamically
    570 // changing page setup parameters while the dialog is active.
    571 void CreatePrintDialogForFile(const FilePath& path_to_file,
    572                               const string16& print_job_title,
    573                               const std::string& file_type,
    574                               bool modal) {
    575   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE) ||
    576          BrowserThread::CurrentlyOn(BrowserThread::UI));
    577 
    578   BrowserThread::PostTask(
    579       BrowserThread::UI, FROM_HERE,
    580       NewRunnableFunction(&internal_cloud_print_helpers::CreateDialogImpl,
    581                           path_to_file,
    582                           print_job_title,
    583                           file_type,
    584                           modal));
    585 }
    586 
    587 bool CreatePrintDialogFromCommandLine(const CommandLine& command_line) {
    588   if (!command_line.GetSwitchValuePath(switches::kCloudPrintFile).empty()) {
    589     FilePath cloud_print_file;
    590     cloud_print_file =
    591         command_line.GetSwitchValuePath(switches::kCloudPrintFile);
    592     if (!cloud_print_file.empty()) {
    593       string16 print_job_title;
    594       if (command_line.HasSwitch(switches::kCloudPrintJobTitle)) {
    595 #ifdef OS_WIN
    596         CommandLine::StringType native_job_title;
    597         native_job_title = command_line.GetSwitchValueNative(
    598             switches::kCloudPrintJobTitle);
    599         print_job_title = string16(native_job_title);
    600 #elif defined(OS_POSIX)
    601         // TODO(abodenha (at) chromium.org) Implement this for OS_POSIX
    602         // Command line string types are different
    603 #endif
    604       }
    605       std::string file_type = "application/pdf";
    606       if (command_line.HasSwitch(switches::kCloudPrintFileType)) {
    607         file_type = command_line.GetSwitchValueASCII(
    608             switches::kCloudPrintFileType);
    609       }
    610       print_dialog_cloud::CreatePrintDialogForFile(cloud_print_file,
    611                                                    print_job_title,
    612                                                    file_type,
    613                                                    false);
    614       return true;
    615     }
    616   }
    617   return false;
    618 }
    619 
    620 }  // end namespace
    621