Home | History | Annotate | Download | only in printing
      1 // Copyright (c) 2012 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 
      7 
      8 #include "base/base64.h"
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/command_line.h"
     12 #include "base/file_util.h"
     13 #include "base/json/json_reader.h"
     14 #include "base/prefs/pref_service.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "base/values.h"
     17 #include "chrome/browser/devtools/devtools_window.h"
     18 #include "chrome/browser/lifetime/application_lifetime.h"
     19 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
     20 #include "chrome/browser/printing/print_dialog_cloud_internal.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "chrome/browser/profiles/profile_manager.h"
     23 #include "chrome/browser/ui/browser_dialogs.h"
     24 #include "chrome/common/chrome_switches.h"
     25 #include "chrome/common/pref_names.h"
     26 #include "chrome/common/print_messages.h"
     27 #include "chrome/common/url_constants.h"
     28 #include "components/user_prefs/pref_registry_syncable.h"
     29 #include "content/public/browser/browser_thread.h"
     30 #include "content/public/browser/navigation_controller.h"
     31 #include "content/public/browser/navigation_entry.h"
     32 #include "content/public/browser/notification_registrar.h"
     33 #include "content/public/browser/notification_source.h"
     34 #include "content/public/browser/notification_types.h"
     35 #include "content/public/browser/render_view_host.h"
     36 #include "content/public/browser/web_contents.h"
     37 #include "content/public/browser/web_contents_view.h"
     38 #include "content/public/browser/web_ui.h"
     39 #include "grit/generated_resources.h"
     40 #include "ui/base/l10n/l10n_util.h"
     41 #include "webkit/common/webpreferences.h"
     42 
     43 #if defined(USE_AURA)
     44 #include "ui/aura/root_window.h"
     45 #include "ui/aura/window.h"
     46 #endif
     47 
     48 #if defined(OS_WIN)
     49 #include "ui/base/win/foreground_helper.h"
     50 #endif
     51 
     52 // This module implements the UI support in Chrome for cloud printing.
     53 // This means hosting a dialog containing HTML/JavaScript and using
     54 // the published cloud print user interface integration APIs to get
     55 // page setup settings from the dialog contents and provide the
     56 // generated print data to the dialog contents for uploading to the
     57 // cloud print service.
     58 
     59 // Currently, the flow between these classes is as follows:
     60 
     61 // PrintDialogCloud::CreatePrintDialogForFile is called from
     62 // resource_message_filter_gtk.cc once the renderer has informed the
     63 // renderer host that print data generation into the renderer host provided
     64 // temp file has been completed.  That call is on the FILE thread.
     65 // That, in turn, hops over to the UI thread to create an instance of
     66 // PrintDialogCloud.
     67 
     68 // The constructor for PrintDialogCloud creates a
     69 // CloudPrintWebDialogDelegate and asks the current active browser to
     70 // show an HTML dialog using that class as the delegate. That class
     71 // hands in the kChromeUICloudPrintResourcesURL as the URL to visit.  That is
     72 // recognized by the GetWebUIFactoryFunction as a signal to create an
     73 // ExternalWebDialogUI.
     74 
     75 // CloudPrintWebDialogDelegate also temporarily owns a
     76 // CloudPrintFlowHandler, a class which is responsible for the actual
     77 // interactions with the dialog contents, including handing in the
     78 // print data and getting any page setup parameters that the dialog
     79 // contents provides.  As part of bringing up the dialog,
     80 // WebDialogUI::RenderViewCreated is called (an override of
     81 // WebUI::RenderViewCreated).  That routine, in turn, calls the
     82 // delegate's GetWebUIMessageHandlers routine, at which point the
     83 // ownership of the CloudPrintFlowHandler is handed over.  A pointer
     84 // to the flow handler is kept to facilitate communication back and
     85 // forth between the two classes.
     86 
     87 // The WebUI continues dialog bring-up, calling
     88 // CloudPrintFlowHandler::RegisterMessages.  This is where the
     89 // additional object model capabilities are registered for the dialog
     90 // contents to use.  It is also at this time that capabilities for the
     91 // dialog contents are adjusted to allow the dialog contents to close
     92 // the window.  In addition, the pending URL is redirected to the
     93 // actual cloud print service URL.  The flow controller also registers
     94 // for notification of when the dialog contents finish loading, which
     95 // is currently used to send the data to the dialog contents.
     96 
     97 // In order to send the data to the dialog contents, the flow
     98 // handler uses a CloudPrintDataSender.  It creates one, letting it
     99 // know the name of the temporary file containing the data, and
    100 // posts the task of reading the file
    101 // (CloudPrintDataSender::ReadPrintDataFile) to the file thread.  That
    102 // routine reads in the file, and then hops over to the IO thread to
    103 // send that data to the dialog contents.
    104 
    105 // When the dialog contents are finished (by either being cancelled or
    106 // hitting the print button), the delegate is notified, and responds
    107 // that the dialog should be closed, at which point things are torn
    108 // down and released.
    109 
    110 using content::BrowserThread;
    111 using content::NavigationController;
    112 using content::NavigationEntry;
    113 using content::RenderViewHost;
    114 using content::WebContents;
    115 using content::WebUIMessageHandler;
    116 using ui::WebDialogDelegate;
    117 
    118 const int kDefaultWidth = 912;
    119 const int kDefaultHeight = 633;
    120 
    121 namespace internal_cloud_print_helpers {
    122 
    123 // From the JSON parsed value, get the entries for the page setup
    124 // parameters.
    125 bool GetPageSetupParameters(const std::string& json,
    126                             PrintMsg_Print_Params& parameters) {
    127   scoped_ptr<Value> parsed_value(base::JSONReader::Read(json));
    128   DLOG_IF(ERROR, (!parsed_value.get() ||
    129                   !parsed_value->IsType(Value::TYPE_DICTIONARY)))
    130       << "PageSetup call didn't have expected contents";
    131   if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY))
    132     return false;
    133 
    134   bool result = true;
    135   DictionaryValue* params = static_cast<DictionaryValue*>(parsed_value.get());
    136   result &= params->GetDouble("dpi", &parameters.dpi);
    137   result &= params->GetDouble("min_shrink", &parameters.min_shrink);
    138   result &= params->GetDouble("max_shrink", &parameters.max_shrink);
    139   result &= params->GetBoolean("selection_only", &parameters.selection_only);
    140   return result;
    141 }
    142 
    143 string16 GetSwitchValueString16(const CommandLine& command_line,
    144                                 const char* switchName) {
    145 #if defined(OS_WIN)
    146   CommandLine::StringType native_switch_val;
    147   native_switch_val = command_line.GetSwitchValueNative(switchName);
    148   return string16(native_switch_val);
    149 #elif defined(OS_POSIX)
    150   // POSIX Command line string types are different.
    151   CommandLine::StringType native_switch_val;
    152   native_switch_val = command_line.GetSwitchValueASCII(switchName);
    153   // Convert the ASCII string to UTF16 to prepare to pass.
    154   return string16(ASCIIToUTF16(native_switch_val));
    155 #endif
    156 }
    157 
    158 void CloudPrintDataSenderHelper::CallJavascriptFunction(
    159     const std::wstring& function_name) {
    160   web_ui_->CallJavascriptFunction(WideToASCII(function_name));
    161 }
    162 
    163 void CloudPrintDataSenderHelper::CallJavascriptFunction(
    164     const std::wstring& function_name, const Value& arg) {
    165   web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg);
    166 }
    167 
    168 void CloudPrintDataSenderHelper::CallJavascriptFunction(
    169     const std::wstring& function_name, const Value& arg1, const Value& arg2) {
    170   web_ui_->CallJavascriptFunction(WideToASCII(function_name), arg1, arg2);
    171 }
    172 
    173 void CloudPrintDataSenderHelper::CallJavascriptFunction(
    174     const std::wstring& function_name,
    175     const Value& arg1,
    176     const Value& arg2,
    177     const Value& arg3) {
    178   web_ui_->CallJavascriptFunction(
    179       WideToASCII(function_name), arg1, arg2, arg3);
    180 }
    181 
    182 // Clears out the pointer we're using to communicate.  Either routine is
    183 // potentially expensive enough that stopping whatever is in progress
    184 // is worth it.
    185 void CloudPrintDataSender::CancelPrintDataFile() {
    186   base::AutoLock lock(lock_);
    187   // We don't own helper, it was passed in to us, so no need to
    188   // delete, just let it go.
    189   helper_ = NULL;
    190 }
    191 
    192 CloudPrintDataSender::CloudPrintDataSender(CloudPrintDataSenderHelper* helper,
    193                                            const string16& print_job_title,
    194                                            const string16& print_ticket,
    195                                            const std::string& file_type,
    196                                            const base::RefCountedMemory* data)
    197     : helper_(helper),
    198       print_job_title_(print_job_title),
    199       print_ticket_(print_ticket),
    200       file_type_(file_type),
    201       data_(data) {
    202 }
    203 
    204 CloudPrintDataSender::~CloudPrintDataSender() {}
    205 
    206 // We have the data in hand that needs to be pushed into the dialog
    207 // contents; do so from the IO thread.
    208 
    209 // TODO(scottbyer): If the print data ends up being larger than the
    210 // upload limit (currently 10MB), what we need to do is upload that
    211 // large data to google docs and set the URL in the printing
    212 // JavaScript to that location, and make sure it gets deleted when not
    213 // needed. - 4/1/2010
    214 void CloudPrintDataSender::SendPrintData() {
    215   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    216   if (!data_.get() || !data_->size())
    217     return;
    218 
    219   std::string base64_data;
    220   base::Base64Encode(
    221       base::StringPiece(reinterpret_cast<const char*>(data_->front()),
    222                         data_->size()),
    223       &base64_data);
    224   std::string header("data:");
    225   header.append(file_type_);
    226   header.append(";base64,");
    227   base64_data.insert(0, header);
    228 
    229   base::AutoLock lock(lock_);
    230   if (helper_) {
    231     StringValue title(print_job_title_);
    232     StringValue ticket(print_ticket_);
    233     // TODO(abodenha): Change Javascript call to pass in print ticket
    234     // after server side support is added. Add test for it.
    235 
    236     // Send the print data to the dialog contents.  The JavaScript
    237     // function is a preliminary API for prototyping purposes and is
    238     // subject to change.
    239     const_cast<CloudPrintDataSenderHelper*>(helper_)->CallJavascriptFunction(
    240         L"printApp._printDataUrl", StringValue(base64_data), title);
    241   }
    242 }
    243 
    244 
    245 CloudPrintFlowHandler::CloudPrintFlowHandler(const base::RefCountedMemory* data,
    246                                              const string16& print_job_title,
    247                                              const string16& print_ticket,
    248                                              const std::string& file_type,
    249                                              bool close_after_signin,
    250                                              const base::Closure& callback)
    251     : dialog_delegate_(NULL),
    252       data_(data),
    253       print_job_title_(print_job_title),
    254       print_ticket_(print_ticket),
    255       file_type_(file_type),
    256       close_after_signin_(close_after_signin),
    257       callback_(callback) {
    258 }
    259 
    260 CloudPrintFlowHandler::~CloudPrintFlowHandler() {
    261   // This will also cancel any task in flight.
    262   CancelAnyRunningTask();
    263 }
    264 
    265 
    266 void CloudPrintFlowHandler::SetDialogDelegate(
    267     CloudPrintWebDialogDelegate* delegate) {
    268   // Even if setting a new WebUI, it means any previous task needs
    269   // to be canceled, its now invalid.
    270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    271   CancelAnyRunningTask();
    272   dialog_delegate_ = delegate;
    273 }
    274 
    275 // Cancels any print data sender we have in flight and removes our
    276 // reference to it, so when the task that is calling it finishes and
    277 // removes its reference, it goes away.
    278 void CloudPrintFlowHandler::CancelAnyRunningTask() {
    279   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    280   if (print_data_sender_.get()) {
    281     print_data_sender_->CancelPrintDataFile();
    282     print_data_sender_ = NULL;
    283   }
    284 }
    285 
    286 void CloudPrintFlowHandler::RegisterMessages() {
    287   // TODO(scottbyer) - This is where we will register messages for the
    288   // UI JS to use.  Needed: Call to update page setup parameters.
    289   web_ui()->RegisterMessageCallback("ShowDebugger",
    290       base::Bind(&CloudPrintFlowHandler::HandleShowDebugger,
    291                  base::Unretained(this)));
    292   web_ui()->RegisterMessageCallback("SendPrintData",
    293       base::Bind(&CloudPrintFlowHandler::HandleSendPrintData,
    294                  base::Unretained(this)));
    295   web_ui()->RegisterMessageCallback("SetPageParameters",
    296       base::Bind(&CloudPrintFlowHandler::HandleSetPageParameters,
    297                  base::Unretained(this)));
    298 
    299   // Register for appropriate notifications, and re-direct the URL
    300   // to the real server URL, now that we've gotten an HTML dialog
    301   // going.
    302   NavigationController* controller =
    303       &web_ui()->GetWebContents()->GetController();
    304   NavigationEntry* pending_entry = controller->GetPendingEntry();
    305   if (pending_entry) {
    306     Profile* profile = Profile::FromWebUI(web_ui());
    307     if (close_after_signin_) {
    308       pending_entry->SetURL(
    309           CloudPrintURL(profile).GetCloudPrintSigninURL());
    310     } else {
    311       pending_entry->SetURL(
    312           CloudPrintURL(profile).GetCloudPrintServiceDialogURL());
    313     }
    314   }
    315   registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
    316                  content::Source<NavigationController>(controller));
    317   registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
    318                  content::Source<NavigationController>(controller));
    319 }
    320 
    321 void CloudPrintFlowHandler::Observe(
    322     int type,
    323     const content::NotificationSource& source,
    324     const content::NotificationDetails& details) {
    325   switch (type) {
    326     case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
    327       NavigationEntry* entry =
    328           web_ui()->GetWebContents()->GetController().GetActiveEntry();
    329       if (entry)
    330         NavigationToURLDidCloseDialog(entry->GetURL());
    331       break;
    332     }
    333     case content::NOTIFICATION_LOAD_STOP: {
    334       GURL url = web_ui()->GetWebContents()->GetURL();
    335       if (IsCloudPrintDialogUrl(url)) {
    336         // Take the opportunity to set some (minimal) additional
    337         // script permissions required for the web UI.
    338         RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
    339         if (rvh) {
    340           WebPreferences webkit_prefs = rvh->GetWebkitPreferences();
    341           webkit_prefs.allow_scripts_to_close_windows = true;
    342           rvh->UpdateWebkitPreferences(webkit_prefs);
    343         } else {
    344           NOTREACHED();
    345         }
    346         // Choose one or the other.  If you need to debug, bring up the
    347         // debugger.  You can then use the various chrome.send()
    348         // registrations above to kick of the various function calls,
    349         // including chrome.send("SendPrintData") in the javaScript
    350         // console and watch things happen with:
    351         // HandleShowDebugger(NULL);
    352         HandleSendPrintData(NULL);
    353       }
    354       break;
    355     }
    356   }
    357 }
    358 
    359 void CloudPrintFlowHandler::HandleShowDebugger(const ListValue* args) {
    360   ShowDebugger();
    361 }
    362 
    363 void CloudPrintFlowHandler::ShowDebugger() {
    364   if (web_ui()) {
    365     RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
    366     if (rvh)
    367       DevToolsWindow::OpenDevToolsWindow(rvh);
    368   }
    369 }
    370 
    371 scoped_refptr<CloudPrintDataSender>
    372 CloudPrintFlowHandler::CreateCloudPrintDataSender() {
    373   DCHECK(web_ui());
    374   print_data_helper_.reset(new CloudPrintDataSenderHelper(web_ui()));
    375   scoped_refptr<CloudPrintDataSender> sender(
    376       new CloudPrintDataSender(print_data_helper_.get(),
    377                                print_job_title_,
    378                                print_ticket_,
    379                                file_type_,
    380                                data_.get()));
    381   return sender;
    382 }
    383 
    384 void CloudPrintFlowHandler::HandleSendPrintData(const ListValue* args) {
    385   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    386   // This will cancel any ReadPrintDataFile() or SendPrintDataFile()
    387   // requests in flight (this is anticipation of when setting page
    388   // setup parameters becomes asynchronous and may be set while some
    389   // data is in flight).  Then we can clear out the print data.
    390   CancelAnyRunningTask();
    391   if (web_ui()) {
    392     print_data_sender_ = CreateCloudPrintDataSender();
    393     BrowserThread::PostTask(
    394         BrowserThread::IO, FROM_HERE,
    395         base::Bind(&CloudPrintDataSender::SendPrintData, print_data_sender_));
    396   }
    397 }
    398 
    399 void CloudPrintFlowHandler::HandleSetPageParameters(const ListValue* args) {
    400   std::string json;
    401   bool ret = args->GetString(0, &json);
    402   if (!ret || json.empty()) {
    403     NOTREACHED() << "Empty json string";
    404     return;
    405   }
    406 
    407   // These are backstop default values - 72 dpi to match the screen,
    408   // 8.5x11 inch paper with margins subtracted (1/4 inch top, left,
    409   // right and 0.56 bottom), and the min page shrink and max page
    410   // shrink values appear all over the place with no explanation.
    411 
    412   // TODO(scottbyer): Get a Linux/ChromeOS edge for PrintSettings
    413   // working so that we can get the default values from there.  Fix up
    414   // PrintWebViewHelper to do the same.
    415   const int kDPI = 72;
    416   const int kWidth = static_cast<int>((8.5-0.25-0.25)*kDPI);
    417   const int kHeight = static_cast<int>((11-0.25-0.56)*kDPI);
    418   const double kMinPageShrink = 1.25;
    419   const double kMaxPageShrink = 2.0;
    420 
    421   PrintMsg_Print_Params default_settings;
    422   default_settings.content_size = gfx::Size(kWidth, kHeight);
    423   default_settings.printable_area = gfx::Rect(0, 0, kWidth, kHeight);
    424   default_settings.dpi = kDPI;
    425   default_settings.min_shrink = kMinPageShrink;
    426   default_settings.max_shrink = kMaxPageShrink;
    427   default_settings.desired_dpi = kDPI;
    428   default_settings.document_cookie = 0;
    429   default_settings.selection_only = false;
    430   default_settings.preview_request_id = 0;
    431   default_settings.is_first_request = true;
    432   default_settings.print_to_pdf = false;
    433 
    434   if (!GetPageSetupParameters(json, default_settings)) {
    435     NOTREACHED();
    436     return;
    437   }
    438 
    439   // TODO(scottbyer) - Here is where we would kick the originating
    440   // renderer thread with these new parameters in order to get it to
    441   // re-generate the PDF data and hand it back to us.  window.print() is
    442   // currently synchronous, so there's a lot of work to do to get to
    443   // that point.
    444 }
    445 
    446 void CloudPrintFlowHandler::StoreDialogClientSize() const {
    447   if (web_ui() && web_ui()->GetWebContents() &&
    448       web_ui()->GetWebContents()->GetView()) {
    449     gfx::Size size = web_ui()->GetWebContents()->GetView()->GetContainerSize();
    450     Profile* profile = Profile::FromWebUI(web_ui());
    451     profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogWidth,
    452                                     size.width());
    453     profile->GetPrefs()->SetInteger(prefs::kCloudPrintDialogHeight,
    454                                     size.height());
    455   }
    456 }
    457 
    458 bool CloudPrintFlowHandler::NavigationToURLDidCloseDialog(const GURL& url) {
    459   if (close_after_signin_) {
    460     if (IsCloudPrintDialogUrl(url)) {
    461       StoreDialogClientSize();
    462       web_ui()->GetWebContents()->GetRenderViewHost()->ClosePage();
    463       callback_.Run();
    464       return true;
    465     }
    466   }
    467   return false;
    468 }
    469 
    470 bool CloudPrintFlowHandler::IsCloudPrintDialogUrl(const GURL& url) {
    471   GURL cloud_print_url =
    472       CloudPrintURL(Profile::FromWebUI(web_ui())).GetCloudPrintServiceURL();
    473   return url.host() == cloud_print_url.host() &&
    474          StartsWithASCII(url.path(), cloud_print_url.path(), false) &&
    475          url.scheme() == cloud_print_url.scheme();
    476 }
    477 
    478 CloudPrintWebDialogDelegate::CloudPrintWebDialogDelegate(
    479     content::BrowserContext* browser_context,
    480     gfx::NativeWindow modal_parent,
    481     const base::RefCountedMemory* data,
    482     const std::string& json_arguments,
    483     const string16& print_job_title,
    484     const string16& print_ticket,
    485     const std::string& file_type,
    486     bool close_after_signin,
    487     const base::Closure& callback)
    488     : flow_handler_(
    489           new CloudPrintFlowHandler(data, print_job_title, print_ticket,
    490                                     file_type, close_after_signin, callback)),
    491       modal_parent_(modal_parent),
    492       owns_flow_handler_(true),
    493       keep_alive_when_non_modal_(true) {
    494   Init(browser_context, json_arguments);
    495 }
    496 
    497 // For unit testing.
    498 CloudPrintWebDialogDelegate::CloudPrintWebDialogDelegate(
    499     CloudPrintFlowHandler* flow_handler,
    500     const std::string& json_arguments)
    501     : flow_handler_(flow_handler),
    502       modal_parent_(NULL),
    503       owns_flow_handler_(true),
    504       keep_alive_when_non_modal_(false) {
    505   Init(NULL, json_arguments);
    506 }
    507 
    508 // Returns the persisted width/height for the print dialog.
    509 void GetDialogWidthAndHeightFromPrefs(content::BrowserContext* browser_context,
    510                                       int* width,
    511                                       int* height) {
    512   if (!browser_context) {
    513     *width = kDefaultWidth;
    514     *height = kDefaultHeight;
    515     return;
    516   }
    517 
    518   PrefService* prefs = Profile::FromBrowserContext(browser_context)->GetPrefs();
    519   *width = prefs->GetInteger(prefs::kCloudPrintDialogWidth);
    520   *height = prefs->GetInteger(prefs::kCloudPrintDialogHeight);
    521 }
    522 
    523 void CloudPrintWebDialogDelegate::Init(content::BrowserContext* browser_context,
    524                                        const std::string& json_arguments) {
    525   // This information is needed to show the dialog HTML content.
    526   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    527 
    528   params_.url = GURL(chrome::kChromeUICloudPrintResourcesURL);
    529   GetDialogWidthAndHeightFromPrefs(browser_context,
    530                                    &params_.width,
    531                                    &params_.height);
    532   params_.json_input = json_arguments;
    533 
    534   flow_handler_->SetDialogDelegate(this);
    535   // If we're not modal we can show the dialog with no browser.
    536   // We need this to keep Chrome alive while our dialog is up.
    537   if (!modal_parent_ && keep_alive_when_non_modal_)
    538     chrome::StartKeepAlive();
    539 }
    540 
    541 CloudPrintWebDialogDelegate::~CloudPrintWebDialogDelegate() {
    542   // If the flow_handler_ is about to outlive us because we don't own
    543   // it anymore, we need to have it remove its reference to us.
    544   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    545   flow_handler_->SetDialogDelegate(NULL);
    546   if (owns_flow_handler_) {
    547     delete flow_handler_;
    548   }
    549 }
    550 
    551 ui::ModalType CloudPrintWebDialogDelegate::GetDialogModalType() const {
    552     return modal_parent_ ? ui::MODAL_TYPE_WINDOW : ui::MODAL_TYPE_NONE;
    553 }
    554 
    555 string16 CloudPrintWebDialogDelegate::GetDialogTitle() const {
    556   return string16();
    557 }
    558 
    559 GURL CloudPrintWebDialogDelegate::GetDialogContentURL() const {
    560   return params_.url;
    561 }
    562 
    563 void CloudPrintWebDialogDelegate::GetWebUIMessageHandlers(
    564     std::vector<WebUIMessageHandler*>* handlers) const {
    565   handlers->push_back(flow_handler_);
    566   // We don't own flow_handler_ anymore, but it sticks around until at
    567   // least right after OnDialogClosed() is called (and this object is
    568   // destroyed).
    569   owns_flow_handler_ = false;
    570 }
    571 
    572 void CloudPrintWebDialogDelegate::GetDialogSize(gfx::Size* size) const {
    573   size->set_width(params_.width);
    574   size->set_height(params_.height);
    575 }
    576 
    577 std::string CloudPrintWebDialogDelegate::GetDialogArgs() const {
    578   return params_.json_input;
    579 }
    580 
    581 void CloudPrintWebDialogDelegate::OnDialogClosed(
    582     const std::string& json_retval) {
    583   // Get the final dialog size and store it.
    584   flow_handler_->StoreDialogClientSize();
    585 
    586   // If we're modal we can show the dialog with no browser.
    587   // End the keep-alive so that Chrome can exit.
    588   if (!modal_parent_ && keep_alive_when_non_modal_)
    589     chrome::EndKeepAlive();
    590   delete this;
    591 }
    592 
    593 void CloudPrintWebDialogDelegate::OnCloseContents(WebContents* source,
    594                                                   bool* out_close_dialog) {
    595   if (out_close_dialog)
    596     *out_close_dialog = true;
    597 }
    598 
    599 bool CloudPrintWebDialogDelegate::ShouldShowDialogTitle() const {
    600   return false;
    601 }
    602 
    603 bool CloudPrintWebDialogDelegate::HandleContextMenu(
    604     const content::ContextMenuParams& params) {
    605   return true;
    606 }
    607 
    608 bool CloudPrintWebDialogDelegate::HandleOpenURLFromTab(
    609     content::WebContents* source,
    610     const content::OpenURLParams& params,
    611     content::WebContents** out_new_contents) {
    612   return flow_handler_->NavigationToURLDidCloseDialog(params.url);
    613 }
    614 
    615 // Called from the UI thread, starts up the dialog.
    616 void CreateDialogImpl(content::BrowserContext* browser_context,
    617                       gfx::NativeWindow modal_parent,
    618                       const base::RefCountedMemory* data,
    619                       const string16& print_job_title,
    620                       const string16& print_ticket,
    621                       const std::string& file_type,
    622                       bool close_after_signin,
    623                       const base::Closure& callback) {
    624   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    625   WebDialogDelegate* dialog_delegate =
    626       new internal_cloud_print_helpers::CloudPrintWebDialogDelegate(
    627           browser_context, modal_parent, data, std::string(), print_job_title,
    628           print_ticket, file_type, close_after_signin, callback);
    629 #if defined(OS_WIN)
    630   gfx::NativeWindow window =
    631 #endif
    632       chrome::ShowWebDialog(modal_parent,
    633                             Profile::FromBrowserContext(browser_context),
    634                             dialog_delegate);
    635 #if defined(OS_WIN)
    636   if (window) {
    637     HWND dialog_handle;
    638 #if defined(USE_AURA)
    639     dialog_handle = window->GetRootWindow()->GetAcceleratedWidget();
    640 #else
    641     dialog_handle = window;
    642 #endif
    643     if (::GetForegroundWindow() != dialog_handle) {
    644       ui::ForegroundHelper::SetForeground(dialog_handle);
    645     }
    646   }
    647 #endif
    648 }
    649 
    650 void CreateDialogSigninImpl(content::BrowserContext* browser_context,
    651                             gfx::NativeWindow modal_parent,
    652                             const base::Closure& callback) {
    653   CreateDialogImpl(browser_context, modal_parent, NULL, string16(),
    654                    string16(), std::string(), true, callback);
    655 }
    656 
    657 void CreateDialogForFileImpl(content::BrowserContext* browser_context,
    658                              gfx::NativeWindow modal_parent,
    659                              const base::FilePath& path_to_file,
    660                              const string16& print_job_title,
    661                              const string16& print_ticket,
    662                              const std::string& file_type,
    663                              bool delete_on_close) {
    664   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    665   scoped_refptr<base::RefCountedMemory> data;
    666   int64 file_size = 0;
    667   if (file_util::GetFileSize(path_to_file, &file_size) && file_size != 0) {
    668     std::string file_data;
    669     if (file_size < kuint32max) {
    670       file_data.reserve(static_cast<unsigned int>(file_size));
    671     } else {
    672       DLOG(WARNING) << " print data file too large to reserve space";
    673     }
    674     if (file_util::ReadFileToString(path_to_file, &file_data)) {
    675       data = base::RefCountedString::TakeString(&file_data);
    676     }
    677   }
    678   // Proceed even for empty data to simplify testing.
    679   BrowserThread::PostTask(
    680       BrowserThread::UI, FROM_HERE,
    681       base::Bind(&print_dialog_cloud::CreatePrintDialogForBytes,
    682                  browser_context, modal_parent, data, print_job_title,
    683                  print_ticket, file_type));
    684   if (delete_on_close)
    685     base::DeleteFile(path_to_file, false);
    686 }
    687 
    688 }  // namespace internal_cloud_print_helpers
    689 
    690 namespace print_dialog_cloud {
    691 
    692 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
    693   registry->RegisterIntegerPref(
    694       prefs::kCloudPrintDialogWidth,
    695       kDefaultWidth,
    696       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    697   registry->RegisterIntegerPref(
    698       prefs::kCloudPrintDialogHeight,
    699       kDefaultHeight,
    700       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    701 }
    702 
    703 // Called on the FILE or UI thread.  This is the main entry point into creating
    704 // the dialog.
    705 
    706 void CreatePrintDialogForFile(content::BrowserContext* browser_context,
    707                               gfx::NativeWindow modal_parent,
    708                               const base::FilePath& path_to_file,
    709                               const string16& print_job_title,
    710                               const string16& print_ticket,
    711                               const std::string& file_type,
    712                               bool delete_on_close) {
    713   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE) ||
    714          BrowserThread::CurrentlyOn(BrowserThread::UI));
    715   BrowserThread::PostTask(
    716       BrowserThread::FILE, FROM_HERE,
    717       base::Bind(&internal_cloud_print_helpers::CreateDialogForFileImpl,
    718                  browser_context, modal_parent, path_to_file, print_job_title,
    719                  print_ticket, file_type, delete_on_close));
    720 }
    721 
    722 void CreateCloudPrintSigninDialog(content::BrowserContext* browser_context,
    723                                   gfx::NativeWindow modal_parent,
    724                                   const base::Closure& callback) {
    725   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    726 
    727   BrowserThread::PostTask(
    728       BrowserThread::UI, FROM_HERE,
    729       base::Bind(&internal_cloud_print_helpers::CreateDialogSigninImpl,
    730                  browser_context, modal_parent, callback));
    731 }
    732 
    733 void CreatePrintDialogForBytes(content::BrowserContext* browser_context,
    734                                gfx::NativeWindow modal_parent,
    735                                const base::RefCountedMemory* data,
    736                                const string16& print_job_title,
    737                                const string16& print_ticket,
    738                                const std::string& file_type) {
    739   internal_cloud_print_helpers::CreateDialogImpl(browser_context, modal_parent,
    740                                                  data, print_job_title,
    741                                                  print_ticket, file_type, false,
    742                                                  base::Closure());
    743 }
    744 
    745 bool CreatePrintDialogFromCommandLine(const CommandLine& command_line) {
    746   DCHECK(command_line.HasSwitch(switches::kCloudPrintFile));
    747   if (!command_line.GetSwitchValuePath(switches::kCloudPrintFile).empty()) {
    748     base::FilePath cloud_print_file;
    749     cloud_print_file =
    750         command_line.GetSwitchValuePath(switches::kCloudPrintFile);
    751     if (!cloud_print_file.empty()) {
    752       string16 print_job_title;
    753       string16 print_job_print_ticket;
    754       if (command_line.HasSwitch(switches::kCloudPrintJobTitle)) {
    755         print_job_title =
    756           internal_cloud_print_helpers::GetSwitchValueString16(
    757               command_line, switches::kCloudPrintJobTitle);
    758       }
    759       if (command_line.HasSwitch(switches::kCloudPrintPrintTicket)) {
    760         print_job_print_ticket =
    761           internal_cloud_print_helpers::GetSwitchValueString16(
    762               command_line, switches::kCloudPrintPrintTicket);
    763       }
    764       std::string file_type = "application/pdf";
    765       if (command_line.HasSwitch(switches::kCloudPrintFileType)) {
    766         file_type = command_line.GetSwitchValueASCII(
    767             switches::kCloudPrintFileType);
    768       }
    769 
    770       bool delete_on_close = CommandLine::ForCurrentProcess()->HasSwitch(
    771           switches::kCloudPrintDeleteFile);
    772 
    773       print_dialog_cloud::CreatePrintDialogForFile(
    774           ProfileManager::GetDefaultProfile(),
    775           NULL,
    776           cloud_print_file,
    777           print_job_title,
    778           print_job_print_ticket,
    779           file_type,
    780           delete_on_close);
    781       return true;
    782     }
    783   }
    784   return false;
    785 }
    786 
    787 }  // end namespace
    788